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