]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Corrections to has-child filter 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   g_object_unref (fixture->filter);
671   g_object_unref (fixture->store);
672 }
673
674 /*
675  * Model structure validation
676  */
677
678 static void
679 check_filter_model_recurse (FilterTest  *fixture,
680                             GtkTreePath *store_parent_path,
681                             GtkTreePath *filter_parent_path)
682 {
683   int i;
684   GtkTreeIter store_iter;
685   GtkTreeIter filter_iter;
686   gboolean store_has_next, filter_has_next;
687
688   gtk_tree_path_down (store_parent_path);
689   gtk_tree_path_down (filter_parent_path);
690
691   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
692                                             &store_iter, store_parent_path);
693   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
694                                              &filter_iter, filter_parent_path);
695
696   for (i = 0; i < LEVEL_LENGTH; i++)
697     {
698       gboolean visible;
699
700       g_return_if_fail (store_has_next == TRUE);
701
702       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
703                           &store_iter,
704                           1, &visible,
705                           -1);
706
707       if (visible)
708         {
709           GtkTreePath *tmp;
710           gchar *filter_str, *store_str;
711
712           g_return_if_fail (filter_has_next == TRUE);
713
714           /* Verify path */
715           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
716                                          &filter_iter);
717           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
718
719           /* Verify model content */
720           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
721                               &store_iter,
722                               0, &store_str,
723                               -1);
724           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
725                               &filter_iter,
726                               0, &filter_str,
727                               -1);
728
729           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
730
731           g_free (store_str);
732           g_free (filter_str);
733
734           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
735                                              &filter_iter))
736             {
737               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
738
739               check_filter_model_recurse (fixture,
740                                           gtk_tree_path_copy (store_parent_path),
741                                           tmp);
742             }
743
744           gtk_tree_path_next (filter_parent_path);
745           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
746         }
747
748       gtk_tree_path_next (store_parent_path);
749       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
750     }
751
752   /* Both models should have no more content! */
753   g_return_if_fail (store_has_next == FALSE);
754   g_return_if_fail (filter_has_next == FALSE);
755
756   gtk_tree_path_free (store_parent_path);
757   gtk_tree_path_free (filter_parent_path);
758 }
759
760 static void
761 check_filter_model (FilterTest *fixture)
762 {
763   GtkTreePath *path;
764
765   if (fixture->monitor)
766     signal_monitor_assert_is_empty (fixture->monitor);
767
768   path = gtk_tree_path_new ();
769
770   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
771 }
772
773 static void
774 check_filter_model_with_root (FilterTest  *fixture,
775                               GtkTreePath *path)
776 {
777   if (fixture->monitor)
778     signal_monitor_assert_is_empty (fixture->monitor);
779
780   check_filter_model_recurse (fixture,
781                               gtk_tree_path_copy (path),
782                               gtk_tree_path_new ());
783 }
784
785 /* Helpers */
786
787 static void
788 check_level_length (GtkTreeModelFilter *filter,
789                     const gchar        *level,
790                     const int           expected_length)
791 {
792   if (!level)
793     {
794       int model_length;
795
796       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
797       g_assert_cmpint (model_length, ==, expected_length);
798     }
799   else
800     {
801       int model_length;
802       gboolean retrieved_iter = FALSE;
803       GtkTreeIter iter;
804
805       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
806                                                             &iter, level);
807       g_return_if_fail (retrieved_iter);
808       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
809       g_assert_cmpint (model_length, ==, expected_length);
810     }
811 }
812
813 static void
814 set_path_visibility (FilterTest  *fixture,
815                      const gchar *path,
816                      gboolean     visible)
817 {
818   GtkTreeIter store_iter;
819
820   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
821                                        &store_iter, path);
822   gtk_tree_store_set (fixture->store, &store_iter,
823                       1, visible,
824                       -1);
825 }
826
827 #if 0
828 static void
829 insert_path_with_visibility (FilterTest  *fixture,
830                              const gchar *path_string,
831                              gboolean     visible)
832 {
833   int position;
834   GtkTreePath *path;
835   GtkTreeIter parent, iter;
836
837   path = gtk_tree_path_new_from_string (path_string);
838   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
839   gtk_tree_path_up (path);
840
841   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
842     {
843       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
844       create_tree_store_set_values (fixture->store, &iter, visible);
845     }
846   gtk_tree_path_free (path);
847 }
848 #endif
849
850 /*
851  * The actual tests.
852  */
853
854 static void
855 verify_test_suite (FilterTest    *fixture,
856                    gconstpointer  user_data)
857 {
858   check_filter_model (fixture);
859 }
860
861 static void
862 verify_test_suite_vroot (FilterTest    *fixture,
863                          gconstpointer  user_data)
864 {
865   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
866 }
867
868
869 static void
870 filled_hide_root_level (FilterTest    *fixture,
871                         gconstpointer  user_data)
872 {
873   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
874   set_path_visibility (fixture, "2", FALSE);
875   check_filter_model (fixture);
876   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
877
878   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
879   set_path_visibility (fixture, "0", FALSE);
880   check_filter_model (fixture);
881   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
882
883   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
884   set_path_visibility (fixture, "4", FALSE);
885   check_filter_model (fixture);
886   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
887
888
889   /* Hide remaining */
890   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
891   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
892
893   set_path_visibility (fixture, "1", FALSE);
894   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
895
896   set_path_visibility (fixture, "3", FALSE);
897   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
898
899   check_filter_model (fixture);
900
901   /* Show some */
902   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
903   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
904   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
905   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
906
907   set_path_visibility (fixture, "1", TRUE);
908   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
909
910   set_path_visibility (fixture, "3", TRUE);
911   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
912
913   check_filter_model (fixture);
914 }
915
916 static void
917 filled_hide_child_levels (FilterTest    *fixture,
918                           gconstpointer  user_data)
919 {
920   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
921   set_path_visibility (fixture, "0:2", FALSE);
922   check_filter_model (fixture);
923   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
924   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
925
926   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
927   set_path_visibility (fixture, "0:4", FALSE);
928   check_filter_model (fixture);
929   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
930   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
931
932   set_path_visibility (fixture, "0:4:3", 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:0", FALSE);
938   set_path_visibility (fixture, "0:4:1", FALSE);
939   set_path_visibility (fixture, "0:4:2", FALSE);
940   set_path_visibility (fixture, "0:4:4", FALSE);
941   check_filter_model (fixture);
942   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
943   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
944
945   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
946   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
947   /* FIXME: Actually, the filter model should not be emitted the
948    * row-has-child-toggled signal here.  *However* an extraneous emission
949    * of this signal does not hurt and is allowed.
950    */
951   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
952   set_path_visibility (fixture, "0:4", TRUE);
953   check_filter_model (fixture);
954   check_level_length (fixture->filter, "0:3", 0);
955
956   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
957   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
958   set_path_visibility (fixture, "0:2", TRUE);
959   check_filter_model (fixture);
960   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
961   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
962   check_level_length (fixture->filter, "0:4", 0);
963
964   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
965   /* Once 0:4:0 got inserted, 0:4 became a parent */
966   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
967   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
968   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
969   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
970
971   set_path_visibility (fixture, "0:4:2", TRUE);
972   set_path_visibility (fixture, "0:4:4", TRUE);
973   signal_monitor_assert_is_empty (fixture->monitor);
974   check_level_length (fixture->filter, "0:4", 2);
975 }
976
977
978 static void
979 filled_vroot_hide_root_level (FilterTest    *fixture,
980                               gconstpointer  user_data)
981 {
982   GtkTreePath *path = (GtkTreePath *)user_data;
983
984   /* These changes do not affect the filter's root level */
985   set_path_visibility (fixture, "0", FALSE);
986   check_filter_model_with_root (fixture, path);
987   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
988   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
989
990   set_path_visibility (fixture, "4", 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   /* Even though we set the virtual root parent node to FALSE,
996    * the virtual root contents remain.
997    */
998   set_path_visibility (fixture, "2", FALSE);
999   check_filter_model_with_root (fixture, path);
1000   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1001   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1002
1003   /* No change */
1004   set_path_visibility (fixture, "1", FALSE);
1005   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1006   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1007
1008   set_path_visibility (fixture, "3", FALSE);
1009   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1010   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1011
1012   check_filter_model_with_root (fixture, path);
1013
1014   /* Show some */
1015   set_path_visibility (fixture, "2", TRUE);
1016   check_filter_model_with_root (fixture, path);
1017   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1018   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1019
1020   set_path_visibility (fixture, "1", TRUE);
1021   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1022   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1023
1024   set_path_visibility (fixture, "3", TRUE);
1025   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1026   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1027
1028   check_filter_model_with_root (fixture, path);
1029
1030   /* Now test changes in the virtual root level */
1031   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1032   set_path_visibility (fixture, "2:2", FALSE);
1033   check_filter_model_with_root (fixture, path);
1034   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1035
1036   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
1037   set_path_visibility (fixture, "2:4", FALSE);
1038   check_filter_model_with_root (fixture, path);
1039   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1040
1041   set_path_visibility (fixture, "1:4", FALSE);
1042   check_filter_model_with_root (fixture, path);
1043   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1044
1045   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
1046   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
1047   set_path_visibility (fixture, "2:4", TRUE);
1048   check_filter_model_with_root (fixture, path);
1049   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1050
1051   set_path_visibility (fixture, "2", FALSE);
1052   check_filter_model_with_root (fixture, path);
1053   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1054
1055   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1056   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1057   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1058   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1059   set_path_visibility (fixture, "2:0", FALSE);
1060   set_path_visibility (fixture, "2:1", FALSE);
1061   set_path_visibility (fixture, "2:2", FALSE);
1062   set_path_visibility (fixture, "2:3", FALSE);
1063   set_path_visibility (fixture, "2:4", FALSE);
1064   check_filter_model_with_root (fixture, path);
1065   check_level_length (fixture->filter, NULL, 0);
1066
1067   set_path_visibility (fixture, "2", TRUE);
1068   check_filter_model_with_root (fixture, path);
1069   check_level_length (fixture->filter, NULL, 0);
1070
1071   set_path_visibility (fixture, "1:4", FALSE);
1072   check_filter_model_with_root (fixture, path);
1073   check_level_length (fixture->filter, NULL, 0);
1074
1075   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1076   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1077   set_path_visibility (fixture, "2:4", TRUE);
1078   check_filter_model_with_root (fixture, path);
1079   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1080
1081   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1082   set_path_visibility (fixture, "2:4", FALSE);
1083   check_filter_model_with_root (fixture, path);
1084   check_level_length (fixture->filter, NULL, 0);
1085
1086   set_path_visibility (fixture, "2", FALSE);
1087   check_filter_model_with_root (fixture, path);
1088   check_level_length (fixture->filter, NULL, 0);
1089
1090   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1091   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1092   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1093   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1094   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
1095   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1096   set_path_visibility (fixture, "2:0", TRUE);
1097   set_path_visibility (fixture, "2:1", TRUE);
1098   set_path_visibility (fixture, "2:2", TRUE);
1099   check_filter_model_with_root (fixture, path);
1100   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1101
1102   set_path_visibility (fixture, "2", TRUE);
1103   check_filter_model_with_root (fixture, path);
1104   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1105 }
1106
1107 static void
1108 filled_vroot_hide_child_levels (FilterTest    *fixture,
1109                                 gconstpointer  user_data)
1110 {
1111   GtkTreePath *path = (GtkTreePath *)user_data;
1112
1113   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1114   set_path_visibility (fixture, "2:0:2", FALSE);
1115   check_filter_model_with_root (fixture, path);
1116   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1117   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1118
1119   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1120   set_path_visibility (fixture, "2:0:4", FALSE);
1121   check_filter_model_with_root (fixture, path);
1122   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1123   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1124
1125   set_path_visibility (fixture, "2:0:4:3", 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:0", FALSE);
1131   set_path_visibility (fixture, "2:0:4:1", FALSE);
1132   set_path_visibility (fixture, "2:0:4:2", FALSE);
1133   set_path_visibility (fixture, "2:0:4:4", FALSE);
1134   check_filter_model_with_root (fixture, path);
1135   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1136   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1137
1138   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1139   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1140   /* FIXME: Actually, the filter model should not be emitted the
1141    * row-has-child-toggled signal here.  *However* an extraneous emission
1142    * of this signal does not hurt and is allowed.
1143    */
1144   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1145   set_path_visibility (fixture, "2:0:4", TRUE);
1146   check_filter_model_with_root (fixture, path);
1147   check_level_length (fixture->filter, "0:3", 0);
1148
1149   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1150   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1151   set_path_visibility (fixture, "2:0:2", TRUE);
1152   check_filter_model_with_root (fixture, path);
1153   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1154   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1155   check_level_length (fixture->filter, "0:4", 0);
1156
1157   /* FIXME: Inconsistency!  For the non-vroot case we also receive two
1158    * row-has-child-toggled signals here.
1159    */
1160   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
1161   /* Once 0:4:0 got inserted, 0:4 became a parent */
1162   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1163   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
1164   set_path_visibility (fixture, "2:0:4:2", TRUE);
1165   set_path_visibility (fixture, "2:0:4:4", TRUE);
1166   check_level_length (fixture->filter, "0:4", 2);
1167 }
1168
1169
1170 static void
1171 empty_show_nodes (FilterTest    *fixture,
1172                   gconstpointer  user_data)
1173 {
1174   check_filter_model (fixture);
1175   check_level_length (fixture->filter, NULL, 0);
1176
1177   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1178   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1179   set_path_visibility (fixture, "3", TRUE);
1180   check_filter_model (fixture);
1181   check_level_length (fixture->filter, NULL, 1);
1182   check_level_length (fixture->filter, "0", 0);
1183
1184   set_path_visibility (fixture, "3:2:2", TRUE);
1185   check_filter_model (fixture);
1186   check_level_length (fixture->filter, NULL, 1);
1187   check_level_length (fixture->filter, "0", 0);
1188
1189   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1190   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1191   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1192   set_path_visibility (fixture, "3:2", TRUE);
1193   check_filter_model (fixture);
1194   check_level_length (fixture->filter, NULL, 1);
1195   check_level_length (fixture->filter, "0", 1);
1196   check_level_length (fixture->filter, "0:0", 1);
1197   check_level_length (fixture->filter, "0:0:0", 0);
1198
1199   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1200   set_path_visibility (fixture, "3", FALSE);
1201   check_filter_model (fixture);
1202   check_level_length (fixture->filter, NULL, 0);
1203
1204   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1205   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1206   set_path_visibility (fixture, "3:2:1", TRUE);
1207   set_path_visibility (fixture, "3", TRUE);
1208   check_filter_model (fixture);
1209   check_level_length (fixture->filter, NULL, 1);
1210   check_level_length (fixture->filter, "0", 1);
1211   check_level_length (fixture->filter, "0:0", 2);
1212   check_level_length (fixture->filter, "0:0:0", 0);
1213 }
1214
1215 static void
1216 empty_show_multiple_nodes (FilterTest    *fixture,
1217                            gconstpointer  user_data)
1218 {
1219   GtkTreeIter iter;
1220   GtkTreePath *changed_path;
1221
1222   check_filter_model (fixture);
1223   check_level_length (fixture->filter, NULL, 0);
1224
1225   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1226   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1227   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1228   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1229   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "1");
1230   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1231
1232   /* We simulate a change in visible func condition with this.  The
1233    * visibility state of multiple nodes changes at once, we emit row-changed
1234    * for these nodes (and others) after that.
1235    */
1236   filter_test_block_signals (fixture);
1237   set_path_visibility (fixture, "3", TRUE);
1238   set_path_visibility (fixture, "4", TRUE);
1239   filter_test_unblock_signals (fixture);
1240
1241   changed_path = gtk_tree_path_new ();
1242   gtk_tree_path_append_index (changed_path, 2);
1243   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1244                            &iter, changed_path);
1245   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1246                               changed_path, &iter);
1247
1248   gtk_tree_path_next (changed_path);
1249   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
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_free (changed_path);
1259
1260   check_filter_model (fixture);
1261   check_level_length (fixture->filter, NULL, 2);
1262   check_level_length (fixture->filter, "0", 0);
1263
1264   set_path_visibility (fixture, "3:2:2", TRUE);
1265   check_filter_model (fixture);
1266   check_level_length (fixture->filter, NULL, 2);
1267   check_level_length (fixture->filter, "0", 0);
1268
1269   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
1270   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1271   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
1272   set_path_visibility (fixture, "3:2", TRUE);
1273   check_filter_model (fixture);
1274   check_level_length (fixture->filter, NULL, 2);
1275   check_level_length (fixture->filter, "0", 1);
1276   check_level_length (fixture->filter, "0:0", 1);
1277   check_level_length (fixture->filter, "0:0:0", 0);
1278
1279   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1280   set_path_visibility (fixture, "3", FALSE);
1281   check_filter_model (fixture);
1282   check_level_length (fixture->filter, NULL, 1);
1283
1284   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1285   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1286   set_path_visibility (fixture, "3:2:1", TRUE);
1287   set_path_visibility (fixture, "3", TRUE);
1288   check_filter_model (fixture);
1289   check_level_length (fixture->filter, NULL, 2);
1290   check_level_length (fixture->filter, "0", 1);
1291   check_level_length (fixture->filter, "0:0", 2);
1292   check_level_length (fixture->filter, "0:0:0", 0);
1293 }
1294
1295 static void
1296 empty_vroot_show_nodes (FilterTest    *fixture,
1297                         gconstpointer  user_data)
1298 {
1299   GtkTreePath *path = (GtkTreePath *)user_data;
1300
1301   check_filter_model_with_root (fixture, path);
1302   check_level_length (fixture->filter, NULL, 0);
1303
1304   set_path_visibility (fixture, "2", TRUE);
1305   check_filter_model_with_root (fixture, path);
1306   check_level_length (fixture->filter, NULL, 0);
1307
1308   set_path_visibility (fixture, "2:2:2", TRUE);
1309   check_filter_model_with_root (fixture, path);
1310   check_level_length (fixture->filter, NULL, 0);
1311
1312   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1313   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1314   set_path_visibility (fixture, "2:2", TRUE);
1315   check_filter_model_with_root (fixture, path);
1316   check_level_length (fixture->filter, NULL, 1);
1317   check_level_length (fixture->filter, "0", 1);
1318   check_level_length (fixture->filter, "0:0", 0);
1319
1320   set_path_visibility (fixture, "3", TRUE);
1321   check_filter_model_with_root (fixture, path);
1322   check_level_length (fixture->filter, NULL, 1);
1323
1324   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1325   set_path_visibility (fixture, "2:2", FALSE);
1326   check_filter_model_with_root (fixture, path);
1327   check_level_length (fixture->filter, NULL, 0);
1328
1329   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1330   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1331   set_path_visibility (fixture, "2:2:1", TRUE);
1332   set_path_visibility (fixture, "2:2", TRUE);
1333   check_filter_model_with_root (fixture, path);
1334   check_level_length (fixture->filter, NULL, 1);
1335   check_level_length (fixture->filter, "0", 2);
1336   check_level_length (fixture->filter, "0:1", 0);
1337 }
1338
1339 static void
1340 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1341                                  gconstpointer  user_data)
1342 {
1343   GtkTreeIter iter;
1344   GtkTreePath *changed_path;
1345   GtkTreePath *path = (GtkTreePath *)user_data;
1346
1347   check_filter_model_with_root (fixture, path);
1348   check_level_length (fixture->filter, NULL, 0);
1349
1350   /* We simulate a change in visible func condition with this.  The
1351    * visibility state of multiple nodes changes at once, we emit row-changed
1352    * for these nodes (and others) after that.
1353    */
1354   filter_test_block_signals (fixture);
1355   set_path_visibility (fixture, "2", TRUE);
1356   set_path_visibility (fixture, "3", TRUE);
1357   filter_test_unblock_signals (fixture);
1358
1359   changed_path = gtk_tree_path_new ();
1360   gtk_tree_path_append_index (changed_path, 1);
1361   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1362                            &iter, changed_path);
1363   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1364                               changed_path, &iter);
1365
1366   gtk_tree_path_next (changed_path);
1367   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
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_free (changed_path);
1382
1383   check_filter_model_with_root (fixture, path);
1384   check_level_length (fixture->filter, NULL, 0);
1385
1386   set_path_visibility (fixture, "2:2:2", TRUE);
1387   check_filter_model_with_root (fixture, path);
1388   check_level_length (fixture->filter, NULL, 0);
1389
1390   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1391   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1392   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1393   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1394
1395   /* Again, we simulate a call to refilter */
1396   filter_test_block_signals (fixture);
1397   set_path_visibility (fixture, "2:2", TRUE);
1398   set_path_visibility (fixture, "2:3", TRUE);
1399   filter_test_unblock_signals (fixture);
1400
1401   changed_path = gtk_tree_path_new ();
1402   gtk_tree_path_append_index (changed_path, 2);
1403   gtk_tree_path_append_index (changed_path, 1);
1404   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1405                            &iter, changed_path);
1406   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1407                               changed_path, &iter);
1408
1409   gtk_tree_path_next (changed_path);
1410   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
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_free (changed_path);
1425
1426   check_filter_model_with_root (fixture, path);
1427   check_level_length (fixture->filter, NULL, 2);
1428   check_level_length (fixture->filter, "0", 1);
1429   check_level_length (fixture->filter, "0:0", 0);
1430
1431   set_path_visibility (fixture, "3", TRUE);
1432   check_filter_model_with_root (fixture, path);
1433   check_level_length (fixture->filter, NULL, 2);
1434
1435   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1436   set_path_visibility (fixture, "2:2", FALSE);
1437   check_filter_model_with_root (fixture, path);
1438   check_level_length (fixture->filter, NULL, 1);
1439
1440   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1441   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1442   set_path_visibility (fixture, "2:2:1", TRUE);
1443   set_path_visibility (fixture, "2:2", TRUE);
1444   check_filter_model_with_root (fixture, path);
1445   check_level_length (fixture->filter, NULL, 2);
1446   check_level_length (fixture->filter, "0", 2);
1447   check_level_length (fixture->filter, "0:1", 0);
1448 }
1449
1450
1451 static void
1452 unfiltered_hide_single (FilterTest    *fixture,
1453                         gconstpointer  user_data)
1454
1455 {
1456   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1457   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1458   set_path_visibility (fixture, "2", FALSE);
1459
1460   signal_monitor_assert_is_empty (fixture->monitor);
1461   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1462
1463   /* The view only shows the root level, so the filter model only has
1464    * the first two levels cached.
1465    */
1466   filter_test_append_refilter_signals (fixture, 2);
1467   filter_test_enable_filter (fixture);
1468
1469   check_filter_model (fixture);
1470   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1471 }
1472
1473 static void
1474 unfiltered_hide_single_child (FilterTest    *fixture,
1475                               gconstpointer  user_data)
1476
1477 {
1478   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1479   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1480   set_path_visibility (fixture, "2:2", FALSE);
1481
1482   signal_monitor_assert_is_empty (fixture->monitor);
1483   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1484   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1485
1486   /* The view only shows the root level, so the filter model only has
1487    * the first two levels cached.
1488    */
1489   filter_test_append_refilter_signals (fixture, 2);
1490   filter_test_enable_filter (fixture);
1491
1492   check_filter_model (fixture);
1493   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1494   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1495 }
1496
1497 static void
1498 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1499                                     gconstpointer  user_data)
1500
1501 {
1502   /* This row is not shown, so its signal is not propagated */
1503   set_path_visibility (fixture, "2:2:2", FALSE);
1504
1505   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1506   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1507   set_path_visibility (fixture, "2:2", FALSE);
1508
1509   signal_monitor_assert_is_empty (fixture->monitor);
1510   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1511   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1512   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1513
1514   /* The view only shows the root level, so the filter model only has
1515    * the first two levels cached.
1516    */
1517   filter_test_append_refilter_signals (fixture, 2);
1518   filter_test_enable_filter (fixture);
1519
1520   check_filter_model (fixture);
1521   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1522   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1523
1524   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1525   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1526   set_path_visibility (fixture, "2:2", TRUE);
1527
1528   check_filter_model (fixture);
1529   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1530   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1531   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1532 }
1533
1534
1535 static void
1536 unfiltered_vroot_hide_single (FilterTest    *fixture,
1537                               gconstpointer  user_data)
1538
1539 {
1540   GtkTreePath *path = (GtkTreePath *)user_data;
1541
1542   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1543   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1544   set_path_visibility (fixture, "2:2", FALSE);
1545
1546   signal_monitor_assert_is_empty (fixture->monitor);
1547   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1548
1549   /* The view only shows the root level, so the filter model only has
1550    * the first two levels cached.  (We add an additional level to
1551    * take the virtual root into account).
1552    */
1553   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1554   filter_test_enable_filter (fixture);
1555
1556   check_filter_model_with_root (fixture, path);
1557   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1558 }
1559
1560 static void
1561 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1562                                     gconstpointer  user_data)
1563
1564 {
1565   GtkTreePath *path = (GtkTreePath *)user_data;
1566
1567   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1568   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1569   set_path_visibility (fixture, "2:2:2", FALSE);
1570
1571   signal_monitor_assert_is_empty (fixture->monitor);
1572   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1573   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1574
1575   /* The view only shows the root level, so the filter model only has
1576    * the first two levels cached.  (We add an additional level to take
1577    * the virtual root into account).
1578    */
1579   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1580   filter_test_enable_filter (fixture);
1581
1582   check_filter_model_with_root (fixture, path);
1583   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1584   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1585 }
1586
1587 static void
1588 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1589                                           gconstpointer  user_data)
1590
1591 {
1592   GtkTreePath *path = (GtkTreePath *)user_data;
1593
1594   /* This row is not shown, so its signal is not propagated */
1595   set_path_visibility (fixture, "2:2:2:2", FALSE);
1596
1597   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1598   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1599   set_path_visibility (fixture, "2:2:2", FALSE);
1600
1601   signal_monitor_assert_is_empty (fixture->monitor);
1602   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1603   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1604   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1605
1606   /* The view only shows the root level, so the filter model only has
1607    * the first two levels cached.
1608    */
1609   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1610   filter_test_enable_filter (fixture);
1611
1612   check_filter_model_with_root (fixture, path);
1613   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1614   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1615
1616   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1617   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1618   set_path_visibility (fixture, "2:2:2", TRUE);
1619
1620   check_filter_model_with_root (fixture, path);
1621   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1622   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1623   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1624 }
1625
1626
1627
1628 static void
1629 unfiltered_show_single (FilterTest    *fixture,
1630                         gconstpointer  user_data)
1631
1632 {
1633   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1634   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1635   set_path_visibility (fixture, "2", TRUE);
1636
1637   signal_monitor_assert_is_empty (fixture->monitor);
1638   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1639
1640   /* The view only shows the root level, so the filter model only has
1641    * the first two levels cached.
1642    */
1643   filter_test_append_refilter_signals (fixture, 2);
1644   filter_test_enable_filter (fixture);
1645
1646   check_filter_model (fixture);
1647   check_level_length (fixture->filter, NULL, 1);
1648 }
1649
1650 static void
1651 unfiltered_show_single_child (FilterTest    *fixture,
1652                               gconstpointer  user_data)
1653
1654 {
1655   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1656   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1657   set_path_visibility (fixture, "2:2", TRUE);
1658
1659   signal_monitor_assert_is_empty (fixture->monitor);
1660   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1661   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1662
1663   /* The view only shows the root level, so the filter model only has
1664    * the first two levels cached.
1665    */
1666   filter_test_append_refilter_signals (fixture, 3);
1667   filter_test_enable_filter (fixture);
1668
1669   check_filter_model (fixture);
1670   check_level_length (fixture->filter, NULL, 0);
1671
1672   /* From here we are filtered, "2" in the real model is "0" in the filter
1673    * model.
1674    */
1675   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1676   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1677   set_path_visibility (fixture, "2", TRUE);
1678   signal_monitor_assert_is_empty (fixture->monitor);
1679   check_level_length (fixture->filter, NULL, 1);
1680   check_level_length (fixture->filter, "0", 1);
1681 }
1682
1683 static void
1684 unfiltered_show_single_multi_level (FilterTest    *fixture,
1685                                     gconstpointer  user_data)
1686
1687 {
1688   /* The view is not showing this row (collapsed state), so it is not
1689    * referenced.  The signal should not go through.
1690    */
1691   set_path_visibility (fixture, "2:2:2", TRUE);
1692
1693   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1694   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1695   set_path_visibility (fixture, "2:2", TRUE);
1696
1697   signal_monitor_assert_is_empty (fixture->monitor);
1698   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1699   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1700   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1701
1702   /* The view only shows the root level, so the filter model only has
1703    * the first two levels cached.
1704    */
1705   filter_test_append_refilter_signals (fixture, 3);
1706   filter_test_enable_filter (fixture);
1707
1708   check_filter_model (fixture);
1709   check_level_length (fixture->filter, NULL, 0);
1710
1711   /* From here we are filtered, "2" in the real model is "0" in the filter
1712    * model.
1713    */
1714   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1715   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1716   set_path_visibility (fixture, "2", TRUE);
1717   check_filter_model (fixture);
1718   check_level_length (fixture->filter, NULL, 1);
1719   check_level_length (fixture->filter, "0", 1);
1720   check_level_length (fixture->filter, "0:0", 1);
1721 }
1722
1723
1724 static void
1725 unfiltered_vroot_show_single (FilterTest    *fixture,
1726                               gconstpointer  user_data)
1727
1728 {
1729   GtkTreePath *path = (GtkTreePath *)user_data;
1730
1731   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1732   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1733   set_path_visibility (fixture, "2:2", TRUE);
1734
1735   signal_monitor_assert_is_empty (fixture->monitor);
1736   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1737
1738   /* The view only shows the root level, so the filter model only has
1739    * the first two levels cached.
1740    */
1741   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1742   filter_test_enable_filter (fixture);
1743
1744   check_filter_model_with_root (fixture, path);
1745   check_level_length (fixture->filter, NULL, 1);
1746 }
1747
1748 static void
1749 unfiltered_vroot_show_single_child (FilterTest    *fixture,
1750                                     gconstpointer  user_data)
1751
1752 {
1753   GtkTreePath *path = (GtkTreePath *)user_data;
1754
1755   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1756   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1757   set_path_visibility (fixture, "2:2:2", TRUE);
1758
1759   signal_monitor_assert_is_empty (fixture->monitor);
1760   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1761   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1762
1763   /* The view only shows the root level, so the filter model only has
1764    * the first two levels cached.
1765    */
1766   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1767   filter_test_enable_filter (fixture);
1768
1769   check_filter_model_with_root (fixture, path);
1770   check_level_length (fixture->filter, NULL, 0);
1771
1772   /* From here we are filtered, "2" in the real model is "0" in the filter
1773    * model.
1774    */
1775   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1776   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1777   set_path_visibility (fixture, "2:2", TRUE);
1778   signal_monitor_assert_is_empty (fixture->monitor);
1779   check_level_length (fixture->filter, NULL, 1);
1780   check_level_length (fixture->filter, "0", 1);
1781 }
1782
1783 static void
1784 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
1785                                           gconstpointer  user_data)
1786
1787 {
1788   GtkTreePath *path = (GtkTreePath *)user_data;
1789
1790   /* The view is not showing this row (collapsed state), so it is not
1791    * referenced.  The signal should not go through.
1792    */
1793   set_path_visibility (fixture, "2:2:2:2", TRUE);
1794
1795   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1796   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1797   set_path_visibility (fixture, "2:2:2", TRUE);
1798
1799   signal_monitor_assert_is_empty (fixture->monitor);
1800   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1801   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1802   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1803
1804   /* The view only shows the root level, so the filter model only has
1805    * the first two levels cached.
1806    */
1807   filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
1808   filter_test_enable_filter (fixture);
1809
1810   check_filter_model_with_root (fixture, path);
1811   check_level_length (fixture->filter, NULL, 0);
1812
1813   /* From here we are filtered, "2" in the real model is "0" in the filter
1814    * model.
1815    */
1816   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1817   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1818   set_path_visibility (fixture, "2:2", TRUE);
1819   check_filter_model_with_root (fixture, path);
1820   check_level_length (fixture->filter, NULL, 1);
1821   check_level_length (fixture->filter, "0", 1);
1822   check_level_length (fixture->filter, "0:0", 1);
1823 }
1824
1825
1826 static void
1827 insert_before (void)
1828 {
1829   GtkTreeStore *store;
1830   GtkTreeModel *filter;
1831   GtkWidget *tree_view;
1832   SignalMonitor *monitor;
1833   GtkTreeIter iter;
1834   GtkTreeIter last_iter;
1835   GtkTreePath *path;
1836
1837   /* This tests two aspects of the row-inserted handling:
1838    *   1) If the newly inserted node was already handled by building
1839    *      the root level, don't handle it a second time.
1840    *   2) Offsets of existing nodes must be updated when a new
1841    *      node is inserted.
1842    */
1843
1844   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1845   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1846   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
1847                                             1);
1848
1849   tree_view = gtk_tree_view_new_with_model (filter);
1850   monitor = signal_monitor_new (filter);
1851
1852   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
1853
1854   /* Insert 0 */
1855   path = gtk_tree_path_new_from_indices (0, -1);
1856   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1857   gtk_tree_path_free (path);
1858
1859   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
1860                                      0, "Foo", 1, TRUE, -1);
1861
1862   signal_monitor_assert_is_empty (monitor);
1863   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1864
1865   /* Insert 1 */
1866   path = gtk_tree_path_new_from_indices (1, -1);
1867   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1868   gtk_tree_path_free (path);
1869
1870   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1871                                      0, "Foo", 1, TRUE, -1);
1872   last_iter = iter;
1873
1874   signal_monitor_assert_is_empty (monitor);
1875   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
1876
1877   /* Insert on 1 again -- invisible */
1878   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1879                                      0, "Foo", 1, FALSE, -1);
1880
1881   signal_monitor_assert_is_empty (monitor);
1882   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
1883
1884   /* Insert on 1 again -- visible */
1885   path = gtk_tree_path_new_from_indices (1, -1);
1886   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1887   gtk_tree_path_free (path);
1888
1889   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
1890                                      0, "Foo", 1, TRUE, -1);
1891
1892   signal_monitor_assert_is_empty (monitor);
1893   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
1894
1895   /* Modify the iter that should be at the last position and check the
1896    * signal we get.
1897    */
1898   path = gtk_tree_path_new_from_indices (2, -1);
1899   signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
1900   gtk_tree_path_free (path);
1901
1902   gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
1903
1904   signal_monitor_assert_is_empty (monitor);
1905   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
1906 }
1907
1908 static void
1909 insert_child (void)
1910 {
1911   GtkTreeStore *store;
1912   GtkTreeModel *filter;
1913   GtkWidget *tree_view;
1914   SignalMonitor *monitor;
1915   GtkTreeIter parent, iter;
1916   GtkTreePath *path;
1917
1918   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1919
1920   gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
1921                                      0, "Parent", 1, TRUE, -1);
1922
1923
1924   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1925   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
1926                                             1);
1927
1928   tree_view = gtk_tree_view_new_with_model (filter);
1929   monitor = signal_monitor_new (filter);
1930
1931   /* Insert child -- invisible */
1932   path = gtk_tree_path_new_from_indices (0, -1);
1933   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1934   /* The signal is received twice, once a pass through from GtkTreeStore
1935    * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
1936    * hurt.
1937    */
1938   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1939   gtk_tree_path_free (path);
1940
1941   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
1942                                      0, "Child", 1, FALSE, -1);
1943
1944   signal_monitor_assert_is_empty (monitor);
1945   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1946
1947   /* Insert child */
1948   path = gtk_tree_path_new_from_indices (0, 0, -1);
1949   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
1950   gtk_tree_path_up (path); /* 0 */
1951   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
1952   gtk_tree_path_free (path);
1953
1954   gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
1955                                      0, "Child", 1, TRUE, -1);
1956
1957   signal_monitor_assert_is_empty (monitor);
1958   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1959
1960   /* Insert child -- invisible */
1961   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
1962                                      0, "Child", 1, FALSE, -1);
1963
1964   signal_monitor_assert_is_empty (monitor);
1965   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
1966 }
1967
1968
1969
1970 static void
1971 remove_node (void)
1972 {
1973   GtkTreeIter iter, iter1, iter2, iter3;
1974   GtkListStore *list;
1975   GtkTreeModel *filter;
1976   GtkWidget *view G_GNUC_UNUSED;
1977
1978   list = gtk_list_store_new (1, G_TYPE_INT);
1979   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
1980   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
1981   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
1982   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
1983   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
1984   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
1985   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
1986   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
1987
1988   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
1989   view = gtk_tree_view_new_with_model (filter);
1990
1991   gtk_list_store_remove (list, &iter1);
1992   gtk_list_store_remove (list, &iter3);
1993   gtk_list_store_remove (list, &iter2);
1994 }
1995
1996 static void
1997 remove_node_vroot (void)
1998 {
1999   GtkTreeIter parent, root;
2000   GtkTreeIter iter, iter1, iter2, iter3;
2001   GtkTreeStore *tree;
2002   GtkTreeModel *filter;
2003   GtkTreePath *path;
2004   GtkWidget *view G_GNUC_UNUSED;
2005
2006   tree = gtk_tree_store_new (1, G_TYPE_INT);
2007   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2008   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2009
2010   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2011   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2012   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2013   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2014   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2015   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2016   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2017   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2018
2019   path = gtk_tree_path_new_from_indices (0, 0, -1);
2020   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2021   gtk_tree_path_free (path);
2022
2023   view = gtk_tree_view_new_with_model (filter);
2024
2025   gtk_tree_store_remove (tree, &iter1);
2026   gtk_tree_store_remove (tree, &iter3);
2027   gtk_tree_store_remove (tree, &iter2);
2028 }
2029
2030 static void
2031 remove_vroot_ancestor (void)
2032 {
2033   GtkTreeIter parent, root;
2034   GtkTreeIter iter, iter1, iter2, iter3;
2035   GtkTreeStore *tree;
2036   GtkTreeModel *filter;
2037   GtkTreePath *path;
2038   GtkWidget *view G_GNUC_UNUSED;
2039
2040   tree = gtk_tree_store_new (1, G_TYPE_INT);
2041   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2042   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2043
2044   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2045   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2046   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2047   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2048   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2049   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2050   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2051   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2052
2053   path = gtk_tree_path_new_from_indices (0, 0, -1);
2054   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2055   gtk_tree_path_free (path);
2056
2057   view = gtk_tree_view_new_with_model (filter);
2058
2059   gtk_tree_store_remove (tree, &parent);
2060 }
2061
2062
2063 static gboolean
2064 specific_path_dependent_filter_func (GtkTreeModel *model,
2065                                      GtkTreeIter  *iter,
2066                                      gpointer      data)
2067 {
2068   GtkTreePath *path;
2069
2070   path = gtk_tree_model_get_path (model, iter);
2071   if (gtk_tree_path_get_indices (path)[0] < 4)
2072     return FALSE;
2073
2074   return TRUE;
2075 }
2076
2077 static void
2078 specific_path_dependent_filter (void)
2079 {
2080   int i;
2081   GtkTreeIter iter;
2082   GtkListStore *list;
2083   GtkTreeModel *sort;
2084   GtkTreeModel *filter;
2085
2086   list = gtk_list_store_new (1, G_TYPE_INT);
2087   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2088   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2089   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2090   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2091   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2092   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2093   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2094   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2095
2096   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
2097   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
2098   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2099                                           specific_path_dependent_filter_func,
2100                                           NULL, NULL);
2101
2102   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
2103                                         GTK_SORT_DESCENDING);
2104
2105   for (i = 0; i < 4; i++)
2106     {
2107       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
2108                                          NULL, 1))
2109         gtk_list_store_remove (list, &iter);
2110
2111       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
2112                                          NULL, 2))
2113         gtk_list_store_remove (list, &iter);
2114     }
2115 }
2116
2117
2118 static gboolean
2119 specific_append_after_collapse_visible_func (GtkTreeModel *model,
2120                                              GtkTreeIter  *iter,
2121                                              gpointer      data)
2122 {
2123   gint number;
2124   gboolean hide_negative_numbers;
2125
2126   gtk_tree_model_get (model, iter, 1, &number, -1);
2127   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
2128
2129   return (number >= 0 || !hide_negative_numbers);
2130 }
2131
2132 static void
2133 specific_append_after_collapse (void)
2134 {
2135   /* This test is based on one of the test cases I found in my
2136    * old test cases directory.  I unfortunately do not have a record
2137    * from who this test case originated.  -Kris.
2138    *
2139    * General idea:
2140    * - Construct tree.
2141    * - Show tree, expand, collapse.
2142    * - Add a row.
2143    */
2144
2145   GtkTreeIter iter;
2146   GtkTreeIter child_iter;
2147   GtkTreeIter child_iter2;
2148   GtkTreePath *append_path;
2149   GtkTreeStore *store;
2150   GtkTreeModel *filter;
2151   GtkTreeModel *sort;
2152
2153   GtkWidget *window;
2154   GtkWidget *tree_view;
2155
2156   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
2157
2158   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2159   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2160                      GINT_TO_POINTER (FALSE));
2161   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2162                                           specific_append_after_collapse_visible_func,
2163                                           filter, NULL);
2164
2165   sort = gtk_tree_model_sort_new_with_model (filter);
2166
2167   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2168   tree_view = gtk_tree_view_new_with_model (sort);
2169   gtk_container_add (GTK_CONTAINER (window), tree_view);
2170   gtk_widget_realize (tree_view);
2171
2172   while (gtk_events_pending ())
2173     gtk_main_iteration ();
2174
2175   gtk_tree_store_prepend (store, &iter, NULL);
2176   gtk_tree_store_set (store, &iter,
2177                       0, "hallo", 1, 1, -1);
2178
2179   gtk_tree_store_append (store, &child_iter, &iter);
2180   gtk_tree_store_set (store, &child_iter,
2181                       0, "toemaar", 1, 1, -1);
2182
2183   gtk_tree_store_append (store, &child_iter2, &child_iter);
2184   gtk_tree_store_set (store, &child_iter2,
2185                       0, "very deep", 1, 1, -1);
2186
2187   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
2188
2189   gtk_tree_store_append (store, &child_iter, &iter);
2190   gtk_tree_store_set (store, &child_iter,
2191                       0, "sja", 1, 1, -1);
2192
2193   gtk_tree_store_append (store, &child_iter, &iter);
2194   gtk_tree_store_set (store, &child_iter,
2195                       0, "some word", 1, -1, -1);
2196
2197   /* Expand and collapse the tree */
2198   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2199   while (gtk_events_pending ())
2200     gtk_main_iteration ();
2201
2202   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2203   while (gtk_events_pending ())
2204     gtk_main_iteration ();
2205
2206   /* Add another it */
2207   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
2208                      GINT_TO_POINTER (TRUE));
2209
2210   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
2211     {
2212       gtk_tree_store_append (store, &child_iter, &iter);
2213       gtk_tree_store_set (store, &child_iter,
2214                           0, "new new new !!", 1, 1, -1);
2215     }
2216   gtk_tree_path_free (append_path);
2217
2218   /* Expand */
2219   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2220   while (gtk_events_pending ())
2221     gtk_main_iteration ();
2222 }
2223
2224
2225 static gint
2226 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
2227                                                GtkTreeIter   *iter1,
2228                                                GtkTreeIter   *iter2,
2229                                                gpointer       data)
2230 {
2231   return -1;
2232 }
2233
2234 static gboolean
2235 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
2236                                                GtkTreeIter   *iter,
2237                                                gpointer       data)
2238 {
2239   char *item = NULL;
2240
2241   /* Do reference the model */
2242   gtk_tree_model_get (model, iter, 0, &item, -1);
2243   g_free (item);
2244
2245   return FALSE;
2246 }
2247
2248 static void
2249 specific_sort_filter_remove_node (void)
2250 {
2251   /* This test is based on one of the test cases I found in my
2252    * old test cases directory.  I unfortunately do not have a record
2253    * from who this test case originated.  -Kris.
2254    *
2255    * General idea:
2256    *  - Create tree store, sort, filter models.  The sort model has
2257    *    a default sort func that is enabled, filter model a visible func
2258    *    that defaults to returning FALSE.
2259    *  - Remove a node from the tree store.
2260    */
2261
2262   GtkTreeIter iter;
2263   GtkTreeStore *store;
2264   GtkTreeModel *filter;
2265   GtkTreeModel *sort;
2266
2267   GtkWidget *window;
2268   GtkWidget *tree_view;
2269
2270   store = gtk_tree_store_new (1, G_TYPE_STRING);
2271   gtk_tree_store_append (store, &iter, NULL);
2272   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
2273
2274   gtk_tree_store_append (store, &iter, NULL);
2275   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
2276
2277   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2278   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2279                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
2280
2281   filter = gtk_tree_model_filter_new (sort, NULL);
2282   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2283                                           specific_sort_filter_remove_node_visible_func,
2284                                           filter, NULL);
2285
2286
2287   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2288   tree_view = gtk_tree_view_new_with_model (filter);
2289   gtk_container_add (GTK_CONTAINER (window), tree_view);
2290   gtk_widget_realize (tree_view);
2291
2292   while (gtk_events_pending ())
2293     gtk_main_iteration ();
2294
2295   /* Remove a node */
2296   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
2297   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
2298   gtk_tree_store_remove (store, &iter);
2299
2300   while (gtk_events_pending ())
2301     gtk_main_iteration ();
2302 }
2303
2304
2305 static void
2306 specific_sort_filter_remove_root (void)
2307 {
2308   /* This test is based on one of the test cases I found in my
2309    * old test cases directory.  I unfortunately do not have a record
2310    * from who this test case originated.  -Kris.
2311    */
2312
2313   GtkTreeModel *model, *sort, *filter;
2314   GtkTreeIter root, mid, leaf;
2315   GtkTreePath *path;
2316
2317   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
2318   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
2319   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
2320   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
2321
2322   path = gtk_tree_model_get_path (model, &mid);
2323
2324   sort = gtk_tree_model_sort_new_with_model (model);
2325   filter = gtk_tree_model_filter_new (sort, path);
2326
2327   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
2328
2329   g_object_unref (filter);
2330   g_object_unref (sort);
2331   g_object_unref (model);
2332 }
2333
2334
2335 static void
2336 specific_root_mixed_visibility (void)
2337 {
2338   int i;
2339   GtkTreeModel *filter;
2340   /* A bit nasty, apologies */
2341   FilterTest fixture;
2342
2343   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2344
2345   for (i = 0; i < LEVEL_LENGTH; i++)
2346     {
2347       GtkTreeIter iter;
2348
2349       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
2350       if (i % 2 == 0)
2351         create_tree_store_set_values (fixture.store, &iter, TRUE);
2352       else
2353         create_tree_store_set_values (fixture.store, &iter, FALSE);
2354     }
2355
2356   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2357   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2358   fixture.monitor = NULL;
2359
2360   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
2361
2362   /* In order to trigger the potential bug, we should not access
2363    * the filter model here (so don't call the check functions).
2364    */
2365
2366   /* Change visibility of an odd row to TRUE */
2367   set_path_visibility (&fixture, "3", TRUE);
2368   check_filter_model (&fixture);
2369   check_level_length (fixture.filter, NULL, 4);
2370 }
2371
2372
2373
2374 static gboolean
2375 specific_has_child_filter_filter_func (GtkTreeModel *model,
2376                                        GtkTreeIter  *iter,
2377                                        gpointer      data)
2378 {
2379   return gtk_tree_model_iter_has_child (model, iter);
2380 }
2381
2382 static void
2383 specific_has_child_filter (void)
2384 {
2385   GtkTreeModel *filter;
2386   GtkTreeIter iter, root;
2387   FilterTest fixture; /* This is not how it should be done */
2388   GtkWidget *tree_view;
2389
2390   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2391   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2392   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2393   fixture.monitor = signal_monitor_new (filter);
2394
2395   tree_view = gtk_tree_view_new_with_model (filter);
2396
2397   /* We will filter on parent state using a filter function.  We will
2398    * manually keep the boolean column in sync, so that we can use
2399    * check_filter_model() to check the consistency of the model.
2400    */
2401   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2402    * to be able to check the structure here.  We keep the calls to
2403    * check_filter_model() commented out until then.
2404    */
2405   gtk_tree_model_filter_set_visible_func (fixture.filter,
2406                                           specific_has_child_filter_filter_func,
2407                                           NULL, NULL);
2408
2409   /* The first node will be initially invisible: no signals */
2410   gtk_tree_store_append (fixture.store, &root, NULL);
2411   create_tree_store_set_values (fixture.store, &root, FALSE);
2412
2413   /* check_filter_model (&fixture); */
2414   check_level_length (fixture.filter, NULL, 0);
2415   signal_monitor_assert_is_empty (fixture.monitor);
2416
2417   /* Insert a child node. This will cause the parent to become visible
2418    * since there is a child now.
2419    */
2420   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
2421   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2422   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2423
2424   gtk_tree_store_append (fixture.store, &iter, &root);
2425   create_tree_store_set_values (fixture.store, &iter, TRUE);
2426
2427   /* Parent must now be visible.  Do the level length check first,
2428    * to avoid modifying the child model triggering a row-changed to
2429    * the filter model.
2430    */
2431   check_level_length (fixture.filter, NULL, 1);
2432   check_level_length (fixture.filter, "0", 0);
2433   signal_monitor_assert_is_empty (fixture.monitor);
2434
2435   /* This should propagate row-changed */
2436   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
2437   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2438
2439   set_path_visibility (&fixture, "0", TRUE);
2440   /* check_filter_model (&fixture); */
2441   signal_monitor_assert_is_empty (fixture.monitor);
2442
2443   /* New root node, no child, so no signal */
2444   gtk_tree_store_append (fixture.store, &root, NULL);
2445   check_level_length (fixture.filter, NULL, 1);
2446   signal_monitor_assert_is_empty (fixture.monitor);
2447
2448   /* When the child comes in, this node will become visible */
2449   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
2450   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2451   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2452   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
2453   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2454
2455   gtk_tree_store_append (fixture.store, &iter, &root);
2456   check_level_length (fixture.filter, NULL, 2);
2457   check_level_length (fixture.filter, "1", 0);
2458
2459   create_tree_store_set_values (fixture.store, &root, TRUE);
2460   create_tree_store_set_values (fixture.store, &iter, TRUE);
2461
2462   /* check_filter_model (&fixture); */
2463   signal_monitor_assert_is_empty (fixture.monitor);
2464
2465   /* Add another child for 1 */
2466   gtk_tree_store_append (fixture.store, &iter, &root);
2467   create_tree_store_set_values (fixture.store, &iter, TRUE);
2468   check_level_length (fixture.filter, NULL, 2);
2469   check_level_length (fixture.filter, "0", 0);
2470   check_level_length (fixture.filter, "1", 0);
2471   signal_monitor_assert_is_empty (fixture.monitor);
2472
2473   /* Now remove one of the remaining child rows */
2474   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
2475
2476   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2477                                        &iter, "0:0");
2478   gtk_tree_store_remove (fixture.store, &iter);
2479
2480   check_level_length (fixture.filter, NULL, 1);
2481   check_level_length (fixture.filter, "0", 0);
2482
2483   set_path_visibility (&fixture, "0", FALSE);
2484   /* check_filter_model (&fixture); */
2485   signal_monitor_assert_is_empty (fixture.monitor);
2486 }
2487
2488
2489 static gboolean
2490 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
2491                                             GtkTreeIter  *iter,
2492                                             gpointer      data)
2493 {
2494   int depth;
2495   GtkTreePath *path;
2496
2497   path = gtk_tree_model_get_path (model, iter);
2498   depth = gtk_tree_path_get_depth (path);
2499   gtk_tree_path_free (path);
2500
2501   if (depth > 1)
2502     return TRUE;
2503   /* else */
2504   return gtk_tree_model_iter_has_child (model, iter);
2505 }
2506
2507 static void
2508 specific_root_has_child_filter (void)
2509 {
2510   GtkTreeModel *filter;
2511   GtkTreeIter iter, root;
2512   FilterTest fixture; /* This is not how it should be done ... */
2513   GtkWidget *tree_view;
2514
2515   /* This is a variation on the above test case, specific has-child-filter,
2516    * herein the has-child check for visibility only applies to root level
2517    * nodes.  In this test, children are always visible because we
2518    * only filter based on the "has child" criterion.
2519    */
2520
2521   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2522   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2523   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2524   fixture.monitor = signal_monitor_new (filter);
2525
2526   tree_view = gtk_tree_view_new_with_model (filter);
2527
2528   /* We will filter on parent state using a filter function.  We will
2529    * manually keep the boolean column in sync, so that we can use
2530    * check_filter_model() to check the consistency of the model.
2531    */
2532   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2533    * to be able to check the structure here.  We keep the calls to
2534    * check_filter_model() commented out until then.
2535    */
2536   gtk_tree_model_filter_set_visible_func (fixture.filter,
2537                                           specific_root_has_child_filter_filter_func,
2538                                           NULL, NULL);
2539
2540   /* Add a first node, this will be invisible initially, so no signal
2541    * should be emitted.
2542    */
2543   gtk_tree_store_append (fixture.store, &root, NULL);
2544   create_tree_store_set_values (fixture.store, &root, FALSE);
2545
2546   signal_monitor_assert_is_empty (fixture.monitor);
2547   /* check_filter_model (&fixture); */
2548   check_level_length (fixture.filter, NULL, 0);
2549
2550   /* Add a child node.  This will cause the parent to become visible,
2551    * so we expect row-inserted signals for both.
2552    */
2553   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
2554   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2555   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2556
2557   gtk_tree_store_append (fixture.store, &iter, &root);
2558   signal_monitor_assert_is_empty (fixture.monitor);
2559
2560   check_level_length (fixture.filter, NULL, 1);
2561   check_level_length (fixture.filter, "0", 1);
2562
2563   /* Modify the content of iter, yields row-changed signals */
2564   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0:0");
2565
2566   create_tree_store_set_values (fixture.store, &iter, TRUE);
2567   signal_monitor_assert_is_empty (fixture.monitor);
2568
2569   /* Parent must now be visible.  Do the level length check first,
2570    * to avoid modifying the child model triggering a row-changed to
2571    * the filter model.
2572    */
2573   check_level_length (fixture.filter, NULL, 1);
2574   check_level_length (fixture.filter, "0", 1);
2575
2576   /* Modify path 0 */
2577   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
2578   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2579
2580   set_path_visibility (&fixture, "0", TRUE);
2581   /* check_filter_model (&fixture); */
2582
2583   signal_monitor_assert_is_empty (fixture.monitor);
2584
2585   /* Insert another node in the root level.  Initially invisible, so
2586    * not expecting any signal.
2587    */
2588   gtk_tree_store_append (fixture.store, &root, NULL);
2589   check_level_length (fixture.filter, NULL, 1);
2590
2591   signal_monitor_assert_is_empty (fixture.monitor);
2592
2593   /* Adding a child node which also makes parent at path 1 visible. */
2594   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
2595   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2596   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2597
2598   gtk_tree_store_append (fixture.store, &iter, &root);
2599   check_level_length (fixture.filter, NULL, 2);
2600   check_level_length (fixture.filter, "1", 1);
2601
2602   signal_monitor_assert_is_empty (fixture.monitor);
2603
2604   /* Check if row-changed is propagated */
2605   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
2606   /* is row-has-child-toggled really necessary? */
2607   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
2608   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1:0");
2609
2610   create_tree_store_set_values (fixture.store, &root, TRUE);
2611   create_tree_store_set_values (fixture.store, &iter, TRUE);
2612   /* check_filter_model (&fixture); */
2613   signal_monitor_assert_is_empty (fixture.monitor);
2614
2615   /* Insert another child under node 1 */
2616   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1:1");
2617   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1:1");
2618
2619   gtk_tree_store_append (fixture.store, &iter, &root);
2620   create_tree_store_set_values (fixture.store, &iter, TRUE);
2621   check_level_length (fixture.filter, NULL, 2);
2622   check_level_length (fixture.filter, "0", 1);
2623   check_level_length (fixture.filter, "1", 2);
2624   signal_monitor_assert_is_empty (fixture.monitor);
2625
2626   /* Set a child node to invisible.  This should not yield any
2627    * change, because filtering is only done on whether the root
2628    * node has a child, which it still has.
2629    */
2630   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0:0");
2631
2632   set_path_visibility (&fixture, "0:0", FALSE);
2633   signal_monitor_assert_is_empty (fixture.monitor);
2634
2635   /* Now remove one of the remaining child rows */
2636   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0:0");
2637   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
2638   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
2639
2640   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2641                                        &iter, "0:0");
2642   gtk_tree_store_remove (fixture.store, &iter);
2643
2644   check_level_length (fixture.filter, NULL, 1);
2645   check_level_length (fixture.filter, "0", 2);
2646   signal_monitor_assert_is_empty (fixture.monitor);
2647
2648   /* Set visibility of 0 to FALSE, no-op for filter model since
2649    * the child 0:0 is already gone
2650    */
2651   set_path_visibility (&fixture, "0", FALSE);
2652   /* check_filter_model (&fixture); */
2653   signal_monitor_assert_is_empty (fixture.monitor);
2654 }
2655
2656
2657 static void
2658 specific_filter_add_child (void)
2659 {
2660   /* This test is based on one of the test cases I found in my
2661    * old test cases directory.  I unfortunately do not have a record
2662    * from who this test case originated.  -Kris.
2663    */
2664
2665   GtkTreeIter iter;
2666   GtkTreeIter iter_first;
2667   GtkTreeIter child;
2668   GtkTreeStore *store;
2669   GtkTreeModel *filter G_GNUC_UNUSED;
2670
2671   store = gtk_tree_store_new (1, G_TYPE_STRING);
2672
2673   gtk_tree_store_append (store, &iter_first, NULL);
2674   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
2675
2676   gtk_tree_store_append (store, &iter, NULL);
2677   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2678
2679   gtk_tree_store_append (store, &iter, NULL);
2680   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2681
2682   gtk_tree_store_append (store, &iter, NULL);
2683   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2684
2685   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2686
2687   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2688   gtk_tree_store_append (store, &child, &iter_first);
2689   gtk_tree_store_set (store, &child, 0, "Hello", -1);
2690 }
2691
2692 static void
2693 specific_list_store_clear (void)
2694 {
2695   GtkTreeIter iter;
2696   GtkListStore *list;
2697   GtkTreeModel *filter;
2698   GtkWidget *view G_GNUC_UNUSED;
2699
2700   list = gtk_list_store_new (1, G_TYPE_INT);
2701   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2702   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2703   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2704   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2705   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2706   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2707   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2708   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2709
2710   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2711   view = gtk_tree_view_new_with_model (filter);
2712
2713   gtk_list_store_clear (list);
2714 }
2715
2716 static void
2717 specific_sort_ref_leaf_and_remove_ancestor (void)
2718 {
2719   GtkTreeIter iter, child, child2, child3;
2720   GtkTreeStore *tree;
2721   GtkTreeModel *sort;
2722   GtkTreePath *path;
2723   GtkTreeRowReference *rowref;
2724   GtkWidget *view G_GNUC_UNUSED;
2725
2726   tree = gtk_tree_store_new (1, G_TYPE_INT);
2727   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2728   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2729   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2730   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2731
2732   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2733   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2734   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2735
2736   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2737   view = gtk_tree_view_new_with_model (sort);
2738   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2739
2740   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2741   rowref = gtk_tree_row_reference_new (sort, path);
2742   gtk_tree_path_free (path);
2743
2744   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2745   rowref = gtk_tree_row_reference_new (sort, path);
2746   gtk_tree_path_free (path);
2747
2748   path = gtk_tree_path_new_from_indices (3, 0, -1);
2749   rowref = gtk_tree_row_reference_new (sort, path);
2750   gtk_tree_path_free (path);
2751
2752   path = gtk_tree_path_new_from_indices (3, -1);
2753   rowref = gtk_tree_row_reference_new (sort, path);
2754   gtk_tree_path_free (path);
2755
2756   /* Deleting a parent */
2757   path = gtk_tree_path_new_from_indices (3, 0, -1);
2758   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2759   gtk_tree_store_remove (tree, &iter);
2760   gtk_tree_path_free (path);
2761
2762   gtk_tree_row_reference_free (rowref);
2763 }
2764
2765 static void
2766 specific_ref_leaf_and_remove_ancestor (void)
2767 {
2768   GtkTreeIter iter, child, child2, child3;
2769   GtkTreeStore *tree;
2770   GtkTreeModel *filter;
2771   GtkTreePath *path;
2772   GtkTreeRowReference *rowref;
2773   GtkWidget *view G_GNUC_UNUSED;
2774
2775   tree = gtk_tree_store_new (1, G_TYPE_INT);
2776   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2777   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2778   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2779   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2780
2781   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2782   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2783   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2784
2785   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
2786   view = gtk_tree_view_new_with_model (filter);
2787   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2788
2789   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2790   rowref = gtk_tree_row_reference_new (filter, path);
2791   gtk_tree_path_free (path);
2792
2793   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2794   rowref = gtk_tree_row_reference_new (filter, path);
2795   gtk_tree_path_free (path);
2796
2797   path = gtk_tree_path_new_from_indices (3, 0, -1);
2798   rowref = gtk_tree_row_reference_new (filter, path);
2799   gtk_tree_path_free (path);
2800
2801   path = gtk_tree_path_new_from_indices (3, -1);
2802   rowref = gtk_tree_row_reference_new (filter, path);
2803   gtk_tree_path_free (path);
2804
2805   /* Deleting a parent */
2806   path = gtk_tree_path_new_from_indices (3, 0, -1);
2807   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2808   gtk_tree_store_remove (tree, &iter);
2809   gtk_tree_path_free (path);
2810
2811   gtk_tree_row_reference_free (rowref);
2812 }
2813
2814 static void
2815 specific_virtual_ref_leaf_and_remove_ancestor (void)
2816 {
2817   GtkTreeIter iter, child, child2, child3;
2818   GtkTreeStore *tree;
2819   GtkTreeModel *filter;
2820   GtkTreePath *path;
2821   GtkTreeRowReference *rowref;
2822   GtkWidget *view G_GNUC_UNUSED;
2823
2824   tree = gtk_tree_store_new (1, G_TYPE_INT);
2825   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2826   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2827   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2828   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2829
2830   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2831   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2832   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2833
2834   /* Set a virtual root of 3:0 */
2835   path = gtk_tree_path_new_from_indices (3, 0, -1);
2836   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2837   gtk_tree_path_free (path);
2838
2839   view = gtk_tree_view_new_with_model (filter);
2840   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2841
2842   path = gtk_tree_path_new_from_indices (0, 0, -1);
2843   rowref = gtk_tree_row_reference_new (filter, path);
2844   gtk_tree_path_free (path);
2845
2846   path = gtk_tree_path_new_from_indices (0, 0, -1);
2847   rowref = gtk_tree_row_reference_new (filter, path);
2848   gtk_tree_path_free (path);
2849
2850   path = gtk_tree_path_new_from_indices (0, -1);
2851   rowref = gtk_tree_row_reference_new (filter, path);
2852   gtk_tree_path_free (path);
2853
2854   /* Deleting the virtual root */
2855   path = gtk_tree_path_new_from_indices (3, 0, -1);
2856   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2857   gtk_tree_store_remove (tree, &iter);
2858   gtk_tree_path_free (path);
2859
2860   gtk_tree_row_reference_free (rowref);
2861 }
2862
2863
2864 static int
2865 specific_bug_301558_sort_func (GtkTreeModel *model,
2866                                GtkTreeIter  *a,
2867                                GtkTreeIter  *b,
2868                                gpointer      data)
2869 {
2870   int i, j;
2871
2872   gtk_tree_model_get (model, a, 0, &i, -1);
2873   gtk_tree_model_get (model, b, 0, &j, -1);
2874
2875   return j - i;
2876 }
2877
2878 static void
2879 specific_bug_301558 (void)
2880 {
2881   /* Test case for GNOME Bugzilla bug 301558 provided by
2882    * Markku Vire.
2883    */
2884   GtkTreeStore *tree;
2885   GtkTreeModel *filter;
2886   GtkTreeModel *sort;
2887   GtkTreeIter root, iter, iter2;
2888   GtkWidget *view G_GNUC_UNUSED;
2889   int i;
2890   gboolean add;
2891
2892   g_test_bug ("301558");
2893
2894   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
2895   gtk_tree_store_append (tree, &iter, NULL);
2896   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
2897   gtk_tree_store_append (tree, &iter2, &iter);
2898   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
2899
2900   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2901   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2902                                            specific_bug_301558_sort_func,
2903                                            NULL, NULL);
2904
2905   filter = gtk_tree_model_filter_new (sort, NULL);
2906   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
2907
2908   view = gtk_tree_view_new_with_model (filter);
2909
2910   while (gtk_events_pending ())
2911     gtk_main_iteration ();
2912
2913   add = TRUE;
2914
2915   for (i = 0; i < 10; i++)
2916     {
2917       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
2918         g_assert_not_reached ();
2919
2920       if (add)
2921         {
2922           gtk_tree_store_append (tree, &iter, &root);
2923           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
2924         }
2925       else
2926         {
2927           int n;
2928           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
2929           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
2930                                          &root, n - 1);
2931           gtk_tree_store_remove (tree, &iter);
2932         }
2933
2934       add = !add;
2935     }
2936 }
2937
2938
2939 static gboolean
2940 specific_bug_311955_filter_func (GtkTreeModel *model,
2941                                  GtkTreeIter  *iter,
2942                                  gpointer      data)
2943 {
2944   int value;
2945
2946   gtk_tree_model_get (model, iter, 0, &value, -1);
2947
2948   return (value != 0);
2949 }
2950
2951 static void
2952 specific_bug_311955 (void)
2953 {
2954   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
2955    * by Markku Vire.
2956    */
2957   GtkTreeIter iter, child, root;
2958   GtkTreeStore *store;
2959   GtkTreeModel *sort;
2960   GtkTreeModel *filter;
2961
2962   GtkWidget *window G_GNUC_UNUSED;
2963   GtkWidget *tree_view;
2964   int i;
2965   int n;
2966
2967   g_test_bug ("311955");
2968
2969   store = gtk_tree_store_new (1, G_TYPE_INT);
2970
2971   gtk_tree_store_append (store, &root, NULL);
2972   gtk_tree_store_set (store, &root, 0, 33, -1);
2973
2974   gtk_tree_store_append (store, &iter, &root);
2975   gtk_tree_store_set (store, &iter, 0, 50, -1);
2976
2977   gtk_tree_store_append (store, &iter, NULL);
2978   gtk_tree_store_set (store, &iter, 0, 22, -1);
2979
2980   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2981   filter = gtk_tree_model_filter_new (sort, NULL);
2982
2983   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2984                                           specific_bug_311955_filter_func,
2985                                           NULL, NULL);
2986
2987   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2988   tree_view = gtk_tree_view_new_with_model (filter);
2989   g_object_unref (store);
2990
2991   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2992
2993   while (gtk_events_pending ())
2994     gtk_main_iteration ();
2995
2996   /* Fill model */
2997   for (i = 0; i < 4; i++)
2998     {
2999       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
3000
3001       gtk_tree_store_append (store, &iter, &root);
3002
3003       if (i < 3)
3004         gtk_tree_store_set (store, &iter, 0, i, -1);
3005
3006       if (i % 2 == 0)
3007         {
3008           gtk_tree_store_append (store, &child, &iter);
3009           gtk_tree_store_set (store, &child, 0, 10, -1);
3010         }
3011     }
3012
3013   while (gtk_events_pending ())
3014     gtk_main_iteration ();
3015
3016   /* Remove bottommost child from the tree. */
3017   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
3018   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
3019
3020   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
3021     {
3022       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
3023         gtk_tree_store_remove (store, &child);
3024     }
3025   else
3026     g_assert_not_reached ();
3027 }
3028
3029 static void
3030 specific_bug_346800 (void)
3031 {
3032   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
3033    * by Jonathan Matthew.
3034    */
3035
3036   GtkTreeIter node_iters[50];
3037   GtkTreeIter child_iters[50];
3038   GtkTreeModel *model;
3039   GtkTreeModelFilter *filter;
3040   GtkTreeStore *store;
3041   GType *columns;
3042   int i;
3043   int items = 50;
3044   columns = g_new (GType, 2);
3045   columns[0] = G_TYPE_STRING;
3046   columns[1] = G_TYPE_BOOLEAN;
3047   store = gtk_tree_store_newv (2, columns);
3048   model = GTK_TREE_MODEL (store);
3049
3050   g_test_bug ("346800");
3051
3052   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
3053   gtk_tree_model_filter_set_visible_column (filter, 1);
3054
3055   for (i=0; i<items; i++)
3056     {
3057       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
3058
3059       g_malloc (138);
3060       gtk_tree_store_append (store, &node_iters[i], NULL);
3061       gtk_tree_store_set (store, &node_iters[i],
3062                           0, "something",
3063                           1, ((i%6) == 0) ? FALSE : TRUE,
3064                           -1);
3065
3066       g_malloc (47);
3067       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
3068       gtk_tree_store_set (store, &child_iters[i],
3069                           0, "something else",
3070                           1, FALSE,
3071                           -1);
3072       gtk_tree_model_filter_refilter (filter);
3073
3074       if (i > 6)
3075         {
3076           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
3077                               (i & 1) ? TRUE : FALSE, -1);
3078           gtk_tree_model_filter_refilter (filter);
3079
3080           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
3081                               (i & 1) ? FALSE: TRUE, -1);
3082           gtk_tree_model_filter_refilter (filter);
3083         }
3084     }
3085 }
3086
3087 static gboolean
3088 specific_bug_464173_visible_func (GtkTreeModel *model,
3089                                   GtkTreeIter  *iter,
3090                                   gpointer      data)
3091 {
3092   gboolean *visible = (gboolean *)data;
3093
3094   return *visible;
3095 }
3096
3097 static void
3098 specific_bug_464173 (void)
3099 {
3100   /* Test case for GNOME Bugzilla bug 464173, test case written
3101    * by Andreas Koehler.
3102    */
3103   GtkTreeStore *model;
3104   GtkTreeModelFilter *f_model;
3105   GtkTreeIter iter1, iter2;
3106   GtkWidget *view G_GNUC_UNUSED;
3107   gboolean visible = TRUE;
3108
3109   g_test_bug ("464173");
3110
3111   model = gtk_tree_store_new (1, G_TYPE_STRING);
3112   gtk_tree_store_append (model, &iter1, NULL);
3113   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
3114   gtk_tree_store_append (model, &iter2, &iter1);
3115   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
3116
3117   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
3118   gtk_tree_model_filter_set_visible_func (f_model,
3119                                           specific_bug_464173_visible_func,
3120                                           &visible, NULL);
3121
3122   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
3123
3124   visible = FALSE;
3125   gtk_tree_model_filter_refilter (f_model);
3126 }
3127
3128
3129 static gboolean
3130 specific_bug_540201_filter_func (GtkTreeModel *model,
3131                                  GtkTreeIter  *iter,
3132                                  gpointer      data)
3133 {
3134   gboolean has_children;
3135
3136   has_children = gtk_tree_model_iter_has_child (model, iter);
3137
3138   return has_children;
3139 }
3140
3141 static void
3142 specific_bug_540201 (void)
3143 {
3144   /* Test case for GNOME Bugzilla bug 540201, steps provided by
3145    * Charles Day.
3146    */
3147   GtkTreeIter iter, root;
3148   GtkTreeStore *store;
3149   GtkTreeModel *filter;
3150
3151   GtkWidget *tree_view G_GNUC_UNUSED;
3152
3153   g_test_bug ("540201");
3154
3155   store = gtk_tree_store_new (1, G_TYPE_INT);
3156
3157   gtk_tree_store_append (store, &root, NULL);
3158   gtk_tree_store_set (store, &root, 0, 33, -1);
3159
3160   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3161   tree_view = gtk_tree_view_new_with_model (filter);
3162
3163   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3164                                           specific_bug_540201_filter_func,
3165                                           NULL, NULL);
3166
3167   gtk_tree_store_append (store, &iter, &root);
3168   gtk_tree_store_set (store, &iter, 0, 50, -1);
3169
3170   gtk_tree_store_append (store, &iter, &root);
3171   gtk_tree_store_set (store, &iter, 0, 22, -1);
3172
3173
3174   gtk_tree_store_append (store, &root, NULL);
3175   gtk_tree_store_set (store, &root, 0, 33, -1);
3176
3177   gtk_tree_store_append (store, &iter, &root);
3178   gtk_tree_store_set (store, &iter, 0, 22, -1);
3179 }
3180
3181
3182 static gboolean
3183 specific_bug_549287_visible_func (GtkTreeModel *model,
3184                                   GtkTreeIter  *iter,
3185                                   gpointer      data)
3186 {
3187   gboolean result = FALSE;
3188
3189   result = gtk_tree_model_iter_has_child (model, iter);
3190
3191   return result;
3192 }
3193
3194 static void
3195 specific_bug_549287 (void)
3196 {
3197   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
3198
3199   int i;
3200   GtkTreeStore *store;
3201   GtkTreeModel *filtered;
3202   GtkWidget *view G_GNUC_UNUSED;
3203   GtkTreeIter iter;
3204   GtkTreeIter *swap, *parent, *child;
3205
3206   g_test_bug ("529287");
3207
3208   store = gtk_tree_store_new (1, G_TYPE_STRING);
3209   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3210   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
3211                                           specific_bug_549287_visible_func,
3212                                           NULL, NULL);
3213
3214   view = gtk_tree_view_new_with_model (filtered);
3215
3216   for (i = 0; i < 4; i++)
3217     {
3218       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
3219         {
3220           parent = gtk_tree_iter_copy (&iter);
3221           child = gtk_tree_iter_copy (&iter);
3222
3223           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
3224                                                 child, parent, 0))
3225             {
3226
3227               swap = parent;
3228               parent = child;
3229               child = swap;
3230             }
3231
3232           gtk_tree_store_append (store, child, parent);
3233           gtk_tree_store_set (store, child,
3234                               0, "Something",
3235                               -1);
3236
3237           gtk_tree_iter_free (parent);
3238           gtk_tree_iter_free (child);
3239         }
3240       else
3241         {
3242           gtk_tree_store_append (store, &iter, NULL);
3243           gtk_tree_store_set (store, &iter,
3244                               0, "Something",
3245                               -1);
3246         }
3247
3248       /* since we inserted something, we changed the visibility conditions: */
3249       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
3250     }
3251 }
3252
3253 /* main */
3254
3255 void
3256 register_filter_model_tests (void)
3257 {
3258   g_test_add ("/TreeModelFilter/self/verify-test-suite",
3259               FilterTest, NULL,
3260               filter_test_setup,
3261               verify_test_suite,
3262               filter_test_teardown);
3263
3264   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
3265               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3266               filter_test_setup,
3267               verify_test_suite_vroot,
3268               filter_test_teardown);
3269   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
3270               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
3271               filter_test_setup,
3272               verify_test_suite_vroot,
3273               filter_test_teardown);
3274
3275
3276   g_test_add ("/TreeModelFilter/filled/hide-root-level",
3277               FilterTest, NULL,
3278               filter_test_setup,
3279               filled_hide_root_level,
3280               filter_test_teardown);
3281   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
3282               FilterTest, NULL,
3283               filter_test_setup,
3284               filled_hide_child_levels,
3285               filter_test_teardown);
3286
3287   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
3288               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3289               filter_test_setup,
3290               filled_vroot_hide_root_level,
3291               filter_test_teardown);
3292   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
3293               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3294               filter_test_setup,
3295               filled_vroot_hide_child_levels,
3296               filter_test_teardown);
3297
3298
3299   g_test_add ("/TreeModelFilter/empty/show-nodes",
3300               FilterTest, NULL,
3301               filter_test_setup_empty,
3302               empty_show_nodes,
3303               filter_test_teardown);
3304   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
3305               FilterTest, NULL,
3306               filter_test_setup_empty,
3307               empty_show_multiple_nodes,
3308               filter_test_teardown);
3309
3310   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
3311               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3312               filter_test_setup_empty,
3313               empty_vroot_show_nodes,
3314               filter_test_teardown);
3315   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
3316               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3317               filter_test_setup_empty,
3318               empty_vroot_show_multiple_nodes,
3319               filter_test_teardown);
3320
3321
3322   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
3323               FilterTest, NULL,
3324               filter_test_setup_unfiltered,
3325               unfiltered_hide_single,
3326               filter_test_teardown);
3327   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
3328               FilterTest, NULL,
3329               filter_test_setup_unfiltered,
3330               unfiltered_hide_single_child,
3331               filter_test_teardown);
3332   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
3333               FilterTest, NULL,
3334               filter_test_setup_unfiltered,
3335               unfiltered_hide_single_multi_level,
3336               filter_test_teardown);
3337
3338   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
3339               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3340               filter_test_setup_unfiltered,
3341               unfiltered_vroot_hide_single,
3342               filter_test_teardown);
3343   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
3344               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3345               filter_test_setup_unfiltered,
3346               unfiltered_vroot_hide_single_child,
3347               filter_test_teardown);
3348   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
3349               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3350               filter_test_setup_unfiltered,
3351               unfiltered_vroot_hide_single_multi_level,
3352               filter_test_teardown);
3353
3354
3355
3356   g_test_add ("/TreeModelFilter/unfiltered/show-single",
3357               FilterTest, NULL,
3358               filter_test_setup_empty_unfiltered,
3359               unfiltered_show_single,
3360               filter_test_teardown);
3361   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
3362               FilterTest, NULL,
3363               filter_test_setup_empty_unfiltered,
3364               unfiltered_show_single_child,
3365               filter_test_teardown);
3366   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
3367               FilterTest, NULL,
3368               filter_test_setup_empty_unfiltered,
3369               unfiltered_show_single_multi_level,
3370               filter_test_teardown);
3371
3372   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
3373               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3374               filter_test_setup_empty_unfiltered,
3375               unfiltered_vroot_show_single,
3376               filter_test_teardown);
3377   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
3378               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3379               filter_test_setup_empty_unfiltered,
3380               unfiltered_vroot_show_single_child,
3381               filter_test_teardown);
3382   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
3383               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3384               filter_test_setup_empty_unfiltered,
3385               unfiltered_vroot_show_single_multi_level,
3386               filter_test_teardown);
3387
3388   /* Inserts in child models after creation of filter model */
3389   g_test_add_func ("/TreeModelFilter/insert/before",
3390                    insert_before);
3391   g_test_add_func ("/TreeModelFilter/insert/child",
3392                    insert_child);
3393
3394   /* Removals from child model after creating of filter model */
3395   g_test_add_func ("/TreeModelFilter/remove/node",
3396                    remove_node);
3397   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
3398                    remove_node_vroot);
3399   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
3400                    remove_vroot_ancestor);
3401
3402
3403   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
3404                    specific_path_dependent_filter);
3405   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
3406                    specific_append_after_collapse);
3407   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
3408                    specific_sort_filter_remove_node);
3409   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
3410                    specific_sort_filter_remove_root);
3411   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
3412                    specific_root_mixed_visibility);
3413   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
3414                    specific_has_child_filter);
3415   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
3416                    specific_root_has_child_filter);
3417   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
3418                    specific_filter_add_child);
3419   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
3420                    specific_list_store_clear);
3421   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
3422                    specific_sort_ref_leaf_and_remove_ancestor);
3423   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
3424                    specific_ref_leaf_and_remove_ancestor);
3425   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
3426                    specific_virtual_ref_leaf_and_remove_ancestor);
3427
3428   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
3429                    specific_bug_301558);
3430   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
3431                    specific_bug_311955);
3432   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
3433                    specific_bug_346800);
3434   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
3435                    specific_bug_464173);
3436   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
3437                    specific_bug_540201);
3438   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
3439                    specific_bug_549287);
3440 }