]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Have a separate category for tests of gtk_tree_model_filter_row_deleted
[~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   /* A bit nasty, apologies */
2388   FilterTest fixture;
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 = NULL;
2394
2395   /* We will filter on parent state using a filter function.  We will
2396    * manually keep the boolean column in sync, so that we can use
2397    * check_filter_model() to check the consistency of the model.
2398    */
2399   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2400    * to be able to check the structure here.  We keep the calls to
2401    * check_filter_model() commented out until then.
2402    */
2403   gtk_tree_model_filter_set_visible_func (fixture.filter,
2404                                           specific_has_child_filter_filter_func,
2405                                           NULL, NULL);
2406
2407   gtk_tree_store_append (fixture.store, &root, NULL);
2408   create_tree_store_set_values (fixture.store, &root, FALSE);
2409
2410   /* check_filter_model (&fixture); */
2411   check_level_length (fixture.filter, NULL, 0);
2412
2413   gtk_tree_store_append (fixture.store, &iter, &root);
2414   create_tree_store_set_values (fixture.store, &iter, TRUE);
2415
2416   /* Parent must now be visible.  Do the level length check first,
2417    * to avoid modifying the child model triggering a row-changed to
2418    * the filter model.
2419    */
2420   check_level_length (fixture.filter, NULL, 1);
2421   check_level_length (fixture.filter, "0", 0);
2422
2423   set_path_visibility (&fixture, "0", TRUE);
2424   /* check_filter_model (&fixture); */
2425
2426   gtk_tree_store_append (fixture.store, &root, NULL);
2427   check_level_length (fixture.filter, NULL, 1);
2428
2429   gtk_tree_store_append (fixture.store, &iter, &root);
2430   check_level_length (fixture.filter, NULL, 2);
2431   check_level_length (fixture.filter, "1", 0);
2432
2433   create_tree_store_set_values (fixture.store, &root, TRUE);
2434   create_tree_store_set_values (fixture.store, &iter, TRUE);
2435
2436   /* check_filter_model (&fixture); */
2437
2438   gtk_tree_store_append (fixture.store, &iter, &root);
2439   create_tree_store_set_values (fixture.store, &iter, TRUE);
2440   check_level_length (fixture.filter, NULL, 2);
2441   check_level_length (fixture.filter, "0", 0);
2442   check_level_length (fixture.filter, "1", 0);
2443
2444   /* Now remove one of the remaining child rows */
2445   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2446                                        &iter, "0:0");
2447   gtk_tree_store_remove (fixture.store, &iter);
2448
2449   check_level_length (fixture.filter, NULL, 1);
2450   check_level_length (fixture.filter, "0", 0);
2451
2452   set_path_visibility (&fixture, "0", FALSE);
2453   /* check_filter_model (&fixture); */
2454 }
2455
2456
2457 static gboolean
2458 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
2459                                             GtkTreeIter  *iter,
2460                                             gpointer      data)
2461 {
2462   int depth;
2463   GtkTreePath *path;
2464
2465   path = gtk_tree_model_get_path (model, iter);
2466   depth = gtk_tree_path_get_depth (path);
2467   gtk_tree_path_free (path);
2468
2469   if (depth > 1)
2470     return TRUE;
2471   /* else */
2472   return gtk_tree_model_iter_has_child (model, iter);
2473 }
2474
2475 static void
2476 specific_root_has_child_filter (void)
2477 {
2478   GtkTreeModel *filter;
2479   GtkTreeIter iter, root;
2480   /* A bit nasty, apologies */
2481   FilterTest fixture;
2482
2483   /* This is a variation on the above test case wherein the has-child
2484    * check for visibility only applies to root level nodes.
2485    */
2486
2487   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2488   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
2489   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
2490   fixture.monitor = NULL;
2491
2492   /* We will filter on parent state using a filter function.  We will
2493    * manually keep the boolean column in sync, so that we can use
2494    * check_filter_model() to check the consistency of the model.
2495    */
2496   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
2497    * to be able to check the structure here.  We keep the calls to
2498    * check_filter_model() commented out until then.
2499    */
2500   gtk_tree_model_filter_set_visible_func (fixture.filter,
2501                                           specific_root_has_child_filter_filter_func,
2502                                           NULL, NULL);
2503
2504   gtk_tree_store_append (fixture.store, &root, NULL);
2505   create_tree_store_set_values (fixture.store, &root, FALSE);
2506
2507   /* check_filter_model (&fixture); */
2508   check_level_length (fixture.filter, NULL, 0);
2509
2510   gtk_tree_store_append (fixture.store, &iter, &root);
2511   create_tree_store_set_values (fixture.store, &iter, TRUE);
2512
2513   /* Parent must now be visible.  Do the level length check first,
2514    * to avoid modifying the child model triggering a row-changed to
2515    * the filter model.
2516    */
2517   check_level_length (fixture.filter, NULL, 1);
2518   check_level_length (fixture.filter, "0", 1);
2519
2520   set_path_visibility (&fixture, "0", TRUE);
2521   /* check_filter_model (&fixture); */
2522
2523   gtk_tree_store_append (fixture.store, &root, NULL);
2524   check_level_length (fixture.filter, NULL, 1);
2525
2526   gtk_tree_store_append (fixture.store, &iter, &root);
2527   check_level_length (fixture.filter, NULL, 2);
2528   check_level_length (fixture.filter, "1", 1);
2529
2530   create_tree_store_set_values (fixture.store, &root, TRUE);
2531   create_tree_store_set_values (fixture.store, &iter, TRUE);
2532
2533   /* check_filter_model (&fixture); */
2534
2535   gtk_tree_store_append (fixture.store, &iter, &root);
2536   create_tree_store_set_values (fixture.store, &iter, TRUE);
2537   check_level_length (fixture.filter, NULL, 2);
2538   check_level_length (fixture.filter, "0", 1);
2539   check_level_length (fixture.filter, "1", 2);
2540
2541   /* Now remove one of the remaining child rows */
2542   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
2543                                        &iter, "0:0");
2544   gtk_tree_store_remove (fixture.store, &iter);
2545
2546   check_level_length (fixture.filter, NULL, 1);
2547   check_level_length (fixture.filter, "0", 2);
2548
2549   set_path_visibility (&fixture, "0", FALSE);
2550   /* check_filter_model (&fixture); */
2551 }
2552
2553
2554 static void
2555 specific_filter_add_child (void)
2556 {
2557   /* This test is based on one of the test cases I found in my
2558    * old test cases directory.  I unfortunately do not have a record
2559    * from who this test case originated.  -Kris.
2560    */
2561
2562   GtkTreeIter iter;
2563   GtkTreeIter iter_first;
2564   GtkTreeIter child;
2565   GtkTreeStore *store;
2566   GtkTreeModel *filter G_GNUC_UNUSED;
2567
2568   store = gtk_tree_store_new (1, G_TYPE_STRING);
2569
2570   gtk_tree_store_append (store, &iter_first, NULL);
2571   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
2572
2573   gtk_tree_store_append (store, &iter, NULL);
2574   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2575
2576   gtk_tree_store_append (store, &iter, NULL);
2577   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2578
2579   gtk_tree_store_append (store, &iter, NULL);
2580   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2581
2582   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2583
2584   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
2585   gtk_tree_store_append (store, &child, &iter_first);
2586   gtk_tree_store_set (store, &child, 0, "Hello", -1);
2587 }
2588
2589 static void
2590 specific_list_store_clear (void)
2591 {
2592   GtkTreeIter iter;
2593   GtkListStore *list;
2594   GtkTreeModel *filter;
2595   GtkWidget *view G_GNUC_UNUSED;
2596
2597   list = gtk_list_store_new (1, G_TYPE_INT);
2598   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
2599   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2600   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2601   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2602   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2603   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2604   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
2605   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
2606
2607   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2608   view = gtk_tree_view_new_with_model (filter);
2609
2610   gtk_list_store_clear (list);
2611 }
2612
2613 static void
2614 specific_sort_ref_leaf_and_remove_ancestor (void)
2615 {
2616   GtkTreeIter iter, child, child2, child3;
2617   GtkTreeStore *tree;
2618   GtkTreeModel *sort;
2619   GtkTreePath *path;
2620   GtkTreeRowReference *rowref;
2621   GtkWidget *view G_GNUC_UNUSED;
2622
2623   tree = gtk_tree_store_new (1, G_TYPE_INT);
2624   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2625   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2626   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2627   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2628
2629   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2630   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2631   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2632
2633   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2634   view = gtk_tree_view_new_with_model (sort);
2635   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2636
2637   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2638   rowref = gtk_tree_row_reference_new (sort, path);
2639   gtk_tree_path_free (path);
2640
2641   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2642   rowref = gtk_tree_row_reference_new (sort, path);
2643   gtk_tree_path_free (path);
2644
2645   path = gtk_tree_path_new_from_indices (3, 0, -1);
2646   rowref = gtk_tree_row_reference_new (sort, path);
2647   gtk_tree_path_free (path);
2648
2649   path = gtk_tree_path_new_from_indices (3, -1);
2650   rowref = gtk_tree_row_reference_new (sort, path);
2651   gtk_tree_path_free (path);
2652
2653   /* Deleting a parent */
2654   path = gtk_tree_path_new_from_indices (3, 0, -1);
2655   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2656   gtk_tree_store_remove (tree, &iter);
2657   gtk_tree_path_free (path);
2658
2659   gtk_tree_row_reference_free (rowref);
2660 }
2661
2662 static void
2663 specific_ref_leaf_and_remove_ancestor (void)
2664 {
2665   GtkTreeIter iter, child, child2, child3;
2666   GtkTreeStore *tree;
2667   GtkTreeModel *filter;
2668   GtkTreePath *path;
2669   GtkTreeRowReference *rowref;
2670   GtkWidget *view G_GNUC_UNUSED;
2671
2672   tree = gtk_tree_store_new (1, G_TYPE_INT);
2673   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2674   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2675   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2676   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2677
2678   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2679   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2680   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2681
2682   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
2683   view = gtk_tree_view_new_with_model (filter);
2684   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2685
2686   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2687   rowref = gtk_tree_row_reference_new (filter, path);
2688   gtk_tree_path_free (path);
2689
2690   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
2691   rowref = gtk_tree_row_reference_new (filter, path);
2692   gtk_tree_path_free (path);
2693
2694   path = gtk_tree_path_new_from_indices (3, 0, -1);
2695   rowref = gtk_tree_row_reference_new (filter, path);
2696   gtk_tree_path_free (path);
2697
2698   path = gtk_tree_path_new_from_indices (3, -1);
2699   rowref = gtk_tree_row_reference_new (filter, path);
2700   gtk_tree_path_free (path);
2701
2702   /* Deleting a parent */
2703   path = gtk_tree_path_new_from_indices (3, 0, -1);
2704   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2705   gtk_tree_store_remove (tree, &iter);
2706   gtk_tree_path_free (path);
2707
2708   gtk_tree_row_reference_free (rowref);
2709 }
2710
2711 static void
2712 specific_virtual_ref_leaf_and_remove_ancestor (void)
2713 {
2714   GtkTreeIter iter, child, child2, child3;
2715   GtkTreeStore *tree;
2716   GtkTreeModel *filter;
2717   GtkTreePath *path;
2718   GtkTreeRowReference *rowref;
2719   GtkWidget *view G_GNUC_UNUSED;
2720
2721   tree = gtk_tree_store_new (1, G_TYPE_INT);
2722   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
2723   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
2724   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
2725   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
2726
2727   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
2728   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
2729   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
2730
2731   /* Set a virtual root of 3:0 */
2732   path = gtk_tree_path_new_from_indices (3, 0, -1);
2733   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2734   gtk_tree_path_free (path);
2735
2736   view = gtk_tree_view_new_with_model (filter);
2737   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
2738
2739   path = gtk_tree_path_new_from_indices (0, 0, -1);
2740   rowref = gtk_tree_row_reference_new (filter, path);
2741   gtk_tree_path_free (path);
2742
2743   path = gtk_tree_path_new_from_indices (0, 0, -1);
2744   rowref = gtk_tree_row_reference_new (filter, path);
2745   gtk_tree_path_free (path);
2746
2747   path = gtk_tree_path_new_from_indices (0, -1);
2748   rowref = gtk_tree_row_reference_new (filter, path);
2749   gtk_tree_path_free (path);
2750
2751   /* Deleting the virtual root */
2752   path = gtk_tree_path_new_from_indices (3, 0, -1);
2753   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
2754   gtk_tree_store_remove (tree, &iter);
2755   gtk_tree_path_free (path);
2756
2757   gtk_tree_row_reference_free (rowref);
2758 }
2759
2760
2761 static int
2762 specific_bug_301558_sort_func (GtkTreeModel *model,
2763                                GtkTreeIter  *a,
2764                                GtkTreeIter  *b,
2765                                gpointer      data)
2766 {
2767   int i, j;
2768
2769   gtk_tree_model_get (model, a, 0, &i, -1);
2770   gtk_tree_model_get (model, b, 0, &j, -1);
2771
2772   return j - i;
2773 }
2774
2775 static void
2776 specific_bug_301558 (void)
2777 {
2778   /* Test case for GNOME Bugzilla bug 301558 provided by
2779    * Markku Vire.
2780    */
2781   GtkTreeStore *tree;
2782   GtkTreeModel *filter;
2783   GtkTreeModel *sort;
2784   GtkTreeIter root, iter, iter2;
2785   GtkWidget *view G_GNUC_UNUSED;
2786   int i;
2787   gboolean add;
2788
2789   g_test_bug ("301558");
2790
2791   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
2792   gtk_tree_store_append (tree, &iter, NULL);
2793   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
2794   gtk_tree_store_append (tree, &iter2, &iter);
2795   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
2796
2797   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
2798   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
2799                                            specific_bug_301558_sort_func,
2800                                            NULL, NULL);
2801
2802   filter = gtk_tree_model_filter_new (sort, NULL);
2803   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
2804
2805   view = gtk_tree_view_new_with_model (filter);
2806
2807   while (gtk_events_pending ())
2808     gtk_main_iteration ();
2809
2810   add = TRUE;
2811
2812   for (i = 0; i < 10; i++)
2813     {
2814       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
2815         g_assert_not_reached ();
2816
2817       if (add)
2818         {
2819           gtk_tree_store_append (tree, &iter, &root);
2820           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
2821         }
2822       else
2823         {
2824           int n;
2825           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
2826           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
2827                                          &root, n - 1);
2828           gtk_tree_store_remove (tree, &iter);
2829         }
2830
2831       add = !add;
2832     }
2833 }
2834
2835
2836 static gboolean
2837 specific_bug_311955_filter_func (GtkTreeModel *model,
2838                                  GtkTreeIter  *iter,
2839                                  gpointer      data)
2840 {
2841   int value;
2842
2843   gtk_tree_model_get (model, iter, 0, &value, -1);
2844
2845   return (value != 0);
2846 }
2847
2848 static void
2849 specific_bug_311955 (void)
2850 {
2851   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
2852    * by Markku Vire.
2853    */
2854   GtkTreeIter iter, child, root;
2855   GtkTreeStore *store;
2856   GtkTreeModel *sort;
2857   GtkTreeModel *filter;
2858
2859   GtkWidget *window G_GNUC_UNUSED;
2860   GtkWidget *tree_view;
2861   int i;
2862   int n;
2863
2864   g_test_bug ("311955");
2865
2866   store = gtk_tree_store_new (1, G_TYPE_INT);
2867
2868   gtk_tree_store_append (store, &root, NULL);
2869   gtk_tree_store_set (store, &root, 0, 33, -1);
2870
2871   gtk_tree_store_append (store, &iter, &root);
2872   gtk_tree_store_set (store, &iter, 0, 50, -1);
2873
2874   gtk_tree_store_append (store, &iter, NULL);
2875   gtk_tree_store_set (store, &iter, 0, 22, -1);
2876
2877   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
2878   filter = gtk_tree_model_filter_new (sort, NULL);
2879
2880   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
2881                                           specific_bug_311955_filter_func,
2882                                           NULL, NULL);
2883
2884   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2885   tree_view = gtk_tree_view_new_with_model (filter);
2886   g_object_unref (store);
2887
2888   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2889
2890   while (gtk_events_pending ())
2891     gtk_main_iteration ();
2892
2893   /* Fill model */
2894   for (i = 0; i < 4; i++)
2895     {
2896       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
2897
2898       gtk_tree_store_append (store, &iter, &root);
2899
2900       if (i < 3)
2901         gtk_tree_store_set (store, &iter, 0, i, -1);
2902
2903       if (i % 2 == 0)
2904         {
2905           gtk_tree_store_append (store, &child, &iter);
2906           gtk_tree_store_set (store, &child, 0, 10, -1);
2907         }
2908     }
2909
2910   while (gtk_events_pending ())
2911     gtk_main_iteration ();
2912
2913   /* Remove bottommost child from the tree. */
2914   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
2915   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
2916
2917   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
2918     {
2919       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
2920         gtk_tree_store_remove (store, &child);
2921     }
2922   else
2923     g_assert_not_reached ();
2924 }
2925
2926 static void
2927 specific_bug_346800 (void)
2928 {
2929   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
2930    * by Jonathan Matthew.
2931    */
2932
2933   GtkTreeIter node_iters[50];
2934   GtkTreeIter child_iters[50];
2935   GtkTreeModel *model;
2936   GtkTreeModelFilter *filter;
2937   GtkTreeStore *store;
2938   GType *columns;
2939   int i;
2940   int items = 50;
2941   columns = g_new (GType, 2);
2942   columns[0] = G_TYPE_STRING;
2943   columns[1] = G_TYPE_BOOLEAN;
2944   store = gtk_tree_store_newv (2, columns);
2945   model = GTK_TREE_MODEL (store);
2946
2947   g_test_bug ("346800");
2948
2949   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
2950   gtk_tree_model_filter_set_visible_column (filter, 1);
2951
2952   for (i=0; i<items; i++)
2953     {
2954       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
2955
2956       g_malloc (138);
2957       gtk_tree_store_append (store, &node_iters[i], NULL);
2958       gtk_tree_store_set (store, &node_iters[i],
2959                           0, "something",
2960                           1, ((i%6) == 0) ? FALSE : TRUE,
2961                           -1);
2962
2963       g_malloc (47);
2964       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
2965       gtk_tree_store_set (store, &child_iters[i],
2966                           0, "something else",
2967                           1, FALSE,
2968                           -1);
2969       gtk_tree_model_filter_refilter (filter);
2970
2971       if (i > 6)
2972         {
2973           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
2974                               (i & 1) ? TRUE : FALSE, -1);
2975           gtk_tree_model_filter_refilter (filter);
2976
2977           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
2978                               (i & 1) ? FALSE: TRUE, -1);
2979           gtk_tree_model_filter_refilter (filter);
2980         }
2981     }
2982 }
2983
2984 static gboolean
2985 specific_bug_464173_visible_func (GtkTreeModel *model,
2986                                   GtkTreeIter  *iter,
2987                                   gpointer      data)
2988 {
2989   gboolean *visible = (gboolean *)data;
2990
2991   return *visible;
2992 }
2993
2994 static void
2995 specific_bug_464173 (void)
2996 {
2997   /* Test case for GNOME Bugzilla bug 464173, test case written
2998    * by Andreas Koehler.
2999    */
3000   GtkTreeStore *model;
3001   GtkTreeModelFilter *f_model;
3002   GtkTreeIter iter1, iter2;
3003   GtkWidget *view G_GNUC_UNUSED;
3004   gboolean visible = TRUE;
3005
3006   g_test_bug ("464173");
3007
3008   model = gtk_tree_store_new (1, G_TYPE_STRING);
3009   gtk_tree_store_append (model, &iter1, NULL);
3010   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
3011   gtk_tree_store_append (model, &iter2, &iter1);
3012   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
3013
3014   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
3015   gtk_tree_model_filter_set_visible_func (f_model,
3016                                           specific_bug_464173_visible_func,
3017                                           &visible, NULL);
3018
3019   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
3020
3021   visible = FALSE;
3022   gtk_tree_model_filter_refilter (f_model);
3023 }
3024
3025
3026 static gboolean
3027 specific_bug_540201_filter_func (GtkTreeModel *model,
3028                                  GtkTreeIter  *iter,
3029                                  gpointer      data)
3030 {
3031   gboolean has_children;
3032
3033   has_children = gtk_tree_model_iter_has_child (model, iter);
3034
3035   return has_children;
3036 }
3037
3038 static void
3039 specific_bug_540201 (void)
3040 {
3041   /* Test case for GNOME Bugzilla bug 540201, steps provided by
3042    * Charles Day.
3043    */
3044   GtkTreeIter iter, root;
3045   GtkTreeStore *store;
3046   GtkTreeModel *filter;
3047
3048   GtkWidget *tree_view G_GNUC_UNUSED;
3049
3050   g_test_bug ("540201");
3051
3052   store = gtk_tree_store_new (1, G_TYPE_INT);
3053
3054   gtk_tree_store_append (store, &root, NULL);
3055   gtk_tree_store_set (store, &root, 0, 33, -1);
3056
3057   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3058   tree_view = gtk_tree_view_new_with_model (filter);
3059
3060   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3061                                           specific_bug_540201_filter_func,
3062                                           NULL, NULL);
3063
3064   gtk_tree_store_append (store, &iter, &root);
3065   gtk_tree_store_set (store, &iter, 0, 50, -1);
3066
3067   gtk_tree_store_append (store, &iter, &root);
3068   gtk_tree_store_set (store, &iter, 0, 22, -1);
3069
3070
3071   gtk_tree_store_append (store, &root, NULL);
3072   gtk_tree_store_set (store, &root, 0, 33, -1);
3073
3074   gtk_tree_store_append (store, &iter, &root);
3075   gtk_tree_store_set (store, &iter, 0, 22, -1);
3076 }
3077
3078
3079 static gboolean
3080 specific_bug_549287_visible_func (GtkTreeModel *model,
3081                                   GtkTreeIter  *iter,
3082                                   gpointer      data)
3083 {
3084   gboolean result = FALSE;
3085
3086   result = gtk_tree_model_iter_has_child (model, iter);
3087
3088   return result;
3089 }
3090
3091 static void
3092 specific_bug_549287 (void)
3093 {
3094   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
3095
3096   int i;
3097   GtkTreeStore *store;
3098   GtkTreeModel *filtered;
3099   GtkWidget *view G_GNUC_UNUSED;
3100   GtkTreeIter iter;
3101   GtkTreeIter *swap, *parent, *child;
3102
3103   g_test_bug ("529287");
3104
3105   store = gtk_tree_store_new (1, G_TYPE_STRING);
3106   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3107   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
3108                                           specific_bug_549287_visible_func,
3109                                           NULL, NULL);
3110
3111   view = gtk_tree_view_new_with_model (filtered);
3112
3113   for (i = 0; i < 4; i++)
3114     {
3115       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
3116         {
3117           parent = gtk_tree_iter_copy (&iter);
3118           child = gtk_tree_iter_copy (&iter);
3119
3120           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
3121                                                 child, parent, 0))
3122             {
3123
3124               swap = parent;
3125               parent = child;
3126               child = swap;
3127             }
3128
3129           gtk_tree_store_append (store, child, parent);
3130           gtk_tree_store_set (store, child,
3131                               0, "Something",
3132                               -1);
3133
3134           gtk_tree_iter_free (parent);
3135           gtk_tree_iter_free (child);
3136         }
3137       else
3138         {
3139           gtk_tree_store_append (store, &iter, NULL);
3140           gtk_tree_store_set (store, &iter,
3141                               0, "Something",
3142                               -1);
3143         }
3144
3145       /* since we inserted something, we changed the visibility conditions: */
3146       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
3147     }
3148 }
3149
3150 /* main */
3151
3152 void
3153 register_filter_model_tests (void)
3154 {
3155   g_test_add ("/TreeModelFilter/self/verify-test-suite",
3156               FilterTest, NULL,
3157               filter_test_setup,
3158               verify_test_suite,
3159               filter_test_teardown);
3160
3161   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
3162               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3163               filter_test_setup,
3164               verify_test_suite_vroot,
3165               filter_test_teardown);
3166   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
3167               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
3168               filter_test_setup,
3169               verify_test_suite_vroot,
3170               filter_test_teardown);
3171
3172
3173   g_test_add ("/TreeModelFilter/filled/hide-root-level",
3174               FilterTest, NULL,
3175               filter_test_setup,
3176               filled_hide_root_level,
3177               filter_test_teardown);
3178   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
3179               FilterTest, NULL,
3180               filter_test_setup,
3181               filled_hide_child_levels,
3182               filter_test_teardown);
3183
3184   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
3185               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3186               filter_test_setup,
3187               filled_vroot_hide_root_level,
3188               filter_test_teardown);
3189   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
3190               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3191               filter_test_setup,
3192               filled_vroot_hide_child_levels,
3193               filter_test_teardown);
3194
3195
3196   g_test_add ("/TreeModelFilter/empty/show-nodes",
3197               FilterTest, NULL,
3198               filter_test_setup_empty,
3199               empty_show_nodes,
3200               filter_test_teardown);
3201   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
3202               FilterTest, NULL,
3203               filter_test_setup_empty,
3204               empty_show_multiple_nodes,
3205               filter_test_teardown);
3206
3207   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
3208               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3209               filter_test_setup_empty,
3210               empty_vroot_show_nodes,
3211               filter_test_teardown);
3212   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
3213               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3214               filter_test_setup_empty,
3215               empty_vroot_show_multiple_nodes,
3216               filter_test_teardown);
3217
3218
3219   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
3220               FilterTest, NULL,
3221               filter_test_setup_unfiltered,
3222               unfiltered_hide_single,
3223               filter_test_teardown);
3224   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
3225               FilterTest, NULL,
3226               filter_test_setup_unfiltered,
3227               unfiltered_hide_single_child,
3228               filter_test_teardown);
3229   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
3230               FilterTest, NULL,
3231               filter_test_setup_unfiltered,
3232               unfiltered_hide_single_multi_level,
3233               filter_test_teardown);
3234
3235   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
3236               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3237               filter_test_setup_unfiltered,
3238               unfiltered_vroot_hide_single,
3239               filter_test_teardown);
3240   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
3241               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3242               filter_test_setup_unfiltered,
3243               unfiltered_vroot_hide_single_child,
3244               filter_test_teardown);
3245   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
3246               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3247               filter_test_setup_unfiltered,
3248               unfiltered_vroot_hide_single_multi_level,
3249               filter_test_teardown);
3250
3251
3252
3253   g_test_add ("/TreeModelFilter/unfiltered/show-single",
3254               FilterTest, NULL,
3255               filter_test_setup_empty_unfiltered,
3256               unfiltered_show_single,
3257               filter_test_teardown);
3258   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
3259               FilterTest, NULL,
3260               filter_test_setup_empty_unfiltered,
3261               unfiltered_show_single_child,
3262               filter_test_teardown);
3263   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
3264               FilterTest, NULL,
3265               filter_test_setup_empty_unfiltered,
3266               unfiltered_show_single_multi_level,
3267               filter_test_teardown);
3268
3269   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
3270               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3271               filter_test_setup_empty_unfiltered,
3272               unfiltered_vroot_show_single,
3273               filter_test_teardown);
3274   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
3275               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3276               filter_test_setup_empty_unfiltered,
3277               unfiltered_vroot_show_single_child,
3278               filter_test_teardown);
3279   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
3280               FilterTest, gtk_tree_path_new_from_indices (2, -1),
3281               filter_test_setup_empty_unfiltered,
3282               unfiltered_vroot_show_single_multi_level,
3283               filter_test_teardown);
3284
3285   /* Inserts in child models after creation of filter model */
3286   g_test_add_func ("/TreeModelFilter/insert/before",
3287                    insert_before);
3288   g_test_add_func ("/TreeModelFilter/insert/child",
3289                    insert_child);
3290
3291   /* Removals from child model after creating of filter model */
3292   g_test_add_func ("/TreeModelFilter/remove/node",
3293                    remove_node);
3294   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
3295                    remove_node_vroot);
3296   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
3297                    remove_vroot_ancestor);
3298
3299
3300   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
3301                    specific_path_dependent_filter);
3302   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
3303                    specific_append_after_collapse);
3304   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
3305                    specific_sort_filter_remove_node);
3306   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
3307                    specific_sort_filter_remove_root);
3308   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
3309                    specific_root_mixed_visibility);
3310   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
3311                    specific_has_child_filter);
3312   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
3313                    specific_root_has_child_filter);
3314   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
3315                    specific_filter_add_child);
3316   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
3317                    specific_list_store_clear);
3318   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
3319                    specific_sort_ref_leaf_and_remove_ancestor);
3320   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
3321                    specific_ref_leaf_and_remove_ancestor);
3322   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
3323                    specific_virtual_ref_leaf_and_remove_ancestor);
3324
3325   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
3326                    specific_bug_301558);
3327   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
3328                    specific_bug_311955);
3329   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
3330                    specific_bug_346800);
3331   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
3332                    specific_bug_464173);
3333   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
3334                    specific_bug_540201);
3335   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
3336                    specific_bug_549287);
3337 }