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