]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Fix a couple of memleaks in the filter model tests
[~andy/gtk] / gtk / tests / filtermodel.c
1 /* Extensive GtkTreeModelFilter tests.
2  * Copyright (C) 2009  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
23 /* Left to do:
24  *   - Proper coverage checking to see if the unit tests cover
25  *     all possible cases.
26  *   - Verify if the ref counting is done properly for both the
27  *     normal ref_count and the zero_ref_count.  One way to test
28  *     this area is by collapsing/expanding branches on the view
29  *     that is connected to the filter model.
30  *   - Check if the iterator stamp is incremented at the correct times.
31  */
32
33
34 /*
35  * Model creation
36  */
37
38 #define LEVEL_LENGTH 5
39
40 static void
41 create_tree_store_set_values (GtkTreeStore *store,
42                               GtkTreeIter  *iter,
43                               gboolean      visible)
44 {
45   GtkTreePath *path;
46   gchar *path_string;
47
48   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
49   path_string = gtk_tree_path_to_string (path);
50
51   gtk_tree_store_set (store, iter,
52                       0, path_string,
53                       1, visible,
54                       -1);
55
56   gtk_tree_path_free (path);
57   g_free (path_string);
58 }
59
60 static void
61 create_tree_store_recurse (int           depth,
62                            GtkTreeStore *store,
63                            GtkTreeIter  *parent,
64                            gboolean      visible)
65 {
66   int i;
67
68   for (i = 0; i < LEVEL_LENGTH; i++)
69     {
70       GtkTreeIter iter;
71
72       gtk_tree_store_insert (store, &iter, parent, i);
73       create_tree_store_set_values (store, &iter, visible);
74
75       if (depth > 0)
76         create_tree_store_recurse (depth - 1, store, &iter, visible);
77     }
78 }
79
80 static GtkTreeStore *
81 create_tree_store (int      depth,
82                    gboolean visible)
83 {
84   GtkTreeStore *store;
85
86   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
87
88   create_tree_store_recurse (depth, store, NULL, visible);
89
90   return store;
91 }
92
93 /*
94  * Signal monitor
95  */
96
97 typedef enum
98 {
99   ROW_INSERTED,
100   ROW_DELETED,
101   ROW_CHANGED,
102   ROW_HAS_CHILD_TOGGLED,
103   ROWS_REORDERED,
104   LAST_SIGNAL
105 }
106 SignalName;
107
108 static const char *
109 signal_name_to_string (SignalName signal)
110 {
111   switch (signal)
112     {
113       case ROW_INSERTED:
114           return "row-inserted";
115
116       case ROW_DELETED:
117           return "row-deleted";
118
119       case ROW_CHANGED:
120           return "row-changed";
121
122       case ROW_HAS_CHILD_TOGGLED:
123           return "row-has-child-toggled";
124
125       case ROWS_REORDERED:
126           return "rows-reordered";
127
128       default:
129           /* Fall through */
130           break;
131     }
132
133   return "(unknown)";
134 }
135
136 typedef struct
137 {
138   SignalName signal;
139   GtkTreePath *path;
140 }
141 Signal;
142
143
144 static Signal *
145 signal_new (SignalName signal, GtkTreePath *path)
146 {
147   Signal *s;
148
149   s = g_new0 (Signal, 1);
150   s->signal = signal;
151   s->path = gtk_tree_path_copy (path);
152
153   return s;
154 }
155
156 static void
157 signal_free (Signal *s)
158 {
159   if (s->path)
160     gtk_tree_path_free (s->path);
161
162   g_free (s);
163 }
164
165
166 typedef struct
167 {
168   GQueue *queue;
169   GtkTreeModel *client;
170   gulong signal_ids[LAST_SIGNAL];
171 }
172 SignalMonitor;
173
174
175 static void
176 signal_monitor_generic_handler (SignalMonitor *m,
177                                 SignalName     signal,
178                                 GtkTreeModel  *model,
179                                 GtkTreePath   *path)
180 {
181   Signal *s;
182
183   if (g_queue_is_empty (m->queue))
184     {
185       gchar *path_str;
186
187       path_str = gtk_tree_path_to_string (path);
188       g_error ("Signal queue empty, got signal %s path %s\n",
189                signal_name_to_string (signal), path_str);
190       g_free (path_str);
191
192       g_assert_not_reached ();
193     }
194
195   if (m->client != model)
196     {
197       g_error ("Model mismatch; expected %p, got %p\n",
198                m->client, model);
199       g_assert_not_reached ();
200     }
201
202   s = g_queue_peek_tail (m->queue);
203
204 #if 0
205   /* For debugging: output signals that are coming in.  Leaks memory. */
206   g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
207            gtk_tree_path_to_string (path));
208 #endif
209
210   if (s->signal != signal
211       || gtk_tree_path_compare (s->path, path) != 0)
212     {
213       gchar *path_str, *s_path_str;
214
215       s_path_str = gtk_tree_path_to_string (s->path);
216       path_str = gtk_tree_path_to_string (path);
217
218       g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
219                signal_name_to_string (s->signal), s_path_str,
220                signal_name_to_string (signal), path_str);
221
222       g_free (s_path_str);
223       g_free (path_str);
224
225       g_assert_not_reached ();
226     }
227
228   s = g_queue_pop_tail (m->queue);
229
230   signal_free (s);
231 }
232
233 static void
234 signal_monitor_row_inserted (GtkTreeModel *model,
235                              GtkTreePath  *path,
236                              GtkTreeIter  *iter,
237                              gpointer      data)
238 {
239   signal_monitor_generic_handler (data, ROW_INSERTED,
240                                   model, path);
241 }
242
243 static void
244 signal_monitor_row_deleted (GtkTreeModel *model,
245                             GtkTreePath  *path,
246                             gpointer      data)
247 {
248   signal_monitor_generic_handler (data, ROW_DELETED,
249                                   model, path);
250 }
251
252 static void
253 signal_monitor_row_changed (GtkTreeModel *model,
254                             GtkTreePath  *path,
255                             GtkTreeIter  *iter,
256                             gpointer      data)
257 {
258   signal_monitor_generic_handler (data, ROW_CHANGED,
259                                   model, path);
260 }
261
262 static void
263 signal_monitor_row_has_child_toggled (GtkTreeModel *model,
264                                       GtkTreePath  *path,
265                                       GtkTreeIter  *iter,
266                                       gpointer      data)
267 {
268   signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
269                                   model, path);
270 }
271
272 static void
273 signal_monitor_rows_reordered (GtkTreeModel *model,
274                                GtkTreePath  *path,
275                                GtkTreeIter  *iter,
276                                gint         *new_order,
277                                gpointer      data)
278 {
279   signal_monitor_generic_handler (data, ROWS_REORDERED,
280                                   model, path);
281 }
282
283 static SignalMonitor *
284 signal_monitor_new (GtkTreeModel *client)
285 {
286   SignalMonitor *m;
287
288   m = g_new0 (SignalMonitor, 1);
289   m->client = g_object_ref (client);
290   m->queue = g_queue_new ();
291
292   m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
293                                                   "row-inserted",
294                                                   G_CALLBACK (signal_monitor_row_inserted),
295                                                   m);
296   m->signal_ids[ROW_DELETED] = g_signal_connect (client,
297                                                  "row-deleted",
298                                                  G_CALLBACK (signal_monitor_row_deleted),
299                                                  m);
300   m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
301                                                  "row-changed",
302                                                  G_CALLBACK (signal_monitor_row_changed),
303                                                  m);
304   m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
305                                                            "row-has-child-toggled",
306                                                            G_CALLBACK (signal_monitor_row_has_child_toggled),
307                                                            m);
308   m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
309                                                     "rows-reordered",
310                                                     G_CALLBACK (signal_monitor_rows_reordered),
311                                                     m);
312
313   return m;
314 }
315
316 static void
317 signal_monitor_free (SignalMonitor *m)
318 {
319   int i;
320
321   for (i = 0; i < LAST_SIGNAL; i++)
322     g_signal_handler_disconnect (m->client, m->signal_ids[i]);
323
324   g_object_unref (m->client);
325
326   if (m->queue)
327     g_queue_free (m->queue);
328
329   g_free (m);
330 }
331
332 static void
333 signal_monitor_assert_is_empty (SignalMonitor *m)
334 {
335   g_assert (g_queue_is_empty (m->queue));
336 }
337
338 static void
339 signal_monitor_append_signal_path (SignalMonitor *m,
340                                    SignalName     signal,
341                                    GtkTreePath   *path)
342 {
343   Signal *s;
344
345   s = signal_new (signal, path);
346   g_queue_push_head (m->queue, s);
347 }
348
349 static void
350 signal_monitor_append_signal (SignalMonitor *m,
351                               SignalName     signal,
352                               const gchar   *path_string)
353 {
354   Signal *s;
355   GtkTreePath *path;
356
357   path = gtk_tree_path_new_from_string (path_string);
358
359   s = signal_new (signal, path);
360   g_queue_push_head (m->queue, s);
361
362   gtk_tree_path_free (path);
363 }
364
365 /*
366  * Fixture
367  */
368
369 typedef struct
370 {
371   GtkWidget *tree_view;
372
373   GtkTreeStore *store;
374   GtkTreeModelFilter *filter;
375
376   SignalMonitor *monitor;
377
378   guint block_signals : 1;
379 } FilterTest;
380
381
382 static void
383 filter_test_store_signal (FilterTest *fixture)
384 {
385   if (fixture->block_signals)
386     g_signal_stop_emission_by_name (fixture->store, "row-changed");
387 }
388
389
390 static void
391 filter_test_setup_generic (FilterTest    *fixture,
392                            gconstpointer  test_data,
393                            int            depth,
394                            gboolean       empty,
395                            gboolean       unfiltered)
396 {
397   const GtkTreePath *vroot = test_data;
398   GtkTreeModel *filter;
399
400   fixture->store = create_tree_store (depth, !empty);
401
402   g_signal_connect_swapped (fixture->store, "row-changed",
403                             G_CALLBACK (filter_test_store_signal), fixture);
404
405   /* Please forgive me for casting const away. */
406   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
407                                       (GtkTreePath *)vroot);
408   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
409
410   if (!unfiltered)
411     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
412
413   /* We need a tree view that's listening to get ref counting from that
414    * side.
415    */
416   fixture->tree_view = gtk_tree_view_new_with_model (filter);
417
418   fixture->monitor = signal_monitor_new (filter);
419 }
420
421 static void
422 filter_test_setup (FilterTest    *fixture,
423                    gconstpointer  test_data)
424 {
425   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
426 }
427
428 static void
429 filter_test_setup_empty (FilterTest    *fixture,
430                          gconstpointer  test_data)
431 {
432   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
433 }
434
435 static void
436 filter_test_setup_unfiltered (FilterTest    *fixture,
437                               gconstpointer  test_data)
438 {
439   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
440 }
441
442 static void
443 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
444                                     gconstpointer  test_data)
445 {
446   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
447 }
448
449 static GtkTreePath *
450 strip_virtual_root (GtkTreePath *path,
451                     GtkTreePath *root_path)
452 {
453   GtkTreePath *real_path;
454
455   if (root_path)
456     {
457       int j;
458       int depth = gtk_tree_path_get_depth (path);
459       int root_depth = gtk_tree_path_get_depth (root_path);
460
461       real_path = gtk_tree_path_new ();
462
463       for (j = 0; j < depth - root_depth; j++)
464         gtk_tree_path_append_index (real_path,
465                                     gtk_tree_path_get_indices (path)[root_depth + j]);
466     }
467   else
468     real_path = gtk_tree_path_copy (path);
469
470   return real_path;
471 }
472
473 static void
474 filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
475                                              GtkTreePath *store_path,
476                                              GtkTreePath *filter_path,
477                                              int          depth,
478                                              GtkTreePath *root_path)
479 {
480   int i;
481   int rows_deleted = 0;
482   GtkTreeIter iter;
483
484   gtk_tree_path_down (store_path);
485   gtk_tree_path_down (filter_path);
486
487   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
488                            &iter, store_path);
489
490   for (i = 0; i < LEVEL_LENGTH; i++)
491     {
492       gboolean visible;
493       GtkTreePath *real_path;
494
495       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
496                           1, &visible,
497                           -1);
498
499       if (root_path &&
500           (!gtk_tree_path_is_descendant (store_path, root_path)
501            || !gtk_tree_path_compare (store_path, root_path)))
502         {
503           if (!gtk_tree_path_compare (store_path, root_path))
504             {
505               if (depth > 1
506                   && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
507                                                     &iter))
508                 {
509                   GtkTreePath *store_copy;
510                   GtkTreePath *filter_copy;
511
512                   store_copy = gtk_tree_path_copy (store_path);
513                   filter_copy = gtk_tree_path_copy (filter_path);
514                   filter_test_append_refilter_signals_recurse (fixture,
515                                                                store_copy,
516                                                                filter_copy,
517                                                                depth - 1,
518                                                                root_path);
519                   gtk_tree_path_free (store_copy);
520                   gtk_tree_path_free (filter_copy);
521                 }
522             }
523
524           gtk_tree_path_next (store_path);
525           gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
526
527           if (visible)
528             gtk_tree_path_next (filter_path);
529
530           continue;
531         }
532
533       real_path = strip_virtual_root (filter_path, root_path);
534
535       if (visible)
536         {
537           /* This row will be inserted */
538           signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
539                                              real_path);
540           signal_monitor_append_signal_path (fixture->monitor,
541                                              ROW_HAS_CHILD_TOGGLED,
542                                              real_path);
543
544           if (depth > 1
545               && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
546                                                 &iter))
547             {
548               GtkTreePath *store_copy;
549               GtkTreePath *filter_copy;
550
551               store_copy = gtk_tree_path_copy (store_path);
552               filter_copy = gtk_tree_path_copy (filter_path);
553               filter_test_append_refilter_signals_recurse (fixture,
554                                                            store_copy,
555                                                            filter_copy,
556                                                            depth - 1,
557                                                            root_path);
558               gtk_tree_path_free (store_copy);
559               gtk_tree_path_free (filter_copy);
560             }
561
562           gtk_tree_path_next (filter_path);
563         }
564       else
565         {
566           /* This row will be deleted */
567           rows_deleted++;
568           signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
569                                              real_path);
570         }
571
572       gtk_tree_path_free (real_path);
573
574       gtk_tree_path_next (store_path);
575       gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
576     }
577
578   if (rows_deleted == LEVEL_LENGTH
579       && gtk_tree_path_get_depth (filter_path) > 1)
580     {
581       GtkTreePath *real_path;
582
583       gtk_tree_path_up (store_path);
584       gtk_tree_path_up (filter_path);
585
586       /* A row-has-child-toggled will be emitted on the parent */
587       if (!root_path
588           || (root_path
589               && gtk_tree_path_is_descendant (store_path, root_path)
590               && gtk_tree_path_compare (store_path, root_path)))
591         {
592           real_path = strip_virtual_root (filter_path, root_path);
593           signal_monitor_append_signal_path (fixture->monitor,
594                                              ROW_HAS_CHILD_TOGGLED,
595                                              real_path);
596
597           gtk_tree_path_free (real_path);
598         }
599     }
600 }
601
602 static void
603 filter_test_append_refilter_signals (FilterTest *fixture,
604                                      int         depth)
605 {
606   /* A special function that walks the tree store like the
607    * model validation functions below.
608    */
609   GtkTreePath *path;
610   GtkTreePath *filter_path;
611
612   path = gtk_tree_path_new ();
613   filter_path = gtk_tree_path_new ();
614   filter_test_append_refilter_signals_recurse (fixture,
615                                                path,
616                                                filter_path,
617                                                depth,
618                                                NULL);
619   gtk_tree_path_free (path);
620   gtk_tree_path_free (filter_path);
621 }
622
623 static void
624 filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
625                                                 int          depth,
626                                                 GtkTreePath *root_path)
627 {
628   /* A special function that walks the tree store like the
629    * model validation functions below.
630    */
631   GtkTreePath *path;
632   GtkTreePath *filter_path;
633
634   path = gtk_tree_path_new ();
635   filter_path = gtk_tree_path_new ();
636   filter_test_append_refilter_signals_recurse (fixture,
637                                                path,
638                                                filter_path,
639                                                depth,
640                                                root_path);
641   gtk_tree_path_free (path);
642   gtk_tree_path_free (filter_path);
643 }
644
645 static void
646 filter_test_enable_filter (FilterTest *fixture)
647 {
648   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
649   gtk_tree_model_filter_refilter (fixture->filter);
650 }
651
652 static void
653 filter_test_block_signals (FilterTest *fixture)
654 {
655   fixture->block_signals = TRUE;
656 }
657
658 static void
659 filter_test_unblock_signals (FilterTest *fixture)
660 {
661   fixture->block_signals = FALSE;
662 }
663
664 static void
665 filter_test_teardown (FilterTest    *fixture,
666                       gconstpointer  test_data)
667 {
668   signal_monitor_free (fixture->monitor);
669
670   gtk_widget_destroy (fixture->tree_view);
671
672   g_object_unref (fixture->filter);
673   g_object_unref (fixture->store);
674 }
675
676 /*
677  * Model structure validation
678  */
679
680 static void
681 check_filter_model_recurse (FilterTest  *fixture,
682                             GtkTreePath *store_parent_path,
683                             GtkTreePath *filter_parent_path)
684 {
685   int i;
686   GtkTreeIter store_iter;
687   GtkTreeIter filter_iter;
688   gboolean store_has_next, filter_has_next;
689
690   gtk_tree_path_down (store_parent_path);
691   gtk_tree_path_down (filter_parent_path);
692
693   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
694                                             &store_iter, store_parent_path);
695   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
696                                              &filter_iter, filter_parent_path);
697
698   for (i = 0; i < LEVEL_LENGTH; i++)
699     {
700       gboolean visible;
701
702       g_return_if_fail (store_has_next == TRUE);
703
704       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
705                           &store_iter,
706                           1, &visible,
707                           -1);
708
709       if (visible)
710         {
711           GtkTreePath *tmp;
712           gchar *filter_str, *store_str;
713
714           g_return_if_fail (filter_has_next == TRUE);
715
716           /* Verify path */
717           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
718                                          &filter_iter);
719           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
720
721           /* Verify model content */
722           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
723                               &store_iter,
724                               0, &store_str,
725                               -1);
726           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
727                               &filter_iter,
728                               0, &filter_str,
729                               -1);
730
731           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
732
733           g_free (store_str);
734           g_free (filter_str);
735
736           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
737                                              &filter_iter))
738             {
739               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
740
741               check_filter_model_recurse (fixture,
742                                           gtk_tree_path_copy (store_parent_path),
743                                           tmp);
744             }
745           else
746             /* Only when we do not recurse we need to free tmp */
747             gtk_tree_path_free (tmp);
748
749           gtk_tree_path_next (filter_parent_path);
750           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
751         }
752
753       gtk_tree_path_next (store_parent_path);
754       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
755     }
756
757   /* Both models should have no more content! */
758   g_return_if_fail (store_has_next == FALSE);
759   g_return_if_fail (filter_has_next == FALSE);
760
761   gtk_tree_path_free (store_parent_path);
762   gtk_tree_path_free (filter_parent_path);
763 }
764
765 static void
766 check_filter_model (FilterTest *fixture)
767 {
768   GtkTreePath *path;
769
770   if (fixture->monitor)
771     signal_monitor_assert_is_empty (fixture->monitor);
772
773   path = gtk_tree_path_new ();
774
775   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
776 }
777
778 static void
779 check_filter_model_with_root (FilterTest  *fixture,
780                               GtkTreePath *path)
781 {
782   if (fixture->monitor)
783     signal_monitor_assert_is_empty (fixture->monitor);
784
785   check_filter_model_recurse (fixture,
786                               gtk_tree_path_copy (path),
787                               gtk_tree_path_new ());
788 }
789
790 /* Helpers */
791
792 static void
793 check_level_length (GtkTreeModelFilter *filter,
794                     const gchar        *level,
795                     const int           expected_length)
796 {
797   if (!level)
798     {
799       int model_length;
800
801       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
802       g_assert_cmpint (model_length, ==, expected_length);
803     }
804   else
805     {
806       int model_length;
807       gboolean retrieved_iter = FALSE;
808       GtkTreeIter iter;
809
810       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
811                                                             &iter, level);
812       g_return_if_fail (retrieved_iter);
813       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
814       g_assert_cmpint (model_length, ==, expected_length);
815     }
816 }
817
818 static void
819 set_path_visibility (FilterTest  *fixture,
820                      const gchar *path,
821                      gboolean     visible)
822 {
823   GtkTreeIter store_iter;
824
825   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
826                                        &store_iter, path);
827   gtk_tree_store_set (fixture->store, &store_iter,
828                       1, visible,
829                       -1);
830 }
831
832 #if 0
833 static void
834 insert_path_with_visibility (FilterTest  *fixture,
835                              const gchar *path_string,
836                              gboolean     visible)
837 {
838   int position;
839   GtkTreePath *path;
840   GtkTreeIter parent, iter;
841
842   path = gtk_tree_path_new_from_string (path_string);
843   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
844   gtk_tree_path_up (path);
845
846   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
847     {
848       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
849       create_tree_store_set_values (fixture->store, &iter, visible);
850     }
851   gtk_tree_path_free (path);
852 }
853 #endif
854
855 /*
856  * The actual tests.
857  */
858
859 static void
860 verify_test_suite (FilterTest    *fixture,
861                    gconstpointer  user_data)
862 {
863   check_filter_model (fixture);
864 }
865
866 static void
867 verify_test_suite_vroot (FilterTest    *fixture,
868                          gconstpointer  user_data)
869 {
870   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
871 }
872
873
874 static void
875 filled_hide_root_level (FilterTest    *fixture,
876                         gconstpointer  user_data)
877 {
878   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
879   set_path_visibility (fixture, "2", FALSE);
880   check_filter_model (fixture);
881   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
882
883   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
884   set_path_visibility (fixture, "0", FALSE);
885   check_filter_model (fixture);
886   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
887
888   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
889   set_path_visibility (fixture, "4", FALSE);
890   check_filter_model (fixture);
891   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
892
893
894   /* Hide remaining */
895   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
896   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
897
898   set_path_visibility (fixture, "1", FALSE);
899   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
900
901   set_path_visibility (fixture, "3", FALSE);
902   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
903
904   check_filter_model (fixture);
905
906   /* Show some */
907   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
908   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
909   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
910   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
911
912   set_path_visibility (fixture, "1", TRUE);
913   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
914
915   set_path_visibility (fixture, "3", TRUE);
916   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
917
918   check_filter_model (fixture);
919 }
920
921 static void
922 filled_hide_child_levels (FilterTest    *fixture,
923                           gconstpointer  user_data)
924 {
925   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
926   set_path_visibility (fixture, "0:2", FALSE);
927   check_filter_model (fixture);
928   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
929   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
930
931   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
932   set_path_visibility (fixture, "0:4", FALSE);
933   check_filter_model (fixture);
934   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
935   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
936
937   set_path_visibility (fixture, "0:4:3", FALSE);
938   check_filter_model (fixture);
939   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
940   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
941
942   set_path_visibility (fixture, "0:4:0", FALSE);
943   set_path_visibility (fixture, "0:4:1", FALSE);
944   set_path_visibility (fixture, "0:4:2", FALSE);
945   set_path_visibility (fixture, "0:4:4", FALSE);
946   check_filter_model (fixture);
947   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
948   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
949
950   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
951   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
952   /* FIXME: Actually, the filter model should not be emitted the
953    * row-has-child-toggled signal here.  *However* an extraneous emission
954    * of this signal does not hurt and is allowed.
955    */
956   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
957   set_path_visibility (fixture, "0:4", TRUE);
958   check_filter_model (fixture);
959   check_level_length (fixture->filter, "0:3", 0);
960
961   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
962   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
963   set_path_visibility (fixture, "0:2", TRUE);
964   check_filter_model (fixture);
965   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
966   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
967   check_level_length (fixture->filter, "0:4", 0);
968
969   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
970   /* Once 0:4:0 got inserted, 0:4 became a parent */
971   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
972   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
973   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
974   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
975
976   set_path_visibility (fixture, "0:4:2", TRUE);
977   set_path_visibility (fixture, "0:4:4", TRUE);
978   signal_monitor_assert_is_empty (fixture->monitor);
979   check_level_length (fixture->filter, "0:4", 2);
980 }
981
982
983 static void
984 filled_vroot_hide_root_level (FilterTest    *fixture,
985                               gconstpointer  user_data)
986 {
987   GtkTreePath *path = (GtkTreePath *)user_data;
988
989   /* These changes do not affect the filter's root level */
990   set_path_visibility (fixture, "0", FALSE);
991   check_filter_model_with_root (fixture, path);
992   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
993   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
994
995   set_path_visibility (fixture, "4", FALSE);
996   check_filter_model_with_root (fixture, path);
997   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
998   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
999
1000   /* Even though we set the virtual root parent node to FALSE,
1001    * the virtual root contents remain.
1002    */
1003   set_path_visibility (fixture, "2", FALSE);
1004   check_filter_model_with_root (fixture, path);
1005   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1006   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1007
1008   /* No change */
1009   set_path_visibility (fixture, "1", FALSE);
1010   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1011   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1012
1013   set_path_visibility (fixture, "3", FALSE);
1014   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1015   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1016
1017   check_filter_model_with_root (fixture, path);
1018
1019   /* Show some */
1020   set_path_visibility (fixture, "2", TRUE);
1021   check_filter_model_with_root (fixture, path);
1022   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1023   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1024
1025   set_path_visibility (fixture, "1", TRUE);
1026   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1027   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1028
1029   set_path_visibility (fixture, "3", TRUE);
1030   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1031   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1032
1033   check_filter_model_with_root (fixture, path);
1034
1035   /* Now test changes in the virtual root level */
1036   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1037   set_path_visibility (fixture, "2:2", FALSE);
1038   check_filter_model_with_root (fixture, path);
1039   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1040
1041   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
1042   set_path_visibility (fixture, "2:4", FALSE);
1043   check_filter_model_with_root (fixture, path);
1044   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1045
1046   set_path_visibility (fixture, "1:4", FALSE);
1047   check_filter_model_with_root (fixture, path);
1048   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1049
1050   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
1051   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
1052   set_path_visibility (fixture, "2:4", TRUE);
1053   check_filter_model_with_root (fixture, path);
1054   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1055
1056   set_path_visibility (fixture, "2", FALSE);
1057   check_filter_model_with_root (fixture, path);
1058   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1059
1060   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1061   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1062   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1063   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1064   set_path_visibility (fixture, "2:0", FALSE);
1065   set_path_visibility (fixture, "2:1", FALSE);
1066   set_path_visibility (fixture, "2:2", FALSE);
1067   set_path_visibility (fixture, "2:3", FALSE);
1068   set_path_visibility (fixture, "2:4", FALSE);
1069   check_filter_model_with_root (fixture, path);
1070   check_level_length (fixture->filter, NULL, 0);
1071
1072   set_path_visibility (fixture, "2", TRUE);
1073   check_filter_model_with_root (fixture, path);
1074   check_level_length (fixture->filter, NULL, 0);
1075
1076   set_path_visibility (fixture, "1:4", FALSE);
1077   check_filter_model_with_root (fixture, path);
1078   check_level_length (fixture->filter, NULL, 0);
1079
1080   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1081   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1082   set_path_visibility (fixture, "2:4", TRUE);
1083   check_filter_model_with_root (fixture, path);
1084   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1085
1086   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1087   set_path_visibility (fixture, "2:4", FALSE);
1088   check_filter_model_with_root (fixture, path);
1089   check_level_length (fixture->filter, NULL, 0);
1090
1091   set_path_visibility (fixture, "2", FALSE);
1092   check_filter_model_with_root (fixture, path);
1093   check_level_length (fixture->filter, NULL, 0);
1094
1095   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1096   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1097   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1098   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1099   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
1100   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1101   set_path_visibility (fixture, "2:0", TRUE);
1102   set_path_visibility (fixture, "2:1", TRUE);
1103   set_path_visibility (fixture, "2:2", TRUE);
1104   check_filter_model_with_root (fixture, path);
1105   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1106
1107   set_path_visibility (fixture, "2", TRUE);
1108   check_filter_model_with_root (fixture, path);
1109   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1110 }
1111
1112 static void
1113 filled_vroot_hide_child_levels (FilterTest    *fixture,
1114                                 gconstpointer  user_data)
1115 {
1116   GtkTreePath *path = (GtkTreePath *)user_data;
1117
1118   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1119   set_path_visibility (fixture, "2:0:2", FALSE);
1120   check_filter_model_with_root (fixture, path);
1121   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1122   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1123
1124   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1125   set_path_visibility (fixture, "2:0:4", FALSE);
1126   check_filter_model_with_root (fixture, path);
1127   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1128   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1129
1130   set_path_visibility (fixture, "2:0:4:3", FALSE);
1131   check_filter_model_with_root (fixture, path);
1132   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1133   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1134
1135   set_path_visibility (fixture, "2:0:4:0", FALSE);
1136   set_path_visibility (fixture, "2:0:4:1", FALSE);
1137   set_path_visibility (fixture, "2:0:4:2", FALSE);
1138   set_path_visibility (fixture, "2:0:4:4", FALSE);
1139   check_filter_model_with_root (fixture, path);
1140   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1141   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1142
1143   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1144   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1145   /* FIXME: Actually, the filter model should not be emitted the
1146    * row-has-child-toggled signal here.  *However* an extraneous emission
1147    * of this signal does not hurt and is allowed.
1148    */
1149   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1150   set_path_visibility (fixture, "2:0:4", TRUE);
1151   check_filter_model_with_root (fixture, path);
1152   check_level_length (fixture->filter, "0:3", 0);
1153
1154   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1155   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1156   set_path_visibility (fixture, "2:0:2", TRUE);
1157   check_filter_model_with_root (fixture, path);
1158   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1159   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1160   check_level_length (fixture->filter, "0:4", 0);
1161
1162   /* FIXME: Inconsistency!  For the non-vroot case we also receive two
1163    * row-has-child-toggled signals here.
1164    */
1165   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
1166   /* Once 0:4:0 got inserted, 0:4 became a parent */
1167   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1168   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
1169   set_path_visibility (fixture, "2:0:4:2", TRUE);
1170   set_path_visibility (fixture, "2:0:4:4", TRUE);
1171   check_level_length (fixture->filter, "0:4", 2);
1172 }
1173
1174
1175 static void
1176 empty_show_nodes (FilterTest    *fixture,
1177                   gconstpointer  user_data)
1178 {
1179   check_filter_model (fixture);
1180   check_level_length (fixture->filter, NULL, 0);
1181
1182   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1183   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1184   set_path_visibility (fixture, "3", TRUE);
1185   check_filter_model (fixture);
1186   check_level_length (fixture->filter, NULL, 1);
1187   check_level_length (fixture->filter, "0", 0);
1188
1189   set_path_visibility (fixture, "3:2:2", TRUE);
1190   check_filter_model (fixture);
1191   check_level_length (fixture->filter, NULL, 1);
1192   check_level_length (fixture->filter, "0", 0);
1193
1194   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1195   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1196   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1197   set_path_visibility (fixture, "3:2", TRUE);
1198   check_filter_model (fixture);
1199   check_level_length (fixture->filter, NULL, 1);
1200   check_level_length (fixture->filter, "0", 1);
1201   check_level_length (fixture->filter, "0:0", 1);
1202   check_level_length (fixture->filter, "0:0:0", 0);
1203
1204   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1205   set_path_visibility (fixture, "3", FALSE);
1206   check_filter_model (fixture);
1207   check_level_length (fixture->filter, NULL, 0);
1208
1209   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1210   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1211   set_path_visibility (fixture, "3:2:1", TRUE);
1212   set_path_visibility (fixture, "3", TRUE);
1213   check_filter_model (fixture);
1214   check_level_length (fixture->filter, NULL, 1);
1215   check_level_length (fixture->filter, "0", 1);
1216   check_level_length (fixture->filter, "0:0", 2);
1217   check_level_length (fixture->filter, "0:0:0", 0);
1218 }
1219
1220 static void
1221 empty_show_multiple_nodes (FilterTest    *fixture,
1222                            gconstpointer  user_data)
1223 {
1224   GtkTreeIter iter;
1225   GtkTreePath *changed_path;
1226
1227   check_filter_model (fixture);
1228   check_level_length (fixture->filter, NULL, 0);
1229
1230   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1231   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1232   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1233   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1234   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "1");
1235   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1236
1237   /* We simulate a change in visible func condition with this.  The
1238    * visibility state of multiple nodes changes at once, we emit row-changed
1239    * for these nodes (and others) after that.
1240    */
1241   filter_test_block_signals (fixture);
1242   set_path_visibility (fixture, "3", TRUE);
1243   set_path_visibility (fixture, "4", TRUE);
1244   filter_test_unblock_signals (fixture);
1245
1246   changed_path = gtk_tree_path_new ();
1247   gtk_tree_path_append_index (changed_path, 2);
1248   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1249                            &iter, changed_path);
1250   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1251                               changed_path, &iter);
1252
1253   gtk_tree_path_next (changed_path);
1254   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1255   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1256                               changed_path, &iter);
1257
1258   gtk_tree_path_next (changed_path);
1259   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1260   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1261                               changed_path, &iter);
1262
1263   gtk_tree_path_free (changed_path);
1264
1265   check_filter_model (fixture);
1266   check_level_length (fixture->filter, NULL, 2);
1267   check_level_length (fixture->filter, "0", 0);
1268
1269   set_path_visibility (fixture, "3:2:2", TRUE);
1270   check_filter_model (fixture);
1271   check_level_length (fixture->filter, NULL, 2);
1272   check_level_length (fixture->filter, "0", 0);
1273
1274   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1275   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1276   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1277   set_path_visibility (fixture, "3:2", TRUE);
1278   check_filter_model (fixture);
1279   check_level_length (fixture->filter, NULL, 2);
1280   check_level_length (fixture->filter, "0", 1);
1281   check_level_length (fixture->filter, "0:0", 1);
1282   check_level_length (fixture->filter, "0:0:0", 0);
1283
1284   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1285   set_path_visibility (fixture, "3", FALSE);
1286   check_filter_model (fixture);
1287   check_level_length (fixture->filter, NULL, 1);
1288
1289   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1290   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1291   set_path_visibility (fixture, "3:2:1", TRUE);
1292   set_path_visibility (fixture, "3", TRUE);
1293   check_filter_model (fixture);
1294   check_level_length (fixture->filter, NULL, 2);
1295   check_level_length (fixture->filter, "0", 1);
1296   check_level_length (fixture->filter, "0:0", 2);
1297   check_level_length (fixture->filter, "0:0:0", 0);
1298 }
1299
1300 static void
1301 empty_vroot_show_nodes (FilterTest    *fixture,
1302                         gconstpointer  user_data)
1303 {
1304   GtkTreePath *path = (GtkTreePath *)user_data;
1305
1306   check_filter_model_with_root (fixture, path);
1307   check_level_length (fixture->filter, NULL, 0);
1308
1309   set_path_visibility (fixture, "2", TRUE);
1310   check_filter_model_with_root (fixture, path);
1311   check_level_length (fixture->filter, NULL, 0);
1312
1313   set_path_visibility (fixture, "2:2:2", TRUE);
1314   check_filter_model_with_root (fixture, path);
1315   check_level_length (fixture->filter, NULL, 0);
1316
1317   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1318   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1319   set_path_visibility (fixture, "2:2", TRUE);
1320   check_filter_model_with_root (fixture, path);
1321   check_level_length (fixture->filter, NULL, 1);
1322   check_level_length (fixture->filter, "0", 1);
1323   check_level_length (fixture->filter, "0:0", 0);
1324
1325   set_path_visibility (fixture, "3", TRUE);
1326   check_filter_model_with_root (fixture, path);
1327   check_level_length (fixture->filter, NULL, 1);
1328
1329   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1330   set_path_visibility (fixture, "2:2", FALSE);
1331   check_filter_model_with_root (fixture, path);
1332   check_level_length (fixture->filter, NULL, 0);
1333
1334   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1335   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1336   set_path_visibility (fixture, "2:2:1", TRUE);
1337   set_path_visibility (fixture, "2:2", TRUE);
1338   check_filter_model_with_root (fixture, path);
1339   check_level_length (fixture->filter, NULL, 1);
1340   check_level_length (fixture->filter, "0", 2);
1341   check_level_length (fixture->filter, "0:1", 0);
1342 }
1343
1344 static void
1345 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1346                                  gconstpointer  user_data)
1347 {
1348   GtkTreeIter iter;
1349   GtkTreePath *changed_path;
1350   GtkTreePath *path = (GtkTreePath *)user_data;
1351
1352   check_filter_model_with_root (fixture, path);
1353   check_level_length (fixture->filter, NULL, 0);
1354
1355   /* We simulate a change in visible func condition with this.  The
1356    * visibility state of multiple nodes changes at once, we emit row-changed
1357    * for these nodes (and others) after that.
1358    */
1359   filter_test_block_signals (fixture);
1360   set_path_visibility (fixture, "2", TRUE);
1361   set_path_visibility (fixture, "3", TRUE);
1362   filter_test_unblock_signals (fixture);
1363
1364   changed_path = gtk_tree_path_new ();
1365   gtk_tree_path_append_index (changed_path, 1);
1366   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1367                            &iter, changed_path);
1368   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1369                               changed_path, &iter);
1370
1371   gtk_tree_path_next (changed_path);
1372   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1373   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1374                               changed_path, &iter);
1375
1376   gtk_tree_path_next (changed_path);
1377   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1378   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1379                               changed_path, &iter);
1380
1381   gtk_tree_path_next (changed_path);
1382   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1383   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1384                               changed_path, &iter);
1385
1386   gtk_tree_path_free (changed_path);
1387
1388   check_filter_model_with_root (fixture, path);
1389   check_level_length (fixture->filter, NULL, 0);
1390
1391   set_path_visibility (fixture, "2:2:2", TRUE);
1392   check_filter_model_with_root (fixture, path);
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   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1398   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1399
1400   /* Again, we simulate a call to refilter */
1401   filter_test_block_signals (fixture);
1402   set_path_visibility (fixture, "2:2", TRUE);
1403   set_path_visibility (fixture, "2:3", TRUE);
1404   filter_test_unblock_signals (fixture);
1405
1406   changed_path = gtk_tree_path_new ();
1407   gtk_tree_path_append_index (changed_path, 2);
1408   gtk_tree_path_append_index (changed_path, 1);
1409   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1410                            &iter, changed_path);
1411   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1412                               changed_path, &iter);
1413
1414   gtk_tree_path_next (changed_path);
1415   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1416   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1417                               changed_path, &iter);
1418
1419   gtk_tree_path_next (changed_path);
1420   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1421   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1422                               changed_path, &iter);
1423
1424   gtk_tree_path_next (changed_path);
1425   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1426   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1427                               changed_path, &iter);
1428
1429   gtk_tree_path_free (changed_path);
1430
1431   check_filter_model_with_root (fixture, path);
1432   check_level_length (fixture->filter, NULL, 2);
1433   check_level_length (fixture->filter, "0", 1);
1434   check_level_length (fixture->filter, "0:0", 0);
1435
1436   set_path_visibility (fixture, "3", TRUE);
1437   check_filter_model_with_root (fixture, path);
1438   check_level_length (fixture->filter, NULL, 2);
1439
1440   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1441   set_path_visibility (fixture, "2:2", FALSE);
1442   check_filter_model_with_root (fixture, path);
1443   check_level_length (fixture->filter, NULL, 1);
1444
1445   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1446   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1447   set_path_visibility (fixture, "2:2:1", TRUE);
1448   set_path_visibility (fixture, "2:2", TRUE);
1449   check_filter_model_with_root (fixture, path);
1450   check_level_length (fixture->filter, NULL, 2);
1451   check_level_length (fixture->filter, "0", 2);
1452   check_level_length (fixture->filter, "0:1", 0);
1453 }
1454
1455
1456 static void
1457 unfiltered_hide_single (FilterTest    *fixture,
1458                         gconstpointer  user_data)
1459
1460 {
1461   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1462   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1463   set_path_visibility (fixture, "2", FALSE);
1464
1465   signal_monitor_assert_is_empty (fixture->monitor);
1466   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1467
1468   /* The view only shows the root level, so the filter model only has
1469    * the first two levels cached.
1470    */
1471   filter_test_append_refilter_signals (fixture, 2);
1472   filter_test_enable_filter (fixture);
1473
1474   check_filter_model (fixture);
1475   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1476 }
1477
1478 static void
1479 unfiltered_hide_single_child (FilterTest    *fixture,
1480                               gconstpointer  user_data)
1481
1482 {
1483   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1484   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1485   set_path_visibility (fixture, "2:2", FALSE);
1486
1487   signal_monitor_assert_is_empty (fixture->monitor);
1488   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1489   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1490
1491   /* The view only shows the root level, so the filter model only has
1492    * the first two levels cached.
1493    */
1494   filter_test_append_refilter_signals (fixture, 2);
1495   filter_test_enable_filter (fixture);
1496
1497   check_filter_model (fixture);
1498   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1499   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1500 }
1501
1502 static void
1503 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1504                                     gconstpointer  user_data)
1505
1506 {
1507   /* This row is not shown, so its signal is not propagated */
1508   set_path_visibility (fixture, "2:2:2", FALSE);
1509
1510   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1511   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1512   set_path_visibility (fixture, "2:2", FALSE);
1513
1514   signal_monitor_assert_is_empty (fixture->monitor);
1515   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1516   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1517   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1518
1519   /* The view only shows the root level, so the filter model only has
1520    * the first two levels cached.
1521    */
1522   filter_test_append_refilter_signals (fixture, 2);
1523   filter_test_enable_filter (fixture);
1524
1525   check_filter_model (fixture);
1526   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1527   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1528
1529   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1530   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1531   set_path_visibility (fixture, "2:2", TRUE);
1532
1533   check_filter_model (fixture);
1534   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1535   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1536   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1537 }
1538
1539
1540 static void
1541 unfiltered_vroot_hide_single (FilterTest    *fixture,
1542                               gconstpointer  user_data)
1543
1544 {
1545   GtkTreePath *path = (GtkTreePath *)user_data;
1546
1547   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1548   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1549   set_path_visibility (fixture, "2:2", FALSE);
1550
1551   signal_monitor_assert_is_empty (fixture->monitor);
1552   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1553
1554   /* The view only shows the root level, so the filter model only has
1555    * the first two levels cached.  (We add an additional level to
1556    * take the virtual root into account).
1557    */
1558   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1559   filter_test_enable_filter (fixture);
1560
1561   check_filter_model_with_root (fixture, path);
1562   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1563 }
1564
1565 static void
1566 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1567                                     gconstpointer  user_data)
1568
1569 {
1570   GtkTreePath *path = (GtkTreePath *)user_data;
1571
1572   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1573   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1574   set_path_visibility (fixture, "2:2:2", FALSE);
1575
1576   signal_monitor_assert_is_empty (fixture->monitor);
1577   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1578   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1579
1580   /* The view only shows the root level, so the filter model only has
1581    * the first two levels cached.  (We add an additional level to take
1582    * the virtual root into account).
1583    */
1584   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1585   filter_test_enable_filter (fixture);
1586
1587   check_filter_model_with_root (fixture, path);
1588   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1589   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1590 }
1591
1592 static void
1593 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1594                                           gconstpointer  user_data)
1595
1596 {
1597   GtkTreePath *path = (GtkTreePath *)user_data;
1598
1599   /* This row is not shown, so its signal is not propagated */
1600   set_path_visibility (fixture, "2:2:2:2", FALSE);
1601
1602   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1603   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1604   set_path_visibility (fixture, "2:2:2", FALSE);
1605
1606   signal_monitor_assert_is_empty (fixture->monitor);
1607   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1608   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1609   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1610
1611   /* The view only shows the root level, so the filter model only has
1612    * the first two levels cached.
1613    */
1614   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1615   filter_test_enable_filter (fixture);
1616
1617   check_filter_model_with_root (fixture, path);
1618   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1619   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1620
1621   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1622   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1623   set_path_visibility (fixture, "2:2:2", TRUE);
1624
1625   check_filter_model_with_root (fixture, path);
1626   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1627   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1628   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1629 }
1630
1631
1632
1633 static void
1634 unfiltered_show_single (FilterTest    *fixture,
1635                         gconstpointer  user_data)
1636
1637 {
1638   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1639   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1640   set_path_visibility (fixture, "2", TRUE);
1641
1642   signal_monitor_assert_is_empty (fixture->monitor);
1643   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1644
1645   /* The view only shows the root level, so the filter model only has
1646    * the first two levels cached.
1647    */
1648   filter_test_append_refilter_signals (fixture, 2);
1649   filter_test_enable_filter (fixture);
1650
1651   check_filter_model (fixture);
1652   check_level_length (fixture->filter, NULL, 1);
1653 }
1654
1655 static void
1656 unfiltered_show_single_child (FilterTest    *fixture,
1657                               gconstpointer  user_data)
1658
1659 {
1660   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1661   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1662   set_path_visibility (fixture, "2:2", TRUE);
1663
1664   signal_monitor_assert_is_empty (fixture->monitor);
1665   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1666   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1667
1668   /* The view only shows the root level, so the filter model only has
1669    * the first two levels cached.
1670    */
1671   filter_test_append_refilter_signals (fixture, 3);
1672   filter_test_enable_filter (fixture);
1673
1674   check_filter_model (fixture);
1675   check_level_length (fixture->filter, NULL, 0);
1676
1677   /* From here we are filtered, "2" in the real model is "0" in the filter
1678    * model.
1679    */
1680   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1681   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1682   set_path_visibility (fixture, "2", TRUE);
1683   signal_monitor_assert_is_empty (fixture->monitor);
1684   check_level_length (fixture->filter, NULL, 1);
1685   check_level_length (fixture->filter, "0", 1);
1686 }
1687
1688 static void
1689 unfiltered_show_single_multi_level (FilterTest    *fixture,
1690                                     gconstpointer  user_data)
1691
1692 {
1693   /* The view is not showing this row (collapsed state), so it is not
1694    * referenced.  The signal should not go through.
1695    */
1696   set_path_visibility (fixture, "2:2:2", TRUE);
1697
1698   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1699   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1700   set_path_visibility (fixture, "2:2", TRUE);
1701
1702   signal_monitor_assert_is_empty (fixture->monitor);
1703   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1704   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1705   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1706
1707   /* The view only shows the root level, so the filter model only has
1708    * the first two levels cached.
1709    */
1710   filter_test_append_refilter_signals (fixture, 3);
1711   filter_test_enable_filter (fixture);
1712
1713   check_filter_model (fixture);
1714   check_level_length (fixture->filter, NULL, 0);
1715
1716   /* From here we are filtered, "2" in the real model is "0" in the filter
1717    * model.
1718    */
1719   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1720   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1721   set_path_visibility (fixture, "2", TRUE);
1722   check_filter_model (fixture);
1723   check_level_length (fixture->filter, NULL, 1);
1724   check_level_length (fixture->filter, "0", 1);
1725   check_level_length (fixture->filter, "0:0", 1);
1726 }
1727
1728
1729 static void
1730 unfiltered_vroot_show_single (FilterTest    *fixture,
1731                               gconstpointer  user_data)
1732
1733 {
1734   GtkTreePath *path = (GtkTreePath *)user_data;
1735
1736   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1737   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1738   set_path_visibility (fixture, "2:2", TRUE);
1739
1740   signal_monitor_assert_is_empty (fixture->monitor);
1741   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1742
1743   /* The view only shows the root level, so the filter model only has
1744    * the first two levels cached.
1745    */
1746   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1747   filter_test_enable_filter (fixture);
1748
1749   check_filter_model_with_root (fixture, path);
1750   check_level_length (fixture->filter, NULL, 1);
1751 }
1752
1753 static void
1754 unfiltered_vroot_show_single_child (FilterTest    *fixture,
1755                                     gconstpointer  user_data)
1756
1757 {
1758   GtkTreePath *path = (GtkTreePath *)user_data;
1759
1760   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1761   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1762   set_path_visibility (fixture, "2:2:2", TRUE);
1763
1764   signal_monitor_assert_is_empty (fixture->monitor);
1765   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1766   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1767
1768   /* The view only shows the root level, so the filter model only has
1769    * the first two levels cached.
1770    */
1771   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1772   filter_test_enable_filter (fixture);
1773
1774   check_filter_model_with_root (fixture, path);
1775   check_level_length (fixture->filter, NULL, 0);
1776
1777   /* From here we are filtered, "2" in the real model is "0" in the filter
1778    * model.
1779    */
1780   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1781   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1782   set_path_visibility (fixture, "2:2", TRUE);
1783   signal_monitor_assert_is_empty (fixture->monitor);
1784   check_level_length (fixture->filter, NULL, 1);
1785   check_level_length (fixture->filter, "0", 1);
1786 }
1787
1788 static void
1789 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
1790                                           gconstpointer  user_data)
1791
1792 {
1793   GtkTreePath *path = (GtkTreePath *)user_data;
1794
1795   /* The view is not showing this row (collapsed state), so it is not
1796    * referenced.  The signal should not go through.
1797    */
1798   set_path_visibility (fixture, "2:2:2:2", TRUE);
1799
1800   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1801   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1802   set_path_visibility (fixture, "2:2:2", TRUE);
1803
1804   signal_monitor_assert_is_empty (fixture->monitor);
1805   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1806   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1807   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1808
1809   /* The view only shows the root level, so the filter model only has
1810    * the first two levels cached.
1811    */
1812   filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
1813   filter_test_enable_filter (fixture);
1814
1815   check_filter_model_with_root (fixture, path);
1816   check_level_length (fixture->filter, NULL, 0);
1817
1818   /* From here we are filtered, "2" in the real model is "0" in the filter
1819    * model.
1820    */
1821   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1822   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1823   set_path_visibility (fixture, "2:2", TRUE);
1824   check_filter_model_with_root (fixture, path);
1825   check_level_length (fixture->filter, NULL, 1);
1826   check_level_length (fixture->filter, "0", 1);
1827   check_level_length (fixture->filter, "0:0", 1);
1828 }
1829
1830
1831 static void
1832 insert_before (void)
1833 {
1834   GtkTreeStore *store;
1835   GtkTreeModel *filter;
1836   GtkWidget *tree_view;
1837   SignalMonitor *monitor;
1838   GtkTreeIter iter;
1839   GtkTreeIter last_iter;
1840   GtkTreePath *path;
1841
1842   /* This tests two aspects of the row-inserted handling:
1843    *   1) If the newly inserted node was already handled by building
1844    *      the root level, don't handle it a second time.
1845    *   2) Offsets of existing nodes must be updated when a new
1846    *      node is inserted.
1847    */
1848
1849   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1850   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1851   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
1852                                             1);
1853
1854   tree_view = gtk_tree_view_new_with_model (filter);
1855   monitor = signal_monitor_new (filter);
1856
1857   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
1858
1859   /* Insert 0 */
1860   path = gtk_tree_path_new_from_indices (0, -1);
1861   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1862   gtk_tree_path_free (path);
1863
1864   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
1865                                      0, "Foo", 1, TRUE, -1);
1866
1867   signal_monitor_assert_is_empty (monitor);
1868   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1869
1870   /* Insert 1 */
1871   path = gtk_tree_path_new_from_indices (1, -1);
1872   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1873   gtk_tree_path_free (path);
1874
1875   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1876                                      0, "Foo", 1, TRUE, -1);
1877   last_iter = iter;
1878
1879   signal_monitor_assert_is_empty (monitor);
1880   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
1881
1882   /* Insert on 1 again -- invisible */
1883   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1884                                      0, "Foo", 1, FALSE, -1);
1885
1886   signal_monitor_assert_is_empty (monitor);
1887   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
1888
1889   /* Insert on 1 again -- visible */
1890   path = gtk_tree_path_new_from_indices (1, -1);
1891   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1892   gtk_tree_path_free (path);
1893
1894   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1895                                      0, "Foo", 1, TRUE, -1);
1896
1897   signal_monitor_assert_is_empty (monitor);
1898   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
1899
1900   /* Modify the iter that should be at the last position and check the
1901    * signal we get.
1902    */
1903   path = gtk_tree_path_new_from_indices (2, -1);
1904   signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
1905   gtk_tree_path_free (path);
1906
1907   gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
1908
1909   signal_monitor_assert_is_empty (monitor);
1910   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
1911 }
1912
1913 static void
1914 insert_child (void)
1915 {
1916   GtkTreeStore *store;
1917   GtkTreeModel *filter;
1918   GtkWidget *tree_view;
1919   SignalMonitor *monitor;
1920   GtkTreeIter parent, iter;
1921   GtkTreePath *path;
1922
1923   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1924
1925   gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
1926                                      0, "Parent", 1, TRUE, -1);
1927
1928
1929   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1930   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
1931                                             1);
1932
1933   tree_view = gtk_tree_view_new_with_model (filter);
1934   monitor = signal_monitor_new (filter);
1935
1936   /* Insert child -- invisible */
1937   path = gtk_tree_path_new_from_indices (0, -1);
1938   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1939   /* The signal is received twice, once a pass through from GtkTreeStore
1940    * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
1941    * hurt.
1942    */
1943   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1944   gtk_tree_path_free (path);
1945
1946   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
1947                                      0, "Child", 1, FALSE, -1);
1948
1949   signal_monitor_assert_is_empty (monitor);
1950   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1951
1952   /* Insert child */
1953   path = gtk_tree_path_new_from_indices (0, 0, -1);
1954   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1955   gtk_tree_path_up (path); /* 0 */
1956   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1957   gtk_tree_path_free (path);
1958
1959   gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
1960                                      0, "Child", 1, TRUE, -1);
1961
1962   signal_monitor_assert_is_empty (monitor);
1963   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1964
1965   /* Insert child -- invisible */
1966   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
1967                                      0, "Child", 1, FALSE, -1);
1968
1969   signal_monitor_assert_is_empty (monitor);
1970   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1971 }
1972
1973
1974
1975 static void
1976 remove_node (void)
1977 {
1978   GtkTreeIter iter, iter1, iter2, iter3;
1979   GtkListStore *list;
1980   GtkTreeModel *filter;
1981   GtkWidget *view G_GNUC_UNUSED;
1982
1983   list = gtk_list_store_new (1, G_TYPE_INT);
1984   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
1985   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
1986   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
1987   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
1988   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
1989   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
1990   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
1991   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
1992
1993   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
1994   view = gtk_tree_view_new_with_model (filter);
1995
1996   gtk_list_store_remove (list, &iter1);
1997   gtk_list_store_remove (list, &iter3);
1998   gtk_list_store_remove (list, &iter2);
1999
2000   gtk_widget_destroy (view);
2001   g_object_unref (filter);
2002   g_object_unref (list);
2003 }
2004
2005 static void
2006 remove_node_vroot (void)
2007 {
2008   GtkTreeIter parent, root;
2009   GtkTreeIter iter, iter1, iter2, iter3;
2010   GtkTreeStore *tree;
2011   GtkTreeModel *filter;
2012   GtkTreePath *path;
2013   GtkWidget *view G_GNUC_UNUSED;
2014
2015   tree = gtk_tree_store_new (1, G_TYPE_INT);
2016   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2017   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2018
2019   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2020   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2021   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2022   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2023   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2024   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2025   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2026   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2027
2028   path = gtk_tree_path_new_from_indices (0, 0, -1);
2029   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2030   gtk_tree_path_free (path);
2031
2032   view = gtk_tree_view_new_with_model (filter);
2033
2034   gtk_tree_store_remove (tree, &iter1);
2035   gtk_tree_store_remove (tree, &iter3);
2036   gtk_tree_store_remove (tree, &iter2);
2037
2038   gtk_widget_destroy (view);
2039   g_object_unref (filter);
2040   g_object_unref (tree);
2041 }
2042
2043 static void
2044 remove_vroot_ancestor (void)
2045 {
2046   GtkTreeIter parent, root;
2047   GtkTreeIter iter, iter1, iter2, iter3;
2048   GtkTreeStore *tree;
2049   GtkTreeModel *filter;
2050   GtkTreePath *path;
2051   GtkWidget *view G_GNUC_UNUSED;
2052
2053   tree = gtk_tree_store_new (1, G_TYPE_INT);
2054   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2055   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2056
2057   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2058   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2059   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2060   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2061   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2062   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2063   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2064   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2065
2066   path = gtk_tree_path_new_from_indices (0, 0, -1);
2067   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2068   gtk_tree_path_free (path);
2069
2070   view = gtk_tree_view_new_with_model (filter);
2071
2072   gtk_tree_store_remove (tree, &parent);
2073
2074   gtk_widget_destroy (view);
2075   g_object_unref (filter);
2076   g_object_unref (tree);
2077 }
2078
2079
2080 static gboolean
2081 specific_path_dependent_filter_func (GtkTreeModel *model,
2082                                      GtkTreeIter  *iter,
2083                                      gpointer      data)
2084 {
2085   GtkTreePath *path;
2086
2087   path = gtk_tree_model_get_path (model, iter);
2088   if (gtk_tree_path_get_indices (path)[0] < 4)
2089     return FALSE;
2090
2091   return TRUE;
2092 }
2093
2094 static void
2095 specific_path_dependent_filter (void)
2096 {
2097   int i;
2098   GtkTreeIter iter;
2099   GtkListStore *list;
2100   GtkTreeModel *sort;
2101   GtkTreeModel *filter;
2102
2103   list = gtk_list_store_new (1, G_TYPE_INT);
2104   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2105   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2106   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2107   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2108   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2109   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2110   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2111   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2112
2113   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
2114   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
2115   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2116                                           specific_path_dependent_filter_func,
2117                                           NULL, NULL);
2118
2119   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
2120                                         GTK_SORT_DESCENDING);
2121
2122   for (i = 0; i < 4; i++)
2123     {
2124       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
2125                                          NULL, 1))
2126         gtk_list_store_remove (list, &iter);
2127
2128       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
2129                                          NULL, 2))
2130         gtk_list_store_remove (list, &iter);
2131     }
2132
2133   g_object_unref (filter);
2134   g_object_unref (sort);
2135   g_object_unref (list);
2136 }
2137
2138
2139 static gboolean
2140 specific_append_after_collapse_visible_func (GtkTreeModel *model,
2141                                              GtkTreeIter  *iter,
2142                                              gpointer      data)
2143 {
2144   gint number;
2145   gboolean hide_negative_numbers;
2146
2147   gtk_tree_model_get (model, iter, 1, &number, -1);
2148   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
2149
2150   return (number >= 0 || !hide_negative_numbers);
2151 }
2152
2153 static void
2154 specific_append_after_collapse (void)
2155 {
2156   /* This test is based on one of the test cases I found in my
2157    * old test cases directory.  I unfortunately do not have a record
2158    * from who this test case originated.  -Kris.
2159    *
2160    * General idea:
2161    * - Construct tree.
2162    * - Show tree, expand, collapse.
2163    * - Add a row.
2164    */
2165
2166   GtkTreeIter iter;
2167   GtkTreeIter child_iter;
2168   GtkTreeIter child_iter2;
2169   GtkTreePath *append_path;
2170   GtkTreeStore *store;
2171   GtkTreeModel *filter;
2172   GtkTreeModel *sort;
2173
2174   GtkWidget *window;
2175   GtkWidget *tree_view;
2176
2177   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
2178
2179   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2180   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2181                      GINT_TO_POINTER (FALSE));
2182   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2183                                           specific_append_after_collapse_visible_func,
2184                                           filter, NULL);
2185
2186   sort = gtk_tree_model_sort_new_with_model (filter);
2187
2188   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2189   tree_view = gtk_tree_view_new_with_model (sort);
2190   gtk_container_add (GTK_CONTAINER (window), tree_view);
2191   gtk_widget_realize (tree_view);
2192
2193   while (gtk_events_pending ())
2194     gtk_main_iteration ();
2195
2196   gtk_tree_store_prepend (store, &iter, NULL);
2197   gtk_tree_store_set (store, &iter,
2198                       0, "hallo", 1, 1, -1);
2199
2200   gtk_tree_store_append (store, &child_iter, &iter);
2201   gtk_tree_store_set (store, &child_iter,
2202                       0, "toemaar", 1, 1, -1);
2203
2204   gtk_tree_store_append (store, &child_iter2, &child_iter);
2205   gtk_tree_store_set (store, &child_iter2,
2206                       0, "very deep", 1, 1, -1);
2207
2208   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
2209
2210   gtk_tree_store_append (store, &child_iter, &iter);
2211   gtk_tree_store_set (store, &child_iter,
2212                       0, "sja", 1, 1, -1);
2213
2214   gtk_tree_store_append (store, &child_iter, &iter);
2215   gtk_tree_store_set (store, &child_iter,
2216                       0, "some word", 1, -1, -1);
2217
2218   /* Expand and collapse the tree */
2219   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2220   while (gtk_events_pending ())
2221     gtk_main_iteration ();
2222
2223   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2224   while (gtk_events_pending ())
2225     gtk_main_iteration ();
2226
2227   /* Add another it */
2228   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2229                      GINT_TO_POINTER (TRUE));
2230
2231   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
2232     {
2233       gtk_tree_store_append (store, &child_iter, &iter);
2234       gtk_tree_store_set (store, &child_iter,
2235                           0, "new new new !!", 1, 1, -1);
2236     }
2237   gtk_tree_path_free (append_path);
2238
2239   /* Expand */
2240   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2241   while (gtk_events_pending ())
2242     gtk_main_iteration ();
2243 }
2244
2245
2246 static gint
2247 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
2248                                                GtkTreeIter   *iter1,
2249                                                GtkTreeIter   *iter2,
2250                                                gpointer       data)
2251 {
2252   return -1;
2253 }
2254
2255 static gboolean
2256 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
2257                                                GtkTreeIter   *iter,
2258                                                gpointer       data)
2259 {
2260   char *item = NULL;
2261
2262   /* Do reference the model */
2263   gtk_tree_model_get (model, iter, 0, &item, -1);
2264   g_free (item);
2265
2266   return FALSE;
2267 }
2268
2269 static void
2270 specific_sort_filter_remove_node (void)
2271 {
2272   /* This test is based on one of the test cases I found in my
2273    * old test cases directory.  I unfortunately do not have a record
2274    * from who this test case originated.  -Kris.
2275    *
2276    * General idea:
2277    *  - Create tree store, sort, filter models.  The sort model has
2278    *    a default sort func that is enabled, filter model a visible func
2279    *    that defaults to returning FALSE.
2280    *  - Remove a node from the tree store.
2281    */
2282
2283   GtkTreeIter iter;
2284   GtkTreeStore *store;
2285   GtkTreeModel *filter;
2286   GtkTreeModel *sort;
2287
2288   GtkWidget *window;
2289   GtkWidget *tree_view;
2290
2291   store = gtk_tree_store_new (1, G_TYPE_STRING);
2292   gtk_tree_store_append (store, &iter, NULL);
2293   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
2294
2295   gtk_tree_store_append (store, &iter, NULL);
2296   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
2297
2298   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2299   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2300                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
2301
2302   filter = gtk_tree_model_filter_new (sort, NULL);
2303   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2304                                           specific_sort_filter_remove_node_visible_func,
2305                                           filter, NULL);
2306
2307
2308   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2309   tree_view = gtk_tree_view_new_with_model (filter);
2310   gtk_container_add (GTK_CONTAINER (window), tree_view);
2311   gtk_widget_realize (tree_view);
2312
2313   while (gtk_events_pending ())
2314     gtk_main_iteration ();
2315
2316   /* Remove a node */
2317   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
2318   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
2319   gtk_tree_store_remove (store, &iter);
2320
2321   while (gtk_events_pending ())
2322     gtk_main_iteration ();
2323 }
2324
2325
2326 static void
2327 specific_sort_filter_remove_root (void)
2328 {
2329   /* This test is based on one of the test cases I found in my
2330    * old test cases directory.  I unfortunately do not have a record
2331    * from who this test case originated.  -Kris.
2332    */
2333
2334   GtkTreeModel *model, *sort, *filter;
2335   GtkTreeIter root, mid, leaf;
2336   GtkTreePath *path;
2337
2338   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
2339   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
2340   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
2341   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
2342
2343   path = gtk_tree_model_get_path (model, &mid);
2344
2345   sort = gtk_tree_model_sort_new_with_model (model);
2346   filter = gtk_tree_model_filter_new (sort, path);
2347
2348   gtk_tree_path_free (path);
2349
2350   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
2351
2352   g_object_unref (filter);
2353   g_object_unref (sort);
2354   g_object_unref (model);
2355 }
2356
2357
2358 static void
2359 specific_root_mixed_visibility (void)
2360 {
2361   int i;
2362   GtkTreeModel *filter;
2363   /* A bit nasty, apologies */
2364   FilterTest fixture;
2365
2366   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2367
2368   for (i = 0; i < LEVEL_LENGTH; i++)
2369     {
2370       GtkTreeIter iter;
2371
2372       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
2373       if (i % 2 == 0)
2374         create_tree_store_set_values (fixture.store, &iter, TRUE);
2375       else
2376         create_tree_store_set_values (fixture.store, &iter, FALSE);
2377     }
2378
2379   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2380   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2381   fixture.monitor = NULL;
2382
2383   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
2384
2385   /* In order to trigger the potential bug, we should not access
2386    * the filter model here (so don't call the check functions).
2387    */
2388
2389   /* Change visibility of an odd row to TRUE */
2390   set_path_visibility (&fixture, "3", TRUE);
2391   check_filter_model (&fixture);
2392   check_level_length (fixture.filter, NULL, 4);
2393 }
2394
2395
2396
2397 static gboolean
2398 specific_has_child_filter_filter_func (GtkTreeModel *model,
2399                                        GtkTreeIter  *iter,
2400                                        gpointer      data)
2401 {
2402   return gtk_tree_model_iter_has_child (model, iter);
2403 }
2404
2405 static void
2406 specific_has_child_filter (void)
2407 {
2408   GtkTreeModel *filter;
2409   GtkTreeIter iter, root;
2410   FilterTest fixture; /* This is not how it should be done */
2411   GtkWidget *tree_view;
2412
2413   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2414   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2415   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2416   fixture.monitor = signal_monitor_new (filter);
2417
2418   tree_view = gtk_tree_view_new_with_model (filter);
2419
2420   /* We will filter on parent state using a filter function.  We will
2421    * manually keep the boolean column in sync, so that we can use
2422    * check_filter_model() to check the consistency of the model.
2423    */
2424   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2425    * to be able to check the structure here.  We keep the calls to
2426    * check_filter_model() commented out until then.
2427    */
2428   gtk_tree_model_filter_set_visible_func (fixture.filter,
2429                                           specific_has_child_filter_filter_func,
2430                                           NULL, NULL);
2431
2432   /* The first node will be initially invisible: no signals */
2433   gtk_tree_store_append (fixture.store, &root, NULL);
2434   create_tree_store_set_values (fixture.store, &root, FALSE);
2435
2436   /* check_filter_model (&fixture); */
2437   check_level_length (fixture.filter, NULL, 0);
2438   signal_monitor_assert_is_empty (fixture.monitor);
2439
2440   /* Insert a child node. This will cause the parent to become visible
2441    * since there is a child now.
2442    */
2443   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
2444   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2445   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2446
2447   gtk_tree_store_append (fixture.store, &iter, &root);
2448   create_tree_store_set_values (fixture.store, &iter, TRUE);
2449
2450   /* Parent must now be visible.  Do the level length check first,
2451    * to avoid modifying the child model triggering a row-changed to
2452    * the filter model.
2453    */
2454   check_level_length (fixture.filter, NULL, 1);
2455   check_level_length (fixture.filter, "0", 0);
2456   signal_monitor_assert_is_empty (fixture.monitor);
2457
2458   /* This should propagate row-changed */
2459   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
2460   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2461
2462   set_path_visibility (&fixture, "0", TRUE);
2463   /* check_filter_model (&fixture); */
2464   signal_monitor_assert_is_empty (fixture.monitor);
2465
2466   /* New root node, no child, so no signal */
2467   gtk_tree_store_append (fixture.store, &root, NULL);
2468   check_level_length (fixture.filter, NULL, 1);
2469   signal_monitor_assert_is_empty (fixture.monitor);
2470
2471   /* When the child comes in, this node will become visible */
2472   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
2473   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2474   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2475   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
2476   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2477
2478   gtk_tree_store_append (fixture.store, &iter, &root);
2479   check_level_length (fixture.filter, NULL, 2);
2480   check_level_length (fixture.filter, "1", 0);
2481
2482   create_tree_store_set_values (fixture.store, &root, TRUE);
2483   create_tree_store_set_values (fixture.store, &iter, TRUE);
2484
2485   /* check_filter_model (&fixture); */
2486   signal_monitor_assert_is_empty (fixture.monitor);
2487
2488   /* Add another child for 1 */
2489   gtk_tree_store_append (fixture.store, &iter, &root);
2490   create_tree_store_set_values (fixture.store, &iter, TRUE);
2491   check_level_length (fixture.filter, NULL, 2);
2492   check_level_length (fixture.filter, "0", 0);
2493   check_level_length (fixture.filter, "1", 0);
2494   signal_monitor_assert_is_empty (fixture.monitor);
2495
2496   /* Now remove one of the remaining child rows */
2497   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
2498
2499   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2500                                        &iter, "0:0");
2501   gtk_tree_store_remove (fixture.store, &iter);
2502
2503   check_level_length (fixture.filter, NULL, 1);
2504   check_level_length (fixture.filter, "0", 0);
2505
2506   set_path_visibility (&fixture, "0", FALSE);
2507   /* check_filter_model (&fixture); */
2508   signal_monitor_assert_is_empty (fixture.monitor);
2509 }
2510
2511
2512 static gboolean
2513 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
2514                                             GtkTreeIter  *iter,
2515                                             gpointer      data)
2516 {
2517   int depth;
2518   GtkTreePath *path;
2519
2520   path = gtk_tree_model_get_path (model, iter);
2521   depth = gtk_tree_path_get_depth (path);
2522   gtk_tree_path_free (path);
2523
2524   if (depth > 1)
2525     return TRUE;
2526   /* else */
2527   return gtk_tree_model_iter_has_child (model, iter);
2528 }
2529
2530 static void
2531 specific_root_has_child_filter (void)
2532 {
2533   GtkTreeModel *filter;
2534   GtkTreeIter iter, root;
2535   FilterTest fixture; /* This is not how it should be done ... */
2536   GtkWidget *tree_view;
2537
2538   /* This is a variation on the above test case, specific has-child-filter,
2539    * herein the has-child check for visibility only applies to root level
2540    * nodes.  In this test, children are always visible because we
2541    * only filter based on the "has child" criterion.
2542    */
2543
2544   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2545   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2546   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2547   fixture.monitor = signal_monitor_new (filter);
2548
2549   tree_view = gtk_tree_view_new_with_model (filter);
2550
2551   /* We will filter on parent state using a filter function.  We will
2552    * manually keep the boolean column in sync, so that we can use
2553    * check_filter_model() to check the consistency of the model.
2554    */
2555   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2556    * to be able to check the structure here.  We keep the calls to
2557    * check_filter_model() commented out until then.
2558    */
2559   gtk_tree_model_filter_set_visible_func (fixture.filter,
2560                                           specific_root_has_child_filter_filter_func,
2561                                           NULL, NULL);
2562
2563   /* Add a first node, this will be invisible initially, so no signal
2564    * should be emitted.
2565    */
2566   gtk_tree_store_append (fixture.store, &root, NULL);
2567   create_tree_store_set_values (fixture.store, &root, FALSE);
2568
2569   signal_monitor_assert_is_empty (fixture.monitor);
2570   /* check_filter_model (&fixture); */
2571   check_level_length (fixture.filter, NULL, 0);
2572
2573   /* Add a child node.  This will cause the parent to become visible,
2574    * so we expect row-inserted signals for both.
2575    */
2576   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
2577   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2578   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2579
2580   gtk_tree_store_append (fixture.store, &iter, &root);
2581   signal_monitor_assert_is_empty (fixture.monitor);
2582
2583   check_level_length (fixture.filter, NULL, 1);
2584   check_level_length (fixture.filter, "0", 1);
2585
2586   /* Modify the content of iter, yields row-changed signals */
2587   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0:0");
2588
2589   create_tree_store_set_values (fixture.store, &iter, TRUE);
2590   signal_monitor_assert_is_empty (fixture.monitor);
2591
2592   /* Parent must now be visible.  Do the level length check first,
2593    * to avoid modifying the child model triggering a row-changed to
2594    * the filter model.
2595    */
2596   check_level_length (fixture.filter, NULL, 1);
2597   check_level_length (fixture.filter, "0", 1);
2598
2599   /* Modify path 0 */
2600   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
2601   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2602
2603   set_path_visibility (&fixture, "0", TRUE);
2604   /* check_filter_model (&fixture); */
2605
2606   signal_monitor_assert_is_empty (fixture.monitor);
2607
2608   /* Insert another node in the root level.  Initially invisible, so
2609    * not expecting any signal.
2610    */
2611   gtk_tree_store_append (fixture.store, &root, NULL);
2612   check_level_length (fixture.filter, NULL, 1);
2613
2614   signal_monitor_assert_is_empty (fixture.monitor);
2615
2616   /* Adding a child node which also makes parent at path 1 visible. */
2617   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
2618   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2619   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2620
2621   gtk_tree_store_append (fixture.store, &iter, &root);
2622   check_level_length (fixture.filter, NULL, 2);
2623   check_level_length (fixture.filter, "1", 1);
2624
2625   signal_monitor_assert_is_empty (fixture.monitor);
2626
2627   /* Check if row-changed is propagated */
2628   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
2629   /* is row-has-child-toggled really necessary? */
2630   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2631   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1:0");
2632
2633   create_tree_store_set_values (fixture.store, &root, TRUE);
2634   create_tree_store_set_values (fixture.store, &iter, TRUE);
2635   /* check_filter_model (&fixture); */
2636   signal_monitor_assert_is_empty (fixture.monitor);
2637
2638   /* Insert another child under node 1 */
2639   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1:1");
2640   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1:1");
2641
2642   gtk_tree_store_append (fixture.store, &iter, &root);
2643   create_tree_store_set_values (fixture.store, &iter, TRUE);
2644   check_level_length (fixture.filter, NULL, 2);
2645   check_level_length (fixture.filter, "0", 1);
2646   check_level_length (fixture.filter, "1", 2);
2647   signal_monitor_assert_is_empty (fixture.monitor);
2648
2649   /* Set a child node to invisible.  This should not yield any
2650    * change, because filtering is only done on whether the root
2651    * node has a child, which it still has.
2652    */
2653   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0:0");
2654
2655   set_path_visibility (&fixture, "0:0", FALSE);
2656   signal_monitor_assert_is_empty (fixture.monitor);
2657
2658   /* Now remove one of the remaining child rows */
2659   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0:0");
2660   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2661   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
2662
2663   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2664                                        &iter, "0:0");
2665   gtk_tree_store_remove (fixture.store, &iter);
2666
2667   check_level_length (fixture.filter, NULL, 1);
2668   check_level_length (fixture.filter, "0", 2);
2669   signal_monitor_assert_is_empty (fixture.monitor);
2670
2671   /* Set visibility of 0 to FALSE, no-op for filter model since
2672    * the child 0:0 is already gone
2673    */
2674   set_path_visibility (&fixture, "0", FALSE);
2675   /* check_filter_model (&fixture); */
2676   signal_monitor_assert_is_empty (fixture.monitor);
2677 }
2678
2679
2680 static void
2681 specific_filter_add_child (void)
2682 {
2683   /* This test is based on one of the test cases I found in my
2684    * old test cases directory.  I unfortunately do not have a record
2685    * from who this test case originated.  -Kris.
2686    */
2687
2688   GtkTreeIter iter;
2689   GtkTreeIter iter_first;
2690   GtkTreeIter child;
2691   GtkTreeStore *store;
2692   GtkTreeModel *filter G_GNUC_UNUSED;
2693
2694   store = gtk_tree_store_new (1, G_TYPE_STRING);
2695
2696   gtk_tree_store_append (store, &iter_first, NULL);
2697   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
2698
2699   gtk_tree_store_append (store, &iter, NULL);
2700   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2701
2702   gtk_tree_store_append (store, &iter, NULL);
2703   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2704
2705   gtk_tree_store_append (store, &iter, NULL);
2706   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2707
2708   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2709
2710   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2711   gtk_tree_store_append (store, &child, &iter_first);
2712   gtk_tree_store_set (store, &child, 0, "Hello", -1);
2713 }
2714
2715 static void
2716 specific_list_store_clear (void)
2717 {
2718   GtkTreeIter iter;
2719   GtkListStore *list;
2720   GtkTreeModel *filter;
2721   GtkWidget *view G_GNUC_UNUSED;
2722
2723   list = gtk_list_store_new (1, G_TYPE_INT);
2724   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2725   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2726   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2727   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2728   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2729   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2730   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2731   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2732
2733   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2734   view = gtk_tree_view_new_with_model (filter);
2735
2736   gtk_list_store_clear (list);
2737 }
2738
2739 static void
2740 specific_sort_ref_leaf_and_remove_ancestor (void)
2741 {
2742   GtkTreeIter iter, child, child2, child3;
2743   GtkTreeStore *tree;
2744   GtkTreeModel *sort;
2745   GtkTreePath *path;
2746   GtkTreeRowReference *rowref;
2747   GtkWidget *view G_GNUC_UNUSED;
2748
2749   tree = gtk_tree_store_new (1, G_TYPE_INT);
2750   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2751   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2752   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2753   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2754
2755   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2756   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2757   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2758
2759   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2760   view = gtk_tree_view_new_with_model (sort);
2761   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2762
2763   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2764   rowref = gtk_tree_row_reference_new (sort, path);
2765   gtk_tree_path_free (path);
2766
2767   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2768   rowref = gtk_tree_row_reference_new (sort, path);
2769   gtk_tree_path_free (path);
2770
2771   path = gtk_tree_path_new_from_indices (3, 0, -1);
2772   rowref = gtk_tree_row_reference_new (sort, path);
2773   gtk_tree_path_free (path);
2774
2775   path = gtk_tree_path_new_from_indices (3, -1);
2776   rowref = gtk_tree_row_reference_new (sort, path);
2777   gtk_tree_path_free (path);
2778
2779   /* Deleting a parent */
2780   path = gtk_tree_path_new_from_indices (3, 0, -1);
2781   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2782   gtk_tree_store_remove (tree, &iter);
2783   gtk_tree_path_free (path);
2784
2785   gtk_tree_row_reference_free (rowref);
2786 }
2787
2788 static void
2789 specific_ref_leaf_and_remove_ancestor (void)
2790 {
2791   GtkTreeIter iter, child, child2, child3;
2792   GtkTreeStore *tree;
2793   GtkTreeModel *filter;
2794   GtkTreePath *path;
2795   GtkTreeRowReference *rowref;
2796   GtkWidget *view G_GNUC_UNUSED;
2797
2798   tree = gtk_tree_store_new (1, G_TYPE_INT);
2799   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2800   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2801   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2802   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2803
2804   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2805   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2806   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2807
2808   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
2809   view = gtk_tree_view_new_with_model (filter);
2810   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2811
2812   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2813   rowref = gtk_tree_row_reference_new (filter, path);
2814   gtk_tree_path_free (path);
2815
2816   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2817   rowref = gtk_tree_row_reference_new (filter, path);
2818   gtk_tree_path_free (path);
2819
2820   path = gtk_tree_path_new_from_indices (3, 0, -1);
2821   rowref = gtk_tree_row_reference_new (filter, path);
2822   gtk_tree_path_free (path);
2823
2824   path = gtk_tree_path_new_from_indices (3, -1);
2825   rowref = gtk_tree_row_reference_new (filter, path);
2826   gtk_tree_path_free (path);
2827
2828   /* Deleting a parent */
2829   path = gtk_tree_path_new_from_indices (3, 0, -1);
2830   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2831   gtk_tree_store_remove (tree, &iter);
2832   gtk_tree_path_free (path);
2833
2834   gtk_tree_row_reference_free (rowref);
2835 }
2836
2837 static void
2838 specific_virtual_ref_leaf_and_remove_ancestor (void)
2839 {
2840   GtkTreeIter iter, child, child2, child3;
2841   GtkTreeStore *tree;
2842   GtkTreeModel *filter;
2843   GtkTreePath *path;
2844   GtkTreeRowReference *rowref;
2845   GtkWidget *view G_GNUC_UNUSED;
2846
2847   tree = gtk_tree_store_new (1, G_TYPE_INT);
2848   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2849   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2850   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2851   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2852
2853   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2854   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2855   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2856
2857   /* Set a virtual root of 3:0 */
2858   path = gtk_tree_path_new_from_indices (3, 0, -1);
2859   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2860   gtk_tree_path_free (path);
2861
2862   view = gtk_tree_view_new_with_model (filter);
2863   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2864
2865   path = gtk_tree_path_new_from_indices (0, 0, -1);
2866   rowref = gtk_tree_row_reference_new (filter, path);
2867   gtk_tree_path_free (path);
2868
2869   path = gtk_tree_path_new_from_indices (0, 0, -1);
2870   rowref = gtk_tree_row_reference_new (filter, path);
2871   gtk_tree_path_free (path);
2872
2873   path = gtk_tree_path_new_from_indices (0, -1);
2874   rowref = gtk_tree_row_reference_new (filter, path);
2875   gtk_tree_path_free (path);
2876
2877   /* Deleting the virtual root */
2878   path = gtk_tree_path_new_from_indices (3, 0, -1);
2879   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2880   gtk_tree_store_remove (tree, &iter);
2881   gtk_tree_path_free (path);
2882
2883   gtk_tree_row_reference_free (rowref);
2884 }
2885
2886
2887 static int
2888 specific_bug_301558_sort_func (GtkTreeModel *model,
2889                                GtkTreeIter  *a,
2890                                GtkTreeIter  *b,
2891                                gpointer      data)
2892 {
2893   int i, j;
2894
2895   gtk_tree_model_get (model, a, 0, &i, -1);
2896   gtk_tree_model_get (model, b, 0, &j, -1);
2897
2898   return j - i;
2899 }
2900
2901 static void
2902 specific_bug_301558 (void)
2903 {
2904   /* Test case for GNOME Bugzilla bug 301558 provided by
2905    * Markku Vire.
2906    */
2907   GtkTreeStore *tree;
2908   GtkTreeModel *filter;
2909   GtkTreeModel *sort;
2910   GtkTreeIter root, iter, iter2;
2911   GtkWidget *view G_GNUC_UNUSED;
2912   int i;
2913   gboolean add;
2914
2915   g_test_bug ("301558");
2916
2917   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
2918   gtk_tree_store_append (tree, &iter, NULL);
2919   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
2920   gtk_tree_store_append (tree, &iter2, &iter);
2921   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
2922
2923   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2924   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2925                                            specific_bug_301558_sort_func,
2926                                            NULL, NULL);
2927
2928   filter = gtk_tree_model_filter_new (sort, NULL);
2929   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
2930
2931   view = gtk_tree_view_new_with_model (filter);
2932
2933   while (gtk_events_pending ())
2934     gtk_main_iteration ();
2935
2936   add = TRUE;
2937
2938   for (i = 0; i < 10; i++)
2939     {
2940       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
2941         g_assert_not_reached ();
2942
2943       if (add)
2944         {
2945           gtk_tree_store_append (tree, &iter, &root);
2946           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
2947         }
2948       else
2949         {
2950           int n;
2951           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
2952           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
2953                                          &root, n - 1);
2954           gtk_tree_store_remove (tree, &iter);
2955         }
2956
2957       add = !add;
2958     }
2959 }
2960
2961
2962 static gboolean
2963 specific_bug_311955_filter_func (GtkTreeModel *model,
2964                                  GtkTreeIter  *iter,
2965                                  gpointer      data)
2966 {
2967   int value;
2968
2969   gtk_tree_model_get (model, iter, 0, &value, -1);
2970
2971   return (value != 0);
2972 }
2973
2974 static void
2975 specific_bug_311955 (void)
2976 {
2977   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
2978    * by Markku Vire.
2979    */
2980   GtkTreeIter iter, child, root;
2981   GtkTreeStore *store;
2982   GtkTreeModel *sort;
2983   GtkTreeModel *filter;
2984
2985   GtkWidget *window G_GNUC_UNUSED;
2986   GtkWidget *tree_view;
2987   int i;
2988   int n;
2989
2990   g_test_bug ("311955");
2991
2992   store = gtk_tree_store_new (1, G_TYPE_INT);
2993
2994   gtk_tree_store_append (store, &root, NULL);
2995   gtk_tree_store_set (store, &root, 0, 33, -1);
2996
2997   gtk_tree_store_append (store, &iter, &root);
2998   gtk_tree_store_set (store, &iter, 0, 50, -1);
2999
3000   gtk_tree_store_append (store, &iter, NULL);
3001   gtk_tree_store_set (store, &iter, 0, 22, -1);
3002
3003   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3004   filter = gtk_tree_model_filter_new (sort, NULL);
3005
3006   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3007                                           specific_bug_311955_filter_func,
3008                                           NULL, NULL);
3009
3010   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3011   tree_view = gtk_tree_view_new_with_model (filter);
3012   g_object_unref (store);
3013
3014   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3015
3016   while (gtk_events_pending ())
3017     gtk_main_iteration ();
3018
3019   /* Fill model */
3020   for (i = 0; i < 4; i++)
3021     {
3022       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
3023
3024       gtk_tree_store_append (store, &iter, &root);
3025
3026       if (i < 3)
3027         gtk_tree_store_set (store, &iter, 0, i, -1);
3028
3029       if (i % 2 == 0)
3030         {
3031           gtk_tree_store_append (store, &child, &iter);
3032           gtk_tree_store_set (store, &child, 0, 10, -1);
3033         }
3034     }
3035
3036   while (gtk_events_pending ())
3037     gtk_main_iteration ();
3038
3039   /* Remove bottommost child from the tree. */
3040   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
3041   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
3042
3043   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
3044     {
3045       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
3046         gtk_tree_store_remove (store, &child);
3047     }
3048   else
3049     g_assert_not_reached ();
3050 }
3051
3052 static void
3053 specific_bug_346800 (void)
3054 {
3055   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
3056    * by Jonathan Matthew.
3057    */
3058
3059   GtkTreeIter node_iters[50];
3060   GtkTreeIter child_iters[50];
3061   GtkTreeModel *model;
3062   GtkTreeModelFilter *filter;
3063   GtkTreeStore *store;
3064   GType *columns;
3065   int i;
3066   int items = 50;
3067   columns = g_new (GType, 2);
3068   columns[0] = G_TYPE_STRING;
3069   columns[1] = G_TYPE_BOOLEAN;
3070   store = gtk_tree_store_newv (2, columns);
3071   model = GTK_TREE_MODEL (store);
3072
3073   g_test_bug ("346800");
3074
3075   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
3076   gtk_tree_model_filter_set_visible_column (filter, 1);
3077
3078   for (i=0; i<items; i++)
3079     {
3080       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
3081
3082       g_malloc (138);
3083       gtk_tree_store_append (store, &node_iters[i], NULL);
3084       gtk_tree_store_set (store, &node_iters[i],
3085                           0, "something",
3086                           1, ((i%6) == 0) ? FALSE : TRUE,
3087                           -1);
3088
3089       g_malloc (47);
3090       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
3091       gtk_tree_store_set (store, &child_iters[i],
3092                           0, "something else",
3093                           1, FALSE,
3094                           -1);
3095       gtk_tree_model_filter_refilter (filter);
3096
3097       if (i > 6)
3098         {
3099           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
3100                               (i & 1) ? TRUE : FALSE, -1);
3101           gtk_tree_model_filter_refilter (filter);
3102
3103           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
3104                               (i & 1) ? FALSE: TRUE, -1);
3105           gtk_tree_model_filter_refilter (filter);
3106         }
3107     }
3108 }
3109
3110 static gboolean
3111 specific_bug_464173_visible_func (GtkTreeModel *model,
3112                                   GtkTreeIter  *iter,
3113                                   gpointer      data)
3114 {
3115   gboolean *visible = (gboolean *)data;
3116
3117   return *visible;
3118 }
3119
3120 static void
3121 specific_bug_464173 (void)
3122 {
3123   /* Test case for GNOME Bugzilla bug 464173, test case written
3124    * by Andreas Koehler.
3125    */
3126   GtkTreeStore *model;
3127   GtkTreeModelFilter *f_model;
3128   GtkTreeIter iter1, iter2;
3129   GtkWidget *view G_GNUC_UNUSED;
3130   gboolean visible = TRUE;
3131
3132   g_test_bug ("464173");
3133
3134   model = gtk_tree_store_new (1, G_TYPE_STRING);
3135   gtk_tree_store_append (model, &iter1, NULL);
3136   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
3137   gtk_tree_store_append (model, &iter2, &iter1);
3138   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
3139
3140   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
3141   gtk_tree_model_filter_set_visible_func (f_model,
3142                                           specific_bug_464173_visible_func,
3143                                           &visible, NULL);
3144
3145   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
3146
3147   visible = FALSE;
3148   gtk_tree_model_filter_refilter (f_model);
3149 }
3150
3151
3152 static gboolean
3153 specific_bug_540201_filter_func (GtkTreeModel *model,
3154                                  GtkTreeIter  *iter,
3155                                  gpointer      data)
3156 {
3157   gboolean has_children;
3158
3159   has_children = gtk_tree_model_iter_has_child (model, iter);
3160
3161   return has_children;
3162 }
3163
3164 static void
3165 specific_bug_540201 (void)
3166 {
3167   /* Test case for GNOME Bugzilla bug 540201, steps provided by
3168    * Charles Day.
3169    */
3170   GtkTreeIter iter, root;
3171   GtkTreeStore *store;
3172   GtkTreeModel *filter;
3173
3174   GtkWidget *tree_view G_GNUC_UNUSED;
3175
3176   g_test_bug ("540201");
3177
3178   store = gtk_tree_store_new (1, G_TYPE_INT);
3179
3180   gtk_tree_store_append (store, &root, NULL);
3181   gtk_tree_store_set (store, &root, 0, 33, -1);
3182
3183   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3184   tree_view = gtk_tree_view_new_with_model (filter);
3185
3186   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3187                                           specific_bug_540201_filter_func,
3188                                           NULL, NULL);
3189
3190   gtk_tree_store_append (store, &iter, &root);
3191   gtk_tree_store_set (store, &iter, 0, 50, -1);
3192
3193   gtk_tree_store_append (store, &iter, &root);
3194   gtk_tree_store_set (store, &iter, 0, 22, -1);
3195
3196
3197   gtk_tree_store_append (store, &root, NULL);
3198   gtk_tree_store_set (store, &root, 0, 33, -1);
3199
3200   gtk_tree_store_append (store, &iter, &root);
3201   gtk_tree_store_set (store, &iter, 0, 22, -1);
3202 }
3203
3204
3205 static gboolean
3206 specific_bug_549287_visible_func (GtkTreeModel *model,
3207                                   GtkTreeIter  *iter,
3208                                   gpointer      data)
3209 {
3210   gboolean result = FALSE;
3211
3212   result = gtk_tree_model_iter_has_child (model, iter);
3213
3214   return result;
3215 }
3216
3217 static void
3218 specific_bug_549287 (void)
3219 {
3220   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
3221
3222   int i;
3223   GtkTreeStore *store;
3224   GtkTreeModel *filtered;
3225   GtkWidget *view G_GNUC_UNUSED;
3226   GtkTreeIter iter;
3227   GtkTreeIter *swap, *parent, *child;
3228
3229   g_test_bug ("529287");
3230
3231   store = gtk_tree_store_new (1, G_TYPE_STRING);
3232   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3233   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
3234                                           specific_bug_549287_visible_func,
3235                                           NULL, NULL);
3236
3237   view = gtk_tree_view_new_with_model (filtered);
3238
3239   for (i = 0; i < 4; i++)
3240     {
3241       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
3242         {
3243           parent = gtk_tree_iter_copy (&iter);
3244           child = gtk_tree_iter_copy (&iter);
3245
3246           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
3247                                                 child, parent, 0))
3248             {
3249
3250               swap = parent;
3251               parent = child;
3252               child = swap;
3253             }
3254
3255           gtk_tree_store_append (store, child, parent);
3256           gtk_tree_store_set (store, child,
3257                               0, "Something",
3258                               -1);
3259
3260           gtk_tree_iter_free (parent);
3261           gtk_tree_iter_free (child);
3262         }
3263       else
3264         {
3265           gtk_tree_store_append (store, &iter, NULL);
3266           gtk_tree_store_set (store, &iter,
3267                               0, "Something",
3268                               -1);
3269         }
3270
3271       /* since we inserted something, we changed the visibility conditions: */
3272       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
3273     }
3274 }
3275
3276 static gboolean
3277 specific_bug_621076_visible_func (GtkTreeModel *model,
3278                                   GtkTreeIter  *iter,
3279                                   gpointer      data)
3280 {
3281   gboolean visible = FALSE;
3282   gchar *str = NULL;
3283
3284   gtk_tree_model_get (model, iter, 0, &str, -1);
3285   if (str != NULL && g_str_has_prefix (str, "visible"))
3286     {
3287       visible = TRUE;
3288     }
3289   else
3290     {
3291       GtkTreeIter child_iter;
3292       gboolean valid;
3293
3294       /* Recursively check if we have a visible child */
3295       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
3296            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
3297         {
3298           if (specific_bug_621076_visible_func (model, &child_iter, data))
3299             {
3300               visible = TRUE;
3301               break;
3302             }
3303         }
3304     }
3305
3306   if (str)
3307     g_free (str);
3308
3309   return visible;
3310 }
3311
3312 static void
3313 specific_bug_621076 (void)
3314 {
3315   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
3316
3317   /* This test case differs from has-child-filter and root-has-child-filter
3318    * in that the visible function both filters on content and model
3319    * structure.  Also, it is recursive.
3320    */
3321
3322   GtkTreeStore *store;
3323   GtkTreeModel *filter;
3324   GtkWidget *view;
3325   GtkTreeIter group_iter;
3326   GtkTreeIter item_iter;
3327   SignalMonitor *monitor;
3328
3329   g_test_bug ("621076");
3330
3331   store = gtk_tree_store_new (1, G_TYPE_STRING);
3332   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3333   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3334                                           specific_bug_621076_visible_func,
3335                                           NULL, NULL);
3336
3337   view = gtk_tree_view_new_with_model (filter);
3338   g_object_ref_sink (view);
3339
3340   monitor = signal_monitor_new (filter);
3341
3342   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
3343   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
3344                                      0, "visible-group-0",
3345                                      -1);
3346   signal_monitor_assert_is_empty (monitor);
3347
3348   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
3349    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
3350    * visible-group-0 to tell the view that row can be expanded. */
3351   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
3352   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
3353   group_iter = item_iter;
3354   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
3355                                      0, "visible-0:0",
3356                                      -1);
3357   signal_monitor_assert_is_empty (monitor);
3358
3359   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
3360   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
3361                                      0, "visible-group-1",
3362                                      -1);
3363   signal_monitor_assert_is_empty (monitor);
3364
3365   /* We are adding an hidden item inside visible-group-1, so
3366    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
3367    * because the signal originating at TreeStore will be propagated,
3368    * as well a generated signal because the state of the parent *could*
3369    * change by a change in the model.
3370    */
3371   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
3372   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
3373   group_iter = item_iter;
3374   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
3375                                      0, "group-1:0",
3376                                      -1);
3377   signal_monitor_assert_is_empty (monitor);
3378
3379   /* This group is invisible and its parent too. Nothing should be emitted */
3380   group_iter = item_iter;
3381   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
3382                                      0, "group-1:0:0",
3383                                      -1);
3384   signal_monitor_assert_is_empty (monitor);
3385
3386   /* Adding a visible item in this group hierarchy will make all nodes
3387    * in this path visible.  The first level should simply tell the view
3388    * that it now has a child, and the view will load the tree if needed
3389    * (depends on the expanded state).
3390    */
3391   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
3392   group_iter = item_iter;
3393   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
3394                                      0, "visible-1:0:0:0",
3395                                      -1);
3396   signal_monitor_assert_is_empty (monitor);
3397
3398   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
3399
3400   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
3401                                      0, "group-2",
3402                                      -1);
3403   signal_monitor_assert_is_empty (monitor);
3404
3405   /* Parent is invisible, and adding this invisible item won't change that,
3406    * so no signal should be emitted. */
3407   group_iter = item_iter;
3408   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
3409                                      0, "invisible-2:0",
3410                                      -1);
3411   signal_monitor_assert_is_empty (monitor);
3412
3413   /* This makes group-2 visible, so it gets inserted and tells it has
3414    * children.
3415    */
3416   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
3417   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
3418   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
3419                                      0, "visible-2:1",
3420                                      -1);
3421   signal_monitor_assert_is_empty (monitor);
3422
3423   /* group-2 is already visible, so this time it is a normal insertion */
3424   signal_monitor_append_signal (monitor, ROW_INSERTED, "2:1");
3425   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
3426                                      0, "visible-2:2",
3427                                      -1);
3428   signal_monitor_assert_is_empty (monitor);
3429
3430
3431   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
3432                                      0, "group-3",
3433                                      -1);
3434   signal_monitor_assert_is_empty (monitor);
3435
3436   /* Parent is invisible, and adding this invisible item won't change that,
3437    * so no signal should be emitted. */
3438   group_iter = item_iter;
3439   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
3440                                      0, "invisible-3:0",
3441                                      -1);
3442   signal_monitor_assert_is_empty (monitor);
3443
3444   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
3445                                      0, "invisible-3:1",
3446                                      -1);
3447   signal_monitor_assert_is_empty (monitor);
3448
3449   /* This will make group 3 visible. */
3450   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
3451   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
3452   signal_monitor_append_signal (monitor, ROW_INSERTED, "3:0");
3453   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
3454   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
3455   signal_monitor_assert_is_empty (monitor);
3456
3457   /* Make sure all groups are expanded, so the filter has the tree cached */
3458   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
3459   while (gtk_events_pending ())
3460     gtk_main_iteration ();
3461
3462   /* Should only yield a row-changed */
3463   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
3464   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
3465   signal_monitor_assert_is_empty (monitor);
3466
3467   /* Now remove/hide some items. If a group loses its last item, the group
3468    * should be deleted instead of the item.
3469    */
3470
3471   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
3472   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
3473   gtk_tree_store_remove (store, &item_iter);
3474   signal_monitor_assert_is_empty (monitor);
3475
3476   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
3477   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
3478   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
3479   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
3480   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
3481   signal_monitor_assert_is_empty (monitor);
3482
3483   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
3484   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
3485   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
3486   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
3487   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
3488   gtk_tree_store_remove (store, &item_iter);
3489   signal_monitor_assert_is_empty (monitor);
3490
3491   /* Hide a group using row-changed instead of row-deleted */
3492   /* Caution: group 2 is gone, so offsets of the signals have moved. */
3493   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
3494   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
3495   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
3496   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
3497                                        "3:1");
3498   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
3499   signal_monitor_assert_is_empty (monitor);
3500
3501 #if 0
3502   {
3503     GtkWidget *window;
3504     GtkTreeViewColumn *col;
3505
3506     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
3507
3508     col = gtk_tree_view_column_new_with_attributes ("foo",
3509         gtk_cell_renderer_text_new (),
3510         "text", 0, NULL);
3511     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
3512
3513     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3514     g_signal_connect (window, "delete-event",
3515         G_CALLBACK (gtk_widget_destroy), NULL);
3516     g_signal_connect (window, "destroy",
3517         G_CALLBACK (gtk_main_quit), NULL);
3518
3519     gtk_container_add (GTK_CONTAINER (window), view);
3520
3521     gtk_widget_show (view);
3522     gtk_widget_show (window);
3523
3524     gtk_main ();
3525   }
3526 #endif
3527
3528   /* Cleanup */
3529   signal_monitor_free (monitor);
3530   g_object_unref (view);
3531   g_object_unref (store);
3532   g_object_unref (filter);
3533 }
3534
3535 /* main */
3536
3537 void
3538 register_filter_model_tests (void)
3539 {
3540   g_test_add ("/TreeModelFilter/self/verify-test-suite",
3541               FilterTest, NULL,
3542               filter_test_setup,
3543               verify_test_suite,
3544               filter_test_teardown);
3545
3546   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
3547               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3548               filter_test_setup,
3549               verify_test_suite_vroot,
3550               filter_test_teardown);
3551   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
3552               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
3553               filter_test_setup,
3554               verify_test_suite_vroot,
3555               filter_test_teardown);
3556
3557
3558   g_test_add ("/TreeModelFilter/filled/hide-root-level",
3559               FilterTest, NULL,
3560               filter_test_setup,
3561               filled_hide_root_level,
3562               filter_test_teardown);
3563   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
3564               FilterTest, NULL,
3565               filter_test_setup,
3566               filled_hide_child_levels,
3567               filter_test_teardown);
3568
3569   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
3570               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3571               filter_test_setup,
3572               filled_vroot_hide_root_level,
3573               filter_test_teardown);
3574   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
3575               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3576               filter_test_setup,
3577               filled_vroot_hide_child_levels,
3578               filter_test_teardown);
3579
3580
3581   g_test_add ("/TreeModelFilter/empty/show-nodes",
3582               FilterTest, NULL,
3583               filter_test_setup_empty,
3584               empty_show_nodes,
3585               filter_test_teardown);
3586   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
3587               FilterTest, NULL,
3588               filter_test_setup_empty,
3589               empty_show_multiple_nodes,
3590               filter_test_teardown);
3591
3592   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
3593               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3594               filter_test_setup_empty,
3595               empty_vroot_show_nodes,
3596               filter_test_teardown);
3597   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
3598               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3599               filter_test_setup_empty,
3600               empty_vroot_show_multiple_nodes,
3601               filter_test_teardown);
3602
3603
3604   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
3605               FilterTest, NULL,
3606               filter_test_setup_unfiltered,
3607               unfiltered_hide_single,
3608               filter_test_teardown);
3609   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
3610               FilterTest, NULL,
3611               filter_test_setup_unfiltered,
3612               unfiltered_hide_single_child,
3613               filter_test_teardown);
3614   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
3615               FilterTest, NULL,
3616               filter_test_setup_unfiltered,
3617               unfiltered_hide_single_multi_level,
3618               filter_test_teardown);
3619
3620   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
3621               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3622               filter_test_setup_unfiltered,
3623               unfiltered_vroot_hide_single,
3624               filter_test_teardown);
3625   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
3626               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3627               filter_test_setup_unfiltered,
3628               unfiltered_vroot_hide_single_child,
3629               filter_test_teardown);
3630   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
3631               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3632               filter_test_setup_unfiltered,
3633               unfiltered_vroot_hide_single_multi_level,
3634               filter_test_teardown);
3635
3636
3637
3638   g_test_add ("/TreeModelFilter/unfiltered/show-single",
3639               FilterTest, NULL,
3640               filter_test_setup_empty_unfiltered,
3641               unfiltered_show_single,
3642               filter_test_teardown);
3643   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
3644               FilterTest, NULL,
3645               filter_test_setup_empty_unfiltered,
3646               unfiltered_show_single_child,
3647               filter_test_teardown);
3648   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
3649               FilterTest, NULL,
3650               filter_test_setup_empty_unfiltered,
3651               unfiltered_show_single_multi_level,
3652               filter_test_teardown);
3653
3654   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
3655               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3656               filter_test_setup_empty_unfiltered,
3657               unfiltered_vroot_show_single,
3658               filter_test_teardown);
3659   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
3660               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3661               filter_test_setup_empty_unfiltered,
3662               unfiltered_vroot_show_single_child,
3663               filter_test_teardown);
3664   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
3665               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3666               filter_test_setup_empty_unfiltered,
3667               unfiltered_vroot_show_single_multi_level,
3668               filter_test_teardown);
3669
3670   /* Inserts in child models after creation of filter model */
3671   g_test_add_func ("/TreeModelFilter/insert/before",
3672                    insert_before);
3673   g_test_add_func ("/TreeModelFilter/insert/child",
3674                    insert_child);
3675
3676   /* Removals from child model after creating of filter model */
3677   g_test_add_func ("/TreeModelFilter/remove/node",
3678                    remove_node);
3679   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
3680                    remove_node_vroot);
3681   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
3682                    remove_vroot_ancestor);
3683
3684
3685   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
3686                    specific_path_dependent_filter);
3687   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
3688                    specific_append_after_collapse);
3689   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
3690                    specific_sort_filter_remove_node);
3691   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
3692                    specific_sort_filter_remove_root);
3693   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
3694                    specific_root_mixed_visibility);
3695   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
3696                    specific_has_child_filter);
3697   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
3698                    specific_root_has_child_filter);
3699   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
3700                    specific_filter_add_child);
3701   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
3702                    specific_list_store_clear);
3703   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
3704                    specific_sort_ref_leaf_and_remove_ancestor);
3705   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
3706                    specific_ref_leaf_and_remove_ancestor);
3707   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
3708                    specific_virtual_ref_leaf_and_remove_ancestor);
3709
3710   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
3711                    specific_bug_301558);
3712   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
3713                    specific_bug_311955);
3714   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
3715                    specific_bug_346800);
3716   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
3717                    specific_bug_464173);
3718   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
3719                    specific_bug_540201);
3720   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
3721                    specific_bug_549287);
3722   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
3723                    specific_bug_621076);
3724 }