]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
Remove unused variable
[~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 /*
24  * Model creation
25  */
26
27 #define LEVEL_LENGTH 5
28
29 static void
30 create_tree_store_set_values (GtkTreeStore *store,
31                               GtkTreeIter  *iter,
32                               gboolean      visible)
33 {
34   GtkTreePath *path;
35
36   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
37   gtk_tree_store_set (store, iter,
38                       0, gtk_tree_path_to_string (path),
39                       1, visible,
40                       -1);
41   gtk_tree_path_free (path);
42 }
43
44 static void
45 create_tree_store_recurse (int           depth,
46                            GtkTreeStore *store,
47                            GtkTreeIter  *parent,
48                            gboolean      visible)
49 {
50   int i;
51
52   for (i = 0; i < LEVEL_LENGTH; i++)
53     {
54       GtkTreeIter iter;
55
56       gtk_tree_store_insert (store, &iter, parent, i);
57       create_tree_store_set_values (store, &iter, visible);
58
59       if (depth > 0)
60         create_tree_store_recurse (depth - 1, store, &iter, visible);
61     }
62 }
63
64 static GtkTreeStore *
65 create_tree_store (int      depth,
66                    gboolean visible)
67 {
68   GtkTreeStore *store;
69
70   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
71
72   create_tree_store_recurse (depth, store, NULL, visible);
73
74   return store;
75 }
76
77
78 /*
79  * Fixture
80  */
81
82 typedef struct
83 {
84   GtkWidget *tree_view;
85
86   GtkTreeStore *store;
87   GtkTreeModelFilter *filter;
88 } FilterTest;
89
90 static void
91 filter_test_setup_generic (FilterTest    *fixture,
92                            gconstpointer  test_data,
93                            int            depth,
94                            gboolean       empty,
95                            gboolean       unfiltered)
96 {
97   const GtkTreePath *vroot = test_data;
98   GtkTreeModel *filter;
99
100   fixture->store = create_tree_store (depth, !empty);
101
102   /* Please forgive me for casting const away. */
103   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
104                                       (GtkTreePath *)vroot);
105   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
106
107   if (!unfiltered)
108     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
109
110   /* We need a tree view that's listening to get ref counting from that
111    * side.
112    */
113   fixture->tree_view = gtk_tree_view_new_with_model (filter);
114 }
115
116 static void
117 filter_test_setup (FilterTest    *fixture,
118                    gconstpointer  test_data)
119 {
120   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
121 }
122
123 static void
124 filter_test_setup_empty (FilterTest    *fixture,
125                          gconstpointer  test_data)
126 {
127   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
128 }
129
130 static void
131 filter_test_setup_unfiltered (FilterTest    *fixture,
132                               gconstpointer  test_data)
133 {
134   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
135 }
136
137 static void
138 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
139                                     gconstpointer  test_data)
140 {
141   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
142 }
143
144 static void
145 filter_test_enable_filter (FilterTest *fixture)
146 {
147   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
148   gtk_tree_model_filter_refilter (fixture->filter);
149 }
150
151 static void
152 filter_test_teardown (FilterTest    *fixture,
153                       gconstpointer  test_data)
154 {
155   g_object_unref (fixture->filter);
156   g_object_unref (fixture->store);
157 }
158
159 /*
160  * Model structure validation
161  */
162
163 static void
164 check_filter_model_recurse (FilterTest  *fixture,
165                             GtkTreePath *store_parent_path,
166                             GtkTreePath *filter_parent_path)
167 {
168   int i;
169   GtkTreeIter store_iter;
170   GtkTreeIter filter_iter;
171   gboolean store_has_next, filter_has_next;
172
173   gtk_tree_path_down (store_parent_path);
174   gtk_tree_path_down (filter_parent_path);
175
176   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
177                                             &store_iter, store_parent_path);
178   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
179                                              &filter_iter, filter_parent_path);
180
181   for (i = 0; i < LEVEL_LENGTH; i++)
182     {
183       gboolean visible;
184
185       g_return_if_fail (store_has_next == TRUE);
186
187       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
188                           &store_iter,
189                           1, &visible,
190                           -1);
191
192       if (visible)
193         {
194           GtkTreePath *tmp;
195           gchar *filter_str, *store_str;
196
197           g_return_if_fail (filter_has_next == TRUE);
198
199           /* Verify path */
200           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
201                                          &filter_iter);
202           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
203
204           /* Verify model content */
205           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
206                               &store_iter,
207                               0, &store_str,
208                               -1);
209           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
210                               &filter_iter,
211                               0, &filter_str,
212                               -1);
213
214           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
215
216           g_free (store_str);
217           g_free (filter_str);
218
219           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
220                                              &filter_iter))
221             {
222               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
223
224               check_filter_model_recurse (fixture,
225                                           gtk_tree_path_copy (store_parent_path),
226                                           tmp);
227             }
228
229           gtk_tree_path_next (filter_parent_path);
230           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
231         }
232
233       gtk_tree_path_next (store_parent_path);
234       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
235     }
236
237   /* Both models should have no more content! */
238   g_return_if_fail (store_has_next == FALSE);
239   g_return_if_fail (filter_has_next == FALSE);
240
241   gtk_tree_path_free (store_parent_path);
242   gtk_tree_path_free (filter_parent_path);
243 }
244
245 static void
246 check_filter_model (FilterTest *fixture)
247 {
248   GtkTreePath *path;
249
250   path = gtk_tree_path_new ();
251
252   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
253 }
254
255 static void
256 check_filter_model_with_root (FilterTest  *fixture,
257                               GtkTreePath *path)
258 {
259   check_filter_model_recurse (fixture,
260                               gtk_tree_path_copy (path),
261                               gtk_tree_path_new ());
262 }
263
264 /* Helpers */
265
266 static void
267 check_level_length (GtkTreeModelFilter *filter,
268                     const gchar        *level,
269                     const int           length)
270 {
271   if (!level)
272     {
273       int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
274       g_return_if_fail (l == length);
275     }
276   else
277     {
278       int l;
279       gboolean retrieved_iter = FALSE;
280       GtkTreeIter iter;
281
282       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
283                                                             &iter, level);
284       g_return_if_fail (retrieved_iter);
285       l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
286       g_return_if_fail (l == length);
287     }
288 }
289
290 static void
291 set_path_visibility (FilterTest  *fixture,
292                      const gchar *path,
293                      gboolean     visible)
294 {
295   GtkTreeIter store_iter;
296
297   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
298                                        &store_iter, path);
299   gtk_tree_store_set (fixture->store, &store_iter,
300                       1, visible,
301                       -1);
302 }
303
304 static void
305 insert_path_with_visibility (FilterTest  *fixture,
306                              const gchar *path_string,
307                              gboolean     visible)
308 {
309   int position;
310   GtkTreePath *path;
311   GtkTreeIter parent, iter;
312
313   path = gtk_tree_path_new_from_string (path_string);
314   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
315   gtk_tree_path_up (path);
316
317   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
318     {
319       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
320       create_tree_store_set_values (fixture->store, &iter, visible);
321     }
322   gtk_tree_path_free (path);
323 }
324
325 /*
326  * The actual tests.
327  */
328
329 static void
330 verify_test_suite (FilterTest    *fixture,
331                    gconstpointer  user_data)
332 {
333   check_filter_model (fixture);
334 }
335
336 static void
337 verify_test_suite_vroot (FilterTest    *fixture,
338                          gconstpointer  user_data)
339 {
340   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
341 }
342
343
344 static void
345 filled_hide_root_level (FilterTest    *fixture,
346                         gconstpointer  user_data)
347 {
348   set_path_visibility (fixture, "2", FALSE);
349   check_filter_model (fixture);
350   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
351
352   set_path_visibility (fixture, "0", FALSE);
353   check_filter_model (fixture);
354   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
355
356   set_path_visibility (fixture, "4", FALSE);
357   check_filter_model (fixture);
358   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
359
360
361   /* Hide remaining */
362   set_path_visibility (fixture, "1", FALSE);
363   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
364
365   set_path_visibility (fixture, "3", FALSE);
366   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
367
368   check_filter_model (fixture);
369
370   /* Show some */
371   set_path_visibility (fixture, "1", TRUE);
372   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
373
374   set_path_visibility (fixture, "3", TRUE);
375   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
376
377   check_filter_model (fixture);
378 }
379
380 static void
381 filled_hide_child_levels (FilterTest    *fixture,
382                           gconstpointer  user_data)
383 {
384   set_path_visibility (fixture, "0:2", FALSE);
385   check_filter_model (fixture);
386   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
387   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
388
389   set_path_visibility (fixture, "0:4", FALSE);
390   check_filter_model (fixture);
391   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
392   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
393
394   set_path_visibility (fixture, "0:4:3", FALSE);
395   check_filter_model (fixture);
396   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
397   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
398
399   set_path_visibility (fixture, "0:4:0", FALSE);
400   set_path_visibility (fixture, "0:4:1", FALSE);
401   set_path_visibility (fixture, "0:4:2", FALSE);
402   set_path_visibility (fixture, "0:4:4", FALSE);
403   check_filter_model (fixture);
404   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
405   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
406
407   set_path_visibility (fixture, "0:4", TRUE);
408   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
409   check_filter_model (fixture);
410   check_level_length (fixture->filter, "0:3", 0);
411
412   set_path_visibility (fixture, "0:2", TRUE);
413   check_filter_model (fixture);
414   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
415   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
416   check_level_length (fixture->filter, "0:4", 0);
417
418   set_path_visibility (fixture, "0:4:2", TRUE);
419   set_path_visibility (fixture, "0:4:4", TRUE);
420   check_level_length (fixture->filter, "0:4", 2);
421 }
422
423
424 static void
425 filled_vroot_hide_root_level (FilterTest    *fixture,
426                               gconstpointer  user_data)
427 {
428   GtkTreePath *path = (GtkTreePath *)user_data;
429
430   /* These changes do not affect the filter's root level */
431   set_path_visibility (fixture, "0", FALSE);
432   check_filter_model_with_root (fixture, path);
433   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
434   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
435
436   set_path_visibility (fixture, "4", FALSE);
437   check_filter_model_with_root (fixture, path);
438   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
439   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
440
441   /* Even though we set the virtual root parent node to FALSE,
442    * the virtual root contents remain.
443    */
444   set_path_visibility (fixture, "2", FALSE);
445   check_filter_model_with_root (fixture, path);
446   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
447   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
448
449   /* No change */
450   set_path_visibility (fixture, "1", FALSE);
451   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
452   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
453
454   set_path_visibility (fixture, "3", FALSE);
455   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
456   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
457
458   check_filter_model_with_root (fixture, path);
459
460   /* Show some */
461   set_path_visibility (fixture, "2", TRUE);
462   check_filter_model_with_root (fixture, path);
463   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
464   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
465
466   set_path_visibility (fixture, "1", TRUE);
467   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
468   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
469
470   set_path_visibility (fixture, "3", TRUE);
471   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
472   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
473
474   check_filter_model_with_root (fixture, path);
475
476   /* Now test changes in the virtual root level */
477   set_path_visibility (fixture, "2:2", FALSE);
478   check_filter_model_with_root (fixture, path);
479   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
480
481   set_path_visibility (fixture, "2:4", FALSE);
482   check_filter_model_with_root (fixture, path);
483   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
484
485   set_path_visibility (fixture, "1:4", FALSE);
486   check_filter_model_with_root (fixture, path);
487   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
488
489   set_path_visibility (fixture, "2:4", TRUE);
490   check_filter_model_with_root (fixture, path);
491   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
492
493   set_path_visibility (fixture, "2", FALSE);
494   check_filter_model_with_root (fixture, path);
495   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
496
497   set_path_visibility (fixture, "2:0", FALSE);
498   set_path_visibility (fixture, "2:1", FALSE);
499   set_path_visibility (fixture, "2:2", FALSE);
500   set_path_visibility (fixture, "2:3", FALSE);
501   set_path_visibility (fixture, "2:4", FALSE);
502   check_filter_model_with_root (fixture, path);
503   check_level_length (fixture->filter, NULL, 0);
504
505   set_path_visibility (fixture, "2", TRUE);
506   check_filter_model_with_root (fixture, path);
507   check_level_length (fixture->filter, NULL, 0);
508
509   set_path_visibility (fixture, "1:4", FALSE);
510   check_filter_model_with_root (fixture, path);
511   check_level_length (fixture->filter, NULL, 0);
512
513   set_path_visibility (fixture, "2:4", TRUE);
514   check_filter_model_with_root (fixture, path);
515   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
516
517   set_path_visibility (fixture, "2:4", FALSE);
518   check_filter_model_with_root (fixture, path);
519   check_level_length (fixture->filter, NULL, 0);
520
521   set_path_visibility (fixture, "2", FALSE);
522   check_filter_model_with_root (fixture, path);
523   check_level_length (fixture->filter, NULL, 0);
524
525   set_path_visibility (fixture, "2:0", TRUE);
526   set_path_visibility (fixture, "2:1", TRUE);
527   set_path_visibility (fixture, "2:2", TRUE);
528   check_filter_model_with_root (fixture, path);
529   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
530
531   set_path_visibility (fixture, "2", TRUE);
532   check_filter_model_with_root (fixture, path);
533   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
534 }
535
536 static void
537 filled_vroot_hide_child_levels (FilterTest    *fixture,
538                                 gconstpointer  user_data)
539 {
540   GtkTreePath *path = (GtkTreePath *)user_data;
541
542   set_path_visibility (fixture, "2:0:2", FALSE);
543   check_filter_model_with_root (fixture, path);
544   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
545   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
546
547   set_path_visibility (fixture, "2:0:4", FALSE);
548   check_filter_model_with_root (fixture, path);
549   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
550   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
551
552   set_path_visibility (fixture, "2:0:4:3", FALSE);
553   check_filter_model_with_root (fixture, path);
554   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
555   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
556
557   set_path_visibility (fixture, "2:0:4:0", FALSE);
558   set_path_visibility (fixture, "2:0:4:1", FALSE);
559   set_path_visibility (fixture, "2:0:4:2", FALSE);
560   set_path_visibility (fixture, "2:0:4:4", FALSE);
561   check_filter_model_with_root (fixture, path);
562   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
563   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
564
565   set_path_visibility (fixture, "2:0:4", TRUE);
566   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
567   check_filter_model_with_root (fixture, path);
568   check_level_length (fixture->filter, "0:3", 0);
569
570   set_path_visibility (fixture, "2:0:2", TRUE);
571   check_filter_model_with_root (fixture, path);
572   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
573   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
574   check_level_length (fixture->filter, "0:4", 0);
575
576   set_path_visibility (fixture, "2:0:4:2", TRUE);
577   set_path_visibility (fixture, "2:0:4:4", TRUE);
578   check_level_length (fixture->filter, "0:4", 2);
579 }
580
581
582 static void
583 empty_show_nodes (FilterTest    *fixture,
584                   gconstpointer  user_data)
585 {
586   check_filter_model (fixture);
587   check_level_length (fixture->filter, NULL, 0);
588
589   set_path_visibility (fixture, "3", TRUE);
590   check_filter_model (fixture);
591   check_level_length (fixture->filter, NULL, 1);
592   check_level_length (fixture->filter, "0", 0);
593
594   set_path_visibility (fixture, "3:2:2", TRUE);
595   check_filter_model (fixture);
596   check_level_length (fixture->filter, NULL, 1);
597   check_level_length (fixture->filter, "0", 0);
598
599   set_path_visibility (fixture, "3:2", TRUE);
600   check_filter_model (fixture);
601   check_level_length (fixture->filter, NULL, 1);
602   check_level_length (fixture->filter, "0", 1);
603   check_level_length (fixture->filter, "0:0", 1);
604   check_level_length (fixture->filter, "0:0:0", 0);
605
606   set_path_visibility (fixture, "3", FALSE);
607   check_filter_model (fixture);
608   check_level_length (fixture->filter, NULL, 0);
609
610   set_path_visibility (fixture, "3:2:1", TRUE);
611   set_path_visibility (fixture, "3", TRUE);
612   check_filter_model (fixture);
613   check_level_length (fixture->filter, NULL, 1);
614   check_level_length (fixture->filter, "0", 1);
615   check_level_length (fixture->filter, "0:0", 2);
616   check_level_length (fixture->filter, "0:0:0", 0);
617 }
618
619 static void
620 empty_vroot_show_nodes (FilterTest    *fixture,
621                         gconstpointer  user_data)
622 {
623   GtkTreePath *path = (GtkTreePath *)user_data;
624
625   check_filter_model_with_root (fixture, path);
626   check_level_length (fixture->filter, NULL, 0);
627
628   set_path_visibility (fixture, "2", TRUE);
629   check_filter_model_with_root (fixture, path);
630   check_level_length (fixture->filter, NULL, 0);
631
632   set_path_visibility (fixture, "2:2:2", TRUE);
633   check_filter_model_with_root (fixture, path);
634   check_level_length (fixture->filter, NULL, 0);
635
636   set_path_visibility (fixture, "2:2", TRUE);
637   check_filter_model_with_root (fixture, path);
638   check_level_length (fixture->filter, NULL, 1);
639   check_level_length (fixture->filter, "0", 1);
640   check_level_length (fixture->filter, "0:0", 0);
641
642   set_path_visibility (fixture, "3", TRUE);
643   check_filter_model_with_root (fixture, path);
644   check_level_length (fixture->filter, NULL, 1);
645
646   set_path_visibility (fixture, "2:2", FALSE);
647   check_filter_model_with_root (fixture, path);
648   check_level_length (fixture->filter, NULL, 0);
649
650   set_path_visibility (fixture, "2:2:1", TRUE);
651   set_path_visibility (fixture, "2:2", TRUE);
652   check_filter_model_with_root (fixture, path);
653   check_level_length (fixture->filter, NULL, 1);
654   check_level_length (fixture->filter, "0", 2);
655   check_level_length (fixture->filter, "0:1", 0);
656 }
657
658
659 static void
660 unfiltered_hide_single (FilterTest    *fixture,
661                         gconstpointer  user_data)
662
663 {
664   set_path_visibility (fixture, "2", FALSE);
665
666   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
667
668   filter_test_enable_filter (fixture);
669
670   check_filter_model (fixture);
671   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
672 }
673
674 static void
675 unfiltered_hide_single_child (FilterTest    *fixture,
676                               gconstpointer  user_data)
677
678 {
679   set_path_visibility (fixture, "2:2", FALSE);
680
681   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
682   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
683
684   filter_test_enable_filter (fixture);
685
686   check_filter_model (fixture);
687   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
688   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
689 }
690
691 static void
692 unfiltered_hide_single_multi_level (FilterTest    *fixture,
693                                     gconstpointer  user_data)
694
695 {
696   set_path_visibility (fixture, "2:2:2", FALSE);
697   set_path_visibility (fixture, "2:2", FALSE);
698
699   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
700   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
701   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
702
703   filter_test_enable_filter (fixture);
704
705   check_filter_model (fixture);
706   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
707   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
708
709   set_path_visibility (fixture, "2:2", TRUE);
710
711   check_filter_model (fixture);
712   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
713   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
714   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
715 }
716
717
718 static void
719 unfiltered_vroot_hide_single (FilterTest    *fixture,
720                               gconstpointer  user_data)
721
722 {
723   GtkTreePath *path = (GtkTreePath *)user_data;
724
725   set_path_visibility (fixture, "2:2", FALSE);
726
727   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
728
729   filter_test_enable_filter (fixture);
730
731   check_filter_model_with_root (fixture, path);
732   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
733 }
734
735 static void
736 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
737                                     gconstpointer  user_data)
738
739 {
740   GtkTreePath *path = (GtkTreePath *)user_data;
741
742   set_path_visibility (fixture, "2:2:2", FALSE);
743
744   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
745   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
746
747   filter_test_enable_filter (fixture);
748
749   check_filter_model_with_root (fixture, path);
750   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
751   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
752 }
753
754 static void
755 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
756                                           gconstpointer  user_data)
757
758 {
759   GtkTreePath *path = (GtkTreePath *)user_data;
760
761   set_path_visibility (fixture, "2:2:2:2", FALSE);
762   set_path_visibility (fixture, "2:2:2", FALSE);
763
764   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
765   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
766   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
767
768   filter_test_enable_filter (fixture);
769
770   check_filter_model_with_root (fixture, path);
771   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
772   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
773
774   set_path_visibility (fixture, "2:2:2", TRUE);
775
776   check_filter_model_with_root (fixture, path);
777   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
778   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
779   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
780 }
781
782
783
784 static void
785 unfiltered_show_single (FilterTest    *fixture,
786                         gconstpointer  user_data)
787
788 {
789   set_path_visibility (fixture, "2", TRUE);
790
791   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
792
793   filter_test_enable_filter (fixture);
794
795   check_filter_model (fixture);
796   check_level_length (fixture->filter, NULL, 1);
797 }
798
799 static void
800 unfiltered_show_single_child (FilterTest    *fixture,
801                               gconstpointer  user_data)
802
803 {
804   set_path_visibility (fixture, "2:2", TRUE);
805
806   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
807   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
808
809   filter_test_enable_filter (fixture);
810
811   check_filter_model (fixture);
812   check_level_length (fixture->filter, NULL, 0);
813
814   /* From here we are filtered, "2" in the real model is "0" in the filter
815    * model.
816    */
817   set_path_visibility (fixture, "2", TRUE);
818   check_level_length (fixture->filter, NULL, 1);
819   check_level_length (fixture->filter, "0", 1);
820 }
821
822 static void
823 unfiltered_show_single_multi_level (FilterTest    *fixture,
824                                     gconstpointer  user_data)
825
826 {
827   set_path_visibility (fixture, "2:2:2", TRUE);
828   set_path_visibility (fixture, "2:2", TRUE);
829
830   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
831   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
832   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
833
834   filter_test_enable_filter (fixture);
835
836   check_filter_model (fixture);
837   check_level_length (fixture->filter, NULL, 0);
838
839   /* From here we are filtered, "2" in the real model is "0" in the filter
840    * model.
841    */
842   set_path_visibility (fixture, "2", TRUE);
843   check_filter_model (fixture);
844   check_level_length (fixture->filter, NULL, 1);
845   check_level_length (fixture->filter, "0", 1);
846   check_level_length (fixture->filter, "0:0", 1);
847 }
848
849
850 static void
851 unfiltered_vroot_show_single (FilterTest    *fixture,
852                               gconstpointer  user_data)
853
854 {
855   GtkTreePath *path = (GtkTreePath *)user_data;
856
857   set_path_visibility (fixture, "2:2", TRUE);
858
859   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
860
861   filter_test_enable_filter (fixture);
862
863   check_filter_model_with_root (fixture, path);
864   check_level_length (fixture->filter, NULL, 1);
865 }
866
867 static void
868 unfiltered_vroot_show_single_child (FilterTest    *fixture,
869                                     gconstpointer  user_data)
870
871 {
872   GtkTreePath *path = (GtkTreePath *)user_data;
873
874   set_path_visibility (fixture, "2:2:2", TRUE);
875
876   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
877   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
878
879   filter_test_enable_filter (fixture);
880
881   check_filter_model_with_root (fixture, path);
882   check_level_length (fixture->filter, NULL, 0);
883
884   /* From here we are filtered, "2" in the real model is "0" in the filter
885    * model.
886    */
887   set_path_visibility (fixture, "2:2", TRUE);
888   check_level_length (fixture->filter, NULL, 1);
889   check_level_length (fixture->filter, "0", 1);
890 }
891
892 static void
893 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
894                                           gconstpointer  user_data)
895
896 {
897   GtkTreePath *path = (GtkTreePath *)user_data;
898
899   set_path_visibility (fixture, "2:2:2:2", TRUE);
900   set_path_visibility (fixture, "2:2:2", TRUE);
901
902   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
903   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
904   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
905
906   filter_test_enable_filter (fixture);
907
908   check_filter_model_with_root (fixture, path);
909   check_level_length (fixture->filter, NULL, 0);
910
911   /* From here we are filtered, "2" in the real model is "0" in the filter
912    * model.
913    */
914   set_path_visibility (fixture, "2:2", TRUE);
915   check_filter_model_with_root (fixture, path);
916   check_level_length (fixture->filter, NULL, 1);
917   check_level_length (fixture->filter, "0", 1);
918   check_level_length (fixture->filter, "0:0", 1);
919 }
920
921
922 static gboolean
923 specific_path_dependent_filter_func (GtkTreeModel *model,
924                                      GtkTreeIter  *iter,
925                                      gpointer      data)
926 {
927   GtkTreePath *path;
928
929   path = gtk_tree_model_get_path (model, iter);
930   if (gtk_tree_path_get_indices (path)[0] < 4)
931     return FALSE;
932
933   return TRUE;
934 }
935
936 static void
937 specific_path_dependent_filter (void)
938 {
939   int i;
940   GtkTreeIter iter;
941   GtkListStore *list;
942   GtkTreeModel *sort;
943   GtkTreeModel *filter;
944
945   list = gtk_list_store_new (1, G_TYPE_INT);
946   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
947   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
948   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
949   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
950   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
951   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
952   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
953   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
954
955   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
956   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
957   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
958                                           specific_path_dependent_filter_func,
959                                           NULL, NULL);
960
961   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
962                                         GTK_SORT_DESCENDING);
963
964   for (i = 0; i < 4; i++)
965     {
966       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
967                                          NULL, 1))
968         gtk_list_store_remove (list, &iter);
969
970       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
971                                          NULL, 2))
972         gtk_list_store_remove (list, &iter);
973     }
974 }
975
976
977 static gboolean
978 specific_append_after_collapse_visible_func (GtkTreeModel *model,
979                                              GtkTreeIter  *iter,
980                                              gpointer      data)
981 {
982   gint number;
983   gboolean hide_negative_numbers;
984
985   gtk_tree_model_get (model, iter, 1, &number, -1);
986   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
987
988   return (number >= 0 || !hide_negative_numbers);
989 }
990
991 static void
992 specific_append_after_collapse (void)
993 {
994   /* This test is based on one of the test cases I found in my
995    * old test cases directory.  I unfortunately do not have a record
996    * from who this test case originated.  -Kris.
997    *
998    * General idea:
999    * - Construct tree.
1000    * - Show tree, expand, collapse.
1001    * - Add a row.
1002    */
1003
1004   GtkTreeIter iter;
1005   GtkTreeIter child_iter;
1006   GtkTreeIter child_iter2;
1007   GtkTreePath *append_path;
1008   GtkTreeStore *store;
1009   GtkTreeModel *filter;
1010   GtkTreeModel *sort;
1011
1012   GtkWidget *window;
1013   GtkWidget *tree_view;
1014
1015   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
1016
1017   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1018   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
1019                      GINT_TO_POINTER (FALSE));
1020   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1021                                           specific_append_after_collapse_visible_func,
1022                                           filter, NULL);
1023
1024   sort = gtk_tree_model_sort_new_with_model (filter);
1025
1026   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1027   tree_view = gtk_tree_view_new_with_model (sort);
1028   gtk_container_add (GTK_CONTAINER (window), tree_view);
1029   gtk_widget_realize (tree_view);
1030
1031   while (gtk_events_pending ())
1032     gtk_main_iteration ();
1033
1034   gtk_tree_store_prepend (store, &iter, NULL);
1035   gtk_tree_store_set (store, &iter,
1036                       0, "hallo", 1, 1, -1);
1037
1038   gtk_tree_store_append (store, &child_iter, &iter);
1039   gtk_tree_store_set (store, &child_iter,
1040                       0, "toemaar", 1, 1, -1);
1041
1042   gtk_tree_store_append (store, &child_iter2, &child_iter);
1043   gtk_tree_store_set (store, &child_iter2,
1044                       0, "very deep", 1, 1, -1);
1045
1046   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
1047
1048   gtk_tree_store_append (store, &child_iter, &iter);
1049   gtk_tree_store_set (store, &child_iter,
1050                       0, "sja", 1, 1, -1);
1051
1052   gtk_tree_store_append (store, &child_iter, &iter);
1053   gtk_tree_store_set (store, &child_iter,
1054                       0, "some word", 1, -1, -1);
1055
1056   /* Expand and collapse the tree */
1057   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1058   while (gtk_events_pending ())
1059     gtk_main_iteration ();
1060
1061   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
1062   while (gtk_events_pending ())
1063     gtk_main_iteration ();
1064
1065   /* Add another it */
1066   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
1067                      GINT_TO_POINTER (TRUE));
1068
1069   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
1070     {
1071       gtk_tree_store_append (store, &child_iter, &iter);
1072       gtk_tree_store_set (store, &child_iter,
1073                           0, "new new new !!", 1, 1, -1);
1074     }
1075   gtk_tree_path_free (append_path);
1076
1077   /* Expand */
1078   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1079   while (gtk_events_pending ())
1080     gtk_main_iteration ();
1081 }
1082
1083
1084 static gint
1085 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
1086                                                GtkTreeIter   *iter1,
1087                                                GtkTreeIter   *iter2,
1088                                                gpointer       data)
1089 {
1090   return -1;
1091 }
1092
1093 static gboolean
1094 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
1095                                                GtkTreeIter   *iter,
1096                                                gpointer       data)
1097 {
1098   char *item = NULL;
1099
1100   /* Do reference the model */
1101   gtk_tree_model_get (model, iter, 0, &item, -1);
1102   g_free (item);
1103
1104   return FALSE;
1105 }
1106
1107 static void
1108 specific_sort_filter_remove_node (void)
1109 {
1110   /* This test is based on one of the test cases I found in my
1111    * old test cases directory.  I unfortunately do not have a record
1112    * from who this test case originated.  -Kris.
1113    *
1114    * General idea:
1115    *  - Create tree store, sort, filter models.  The sort model has
1116    *    a default sort func that is enabled, filter model a visible func
1117    *    that defaults to returning FALSE.
1118    *  - Remove a node from the tree store.
1119    */
1120
1121   GtkTreeIter iter;
1122   GtkTreeStore *store;
1123   GtkTreeModel *filter;
1124   GtkTreeModel *sort;
1125
1126   GtkWidget *window;
1127   GtkWidget *tree_view;
1128
1129   store = gtk_tree_store_new (1, G_TYPE_STRING);
1130   gtk_tree_store_append (store, &iter, NULL);
1131   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
1132
1133   gtk_tree_store_append (store, &iter, NULL);
1134   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
1135
1136   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1137   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
1138                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
1139
1140   filter = gtk_tree_model_filter_new (sort, NULL);
1141   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1142                                           specific_sort_filter_remove_node_visible_func,
1143                                           filter, NULL);
1144
1145
1146   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1147   tree_view = gtk_tree_view_new_with_model (filter);
1148   gtk_container_add (GTK_CONTAINER (window), tree_view);
1149   gtk_widget_realize (tree_view);
1150
1151   while (gtk_events_pending ())
1152     gtk_main_iteration ();
1153
1154   /* Remove a node */
1155   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
1156   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
1157   gtk_tree_store_remove (store, &iter);
1158
1159   while (gtk_events_pending ())
1160     gtk_main_iteration ();
1161 }
1162
1163
1164 static void
1165 specific_sort_filter_remove_root (void)
1166 {
1167   /* This test is based on one of the test cases I found in my
1168    * old test cases directory.  I unfortunately do not have a record
1169    * from who this test case originated.  -Kris.
1170    */
1171
1172   GtkTreeModel *model, *sort, *filter;
1173   GtkTreeIter root, mid, leaf;
1174   GtkTreePath *path;
1175
1176   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
1177   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
1178   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
1179   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
1180
1181   path = gtk_tree_model_get_path (model, &mid);
1182
1183   sort = gtk_tree_model_sort_new_with_model (model);
1184   filter = gtk_tree_model_filter_new (sort, path);
1185
1186   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
1187
1188   g_object_unref (filter);
1189   g_object_unref (sort);
1190   g_object_unref (model);
1191 }
1192
1193
1194 static void
1195 specific_root_mixed_visibility (void)
1196 {
1197   int i;
1198   GtkTreeModel *filter;
1199   /* A bit nasty, apologies */
1200   FilterTest fixture;
1201
1202   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
1203
1204   for (i = 0; i < LEVEL_LENGTH; i++)
1205     {
1206       GtkTreeIter iter;
1207
1208       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
1209       if (i % 2 == 0)
1210         create_tree_store_set_values (fixture.store, &iter, TRUE);
1211       else
1212         create_tree_store_set_values (fixture.store, &iter, FALSE);
1213     }
1214
1215   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
1216   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
1217
1218   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
1219
1220   /* In order to trigger the potential bug, we should not access
1221    * the filter model here (so don't call the check functions).
1222    */
1223
1224   /* Change visibility of an odd row to TRUE */
1225   set_path_visibility (&fixture, "3", TRUE);
1226   check_filter_model (&fixture);
1227   check_level_length (fixture.filter, NULL, 4);
1228 }
1229
1230
1231 static void
1232 specific_filter_add_child (void)
1233 {
1234   /* This test is based on one of the test cases I found in my
1235    * old test cases directory.  I unfortunately do not have a record
1236    * from who this test case originated.  -Kris.
1237    */
1238
1239   GtkTreeIter iter;
1240   GtkTreeIter iter_first;
1241   GtkTreeIter child;
1242   GtkTreeStore *store;
1243   GtkTreeModel *filter;
1244
1245   store = gtk_tree_store_new (1, G_TYPE_STRING);
1246
1247   gtk_tree_store_append (store, &iter_first, NULL);
1248   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
1249
1250   gtk_tree_store_append (store, &iter, NULL);
1251   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1252
1253   gtk_tree_store_append (store, &iter, NULL);
1254   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1255
1256   gtk_tree_store_append (store, &iter, NULL);
1257   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1258
1259   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1260
1261   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
1262   gtk_tree_store_append (store, &child, &iter_first);
1263   gtk_tree_store_set (store, &child, 0, "Hello", -1);
1264 }
1265
1266
1267 static void
1268 specific_bug_300089 (void)
1269 {
1270   /* Test case for GNOME Bugzilla bug 300089.  Written by
1271    * Matthias Clasen.
1272    */
1273   GtkTreeModel *sort_model, *child_model;
1274   GtkTreePath *path;
1275   GtkTreeIter iter, iter2, sort_iter;
1276
1277   child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
1278
1279   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1280   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
1281   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1282   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
1283
1284   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
1285   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
1286   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
1287   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
1288
1289   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
1290   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
1291
1292
1293   sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
1294   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
1295                                         0, GTK_SORT_ASCENDING);
1296
1297   path = gtk_tree_path_new_from_indices (1, 1, -1);
1298
1299   /* make sure a level is constructed */ 
1300   gtk_tree_model_get_iter (sort_model, &sort_iter, path);
1301
1302   /* change the "E" row in a way that causes it to change position */ 
1303   gtk_tree_model_get_iter (child_model, &iter, path);
1304   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
1305 }
1306
1307
1308 static int
1309 specific_bug_301558_sort_func (GtkTreeModel *model,
1310                                GtkTreeIter  *a,
1311                                GtkTreeIter  *b,
1312                                gpointer      data)
1313 {
1314   int i, j;
1315
1316   gtk_tree_model_get (model, a, 0, &i, -1);
1317   gtk_tree_model_get (model, b, 0, &j, -1);
1318
1319   return j - i;
1320 }
1321
1322 static void
1323 specific_bug_301558 (void)
1324 {
1325   /* Test case for GNOME Bugzilla bug 301558 provided by
1326    * Markku Vire.
1327    */
1328   GtkTreeStore *tree;
1329   GtkTreeModel *filter;
1330   GtkTreeModel *sort;
1331   GtkTreeIter root, iter, iter2;
1332   GtkWidget *view;
1333   int i;
1334   gboolean add;
1335
1336   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
1337   gtk_tree_store_append (tree, &iter, NULL);
1338   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
1339   gtk_tree_store_append (tree, &iter2, &iter);
1340   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
1341
1342   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
1343   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
1344                                            specific_bug_301558_sort_func,
1345                                            NULL, NULL);
1346
1347   filter = gtk_tree_model_filter_new (sort, NULL);
1348   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
1349
1350   view = gtk_tree_view_new_with_model (filter);
1351
1352   while (gtk_events_pending ())
1353     gtk_main_iteration ();
1354
1355   add = TRUE;
1356
1357   for (i = 0; i < 10; i++)
1358     {
1359       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
1360         g_assert_not_reached ();
1361
1362       if (add)
1363         {
1364           gtk_tree_store_append (tree, &iter, &root);
1365           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
1366         }
1367       else
1368         {
1369           int n;
1370           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
1371           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
1372                                          &root, n - 1);
1373           gtk_tree_store_remove (tree, &iter);
1374         }
1375
1376       add = !add;
1377     }
1378 }
1379
1380
1381 static gboolean
1382 specific_bug_311955_filter_func (GtkTreeModel *model,
1383                                  GtkTreeIter  *iter,
1384                                  gpointer      data)
1385 {
1386   int value;
1387
1388   gtk_tree_model_get (model, iter, 0, &value, -1);
1389
1390   return (value != 0);
1391 }
1392
1393 static void
1394 specific_bug_311955 (void)
1395 {
1396   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
1397    * by Markku Vire.
1398    */
1399   GtkTreeIter iter, child, root;
1400   GtkTreeStore *store;
1401   GtkTreeModel *sort;
1402   GtkTreeModel *filter;
1403
1404   GtkWidget *window;
1405   GtkWidget *tree_view;
1406   int i;
1407   int n;
1408
1409   store = gtk_tree_store_new (1, G_TYPE_INT);
1410
1411   gtk_tree_store_append (store, &root, NULL);
1412   gtk_tree_store_set (store, &root, 0, 33, -1);
1413
1414   gtk_tree_store_append (store, &iter, &root);
1415   gtk_tree_store_set (store, &iter, 0, 50, -1);
1416
1417   gtk_tree_store_append (store, &iter, NULL);
1418   gtk_tree_store_set (store, &iter, 0, 22, -1);
1419
1420   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1421   filter = gtk_tree_model_filter_new (sort, NULL);
1422
1423   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1424                                           specific_bug_311955_filter_func,
1425                                           NULL, NULL);
1426
1427   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1428   tree_view = gtk_tree_view_new_with_model (filter);
1429   g_object_unref (store);
1430
1431   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1432
1433   while (gtk_events_pending ())
1434     gtk_main_iteration ();
1435
1436   /* Fill model */
1437   for (i = 0; i < 4; i++)
1438     {
1439       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1440
1441       gtk_tree_store_append (store, &iter, &root);
1442
1443       if (i < 3)
1444         gtk_tree_store_set (store, &iter, 0, i, -1);
1445
1446       if (i % 2 == 0)
1447         {
1448           gtk_tree_store_append (store, &child, &iter);
1449           gtk_tree_store_set (store, &child, 0, 10, -1);
1450         }
1451     }
1452
1453   while (gtk_events_pending ())
1454     gtk_main_iteration ();
1455
1456   /* Remove bottommost child from the tree. */
1457   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1458   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
1459
1460   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
1461     {
1462       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
1463         gtk_tree_store_remove (store, &child);
1464     }
1465   else
1466     g_assert_not_reached ();
1467 }
1468
1469 static void
1470 specific_bug_346800 (void)
1471 {
1472   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
1473    * by Jonathan Matthew.
1474    */
1475
1476   GtkTreeIter node_iters[50];
1477   GtkTreeIter child_iters[50];
1478   GtkTreeModel *model;
1479   GtkTreeModelFilter *filter;
1480   GtkTreeStore *store;
1481   GType *columns;
1482   int i;
1483   int items = 50;
1484   columns = g_new (GType, 2);
1485   columns[0] = G_TYPE_STRING;
1486   columns[1] = G_TYPE_BOOLEAN;
1487   store = gtk_tree_store_newv (2, columns);
1488   model = GTK_TREE_MODEL (store);
1489
1490   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
1491   gtk_tree_model_filter_set_visible_column (filter, 1);
1492
1493   for (i=0; i<items; i++)
1494     {
1495       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
1496
1497       g_malloc (138);
1498       gtk_tree_store_append (store, &node_iters[i], NULL);
1499       gtk_tree_store_set (store, &node_iters[i],
1500                           0, "something",
1501                           1, ((i%6) == 0) ? FALSE : TRUE,
1502                           -1);
1503
1504       g_malloc (47);
1505       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
1506       gtk_tree_store_set (store, &child_iters[i],
1507                           0, "something else",
1508                           1, FALSE,
1509                           -1);
1510       gtk_tree_model_filter_refilter (filter);
1511
1512       if (i > 6)
1513         {
1514           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
1515                               (i & 1) ? TRUE : FALSE, -1);
1516           gtk_tree_model_filter_refilter (filter);
1517
1518           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
1519                               (i & 1) ? FALSE: TRUE, -1);
1520           gtk_tree_model_filter_refilter (filter);
1521         }
1522     }
1523 }
1524
1525
1526 static void
1527 specific_bug_364946 (void)
1528 {
1529   /* This is a test case for GNOME Bugzilla bug 364946.  It was written
1530    * by Andreas Koehler.
1531    */
1532   GtkTreeStore *store;
1533   GtkTreeIter a, aa, aaa, aab, iter;
1534   GtkTreeModel *s_model;
1535
1536   store = gtk_tree_store_new (1, G_TYPE_STRING);
1537
1538   gtk_tree_store_append (store, &a, NULL);
1539   gtk_tree_store_set (store, &a, 0, "0", -1);
1540
1541   gtk_tree_store_append (store, &aa, &a);
1542   gtk_tree_store_set (store, &aa, 0, "0:0", -1);
1543
1544   gtk_tree_store_append (store, &aaa, &aa);
1545   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1546
1547   gtk_tree_store_append (store, &aab, &aa);
1548   gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
1549
1550   s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1551   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
1552                                         GTK_SORT_ASCENDING);
1553
1554   gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
1555
1556   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1557   gtk_tree_store_remove (store, &aaa);
1558   gtk_tree_store_remove (store, &aab);
1559
1560   gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
1561 }
1562
1563
1564 static gboolean
1565 specific_bug_464173_visible_func (GtkTreeModel *model,
1566                                   GtkTreeIter  *iter,
1567                                   gpointer      data)
1568 {
1569   gboolean *visible = (gboolean *)data;
1570
1571   return *visible;
1572 }
1573
1574 static void
1575 specific_bug_464173 (void)
1576 {
1577   /* Test case for GNOME Bugzilla bug 464173, test case written
1578    * by Andreas Koehler.
1579    */
1580   GtkTreeStore *model;
1581   GtkTreeModelFilter *f_model;
1582   GtkTreeIter iter1, iter2;
1583   GtkWidget *view;
1584   gboolean visible = TRUE;
1585
1586   model = gtk_tree_store_new (1, G_TYPE_STRING);
1587   gtk_tree_store_append (model, &iter1, NULL);
1588   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
1589   gtk_tree_store_append (model, &iter2, &iter1);
1590   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
1591
1592   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
1593   gtk_tree_model_filter_set_visible_func (f_model,
1594                                           specific_bug_464173_visible_func,
1595                                           &visible, NULL);
1596
1597   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
1598
1599   visible = FALSE;
1600   gtk_tree_model_filter_refilter (f_model);
1601 }
1602
1603
1604 static gboolean
1605 specific_bug_540201_filter_func (GtkTreeModel *model,
1606                                  GtkTreeIter  *iter,
1607                                  gpointer      data)
1608 {
1609   gboolean has_children;
1610
1611   has_children = gtk_tree_model_iter_has_child (model, iter);
1612
1613   return has_children;
1614 }
1615
1616 static void
1617 specific_bug_540201 (void)
1618 {
1619   /* Test case for GNOME Bugzilla bug 540201, steps provided by
1620    * Charles Day.
1621    */
1622   GtkTreeIter iter, root;
1623   GtkTreeStore *store;
1624   GtkTreeModel *filter;
1625
1626   GtkWidget *tree_view;
1627
1628   store = gtk_tree_store_new (1, G_TYPE_INT);
1629
1630   gtk_tree_store_append (store, &root, NULL);
1631   gtk_tree_store_set (store, &root, 0, 33, -1);
1632
1633   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1634   tree_view = gtk_tree_view_new_with_model (filter);
1635
1636   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1637                                           specific_bug_540201_filter_func,
1638                                           NULL, NULL);
1639
1640   gtk_tree_store_append (store, &iter, &root);
1641   gtk_tree_store_set (store, &iter, 0, 50, -1);
1642
1643   gtk_tree_store_append (store, &iter, &root);
1644   gtk_tree_store_set (store, &iter, 0, 22, -1);
1645
1646
1647   gtk_tree_store_append (store, &root, NULL);
1648   gtk_tree_store_set (store, &root, 0, 33, -1);
1649
1650   gtk_tree_store_append (store, &iter, &root);
1651   gtk_tree_store_set (store, &iter, 0, 22, -1);
1652 }
1653
1654
1655 static gboolean
1656 specific_bug_549287_visible_func (GtkTreeModel *model,
1657                                   GtkTreeIter  *iter,
1658                                   gpointer      data)
1659 {
1660   gboolean result = FALSE;
1661
1662   result = gtk_tree_model_iter_has_child (model, iter);
1663
1664   return result;
1665 }
1666
1667 static void
1668 specific_bug_549287 (void)
1669 {
1670   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
1671
1672   int i;
1673   GtkTreeStore *store;
1674   GtkTreeModel *filtered;
1675   GtkWidget *view;
1676   GtkTreeIter iter;
1677   GtkTreeIter *swap, *parent, *child;
1678
1679   store = gtk_tree_store_new (1, G_TYPE_STRING);
1680   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
1681   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
1682                                           specific_bug_549287_visible_func,
1683                                           NULL, NULL);
1684
1685   view = gtk_tree_view_new_with_model (filtered);
1686
1687   for (i = 0; i < 4; i++)
1688     {
1689       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
1690         {
1691           parent = gtk_tree_iter_copy (&iter);
1692           child = gtk_tree_iter_copy (&iter);
1693
1694           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
1695                                                 child, parent, 0))
1696             {
1697
1698               swap = parent;
1699               parent = child;
1700               child = swap;
1701             }
1702
1703           gtk_tree_store_append (store, child, parent);
1704           gtk_tree_store_set (store, child,
1705                               0, "Something",
1706                               -1);
1707
1708           gtk_tree_iter_free (parent);
1709           gtk_tree_iter_free (child);
1710         }
1711       else
1712         {
1713           gtk_tree_store_append (store, &iter, NULL);
1714           gtk_tree_store_set (store, &iter,
1715                               0, "Something",
1716                               -1);
1717         }
1718
1719       /* since we inserted something, we changed the visibility conditions: */
1720       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
1721     }
1722 }
1723
1724 /* main */
1725
1726 int
1727 main (int    argc,
1728       char **argv)
1729 {
1730   gtk_test_init (&argc, &argv, NULL);
1731
1732   g_test_add ("/FilterModel/self/verify-test-suite",
1733               FilterTest, NULL,
1734               filter_test_setup,
1735               verify_test_suite,
1736               filter_test_teardown);
1737
1738   g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-1",
1739               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1740               filter_test_setup,
1741               verify_test_suite_vroot,
1742               filter_test_teardown);
1743   g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-2",
1744               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
1745               filter_test_setup,
1746               verify_test_suite_vroot,
1747               filter_test_teardown);
1748
1749
1750   g_test_add ("/FilterModel/filled/hide-root-level",
1751               FilterTest, NULL,
1752               filter_test_setup,
1753               filled_hide_root_level,
1754               filter_test_teardown);
1755   g_test_add ("/FilterModel/filled/hide-child-levels",
1756               FilterTest, NULL,
1757               filter_test_setup,
1758               filled_hide_child_levels,
1759               filter_test_teardown);
1760
1761   g_test_add ("/FilterModel/filled/hide-root-level/vroot",
1762               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1763               filter_test_setup,
1764               filled_vroot_hide_root_level,
1765               filter_test_teardown);
1766   g_test_add ("/FilterModel/filled/hide-child-levels/vroot",
1767               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1768               filter_test_setup,
1769               filled_vroot_hide_child_levels,
1770               filter_test_teardown);
1771
1772
1773   g_test_add ("/FilterModel/empty/show-nodes",
1774               FilterTest, NULL,
1775               filter_test_setup_empty,
1776               empty_show_nodes,
1777               filter_test_teardown);
1778
1779   g_test_add ("/FilterModel/empty/show-nodes/vroot",
1780               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1781               filter_test_setup_empty,
1782               empty_vroot_show_nodes,
1783               filter_test_teardown);
1784
1785
1786   g_test_add ("/FilterModel/unfiltered/hide-single",
1787               FilterTest, NULL,
1788               filter_test_setup_unfiltered,
1789               unfiltered_hide_single,
1790               filter_test_teardown);
1791   g_test_add ("/FilterModel/unfiltered/hide-single-child",
1792               FilterTest, NULL,
1793               filter_test_setup_unfiltered,
1794               unfiltered_hide_single_child,
1795               filter_test_teardown);
1796   g_test_add ("/FilterModel/unfiltered/hide-single-multi-level",
1797               FilterTest, NULL,
1798               filter_test_setup_unfiltered,
1799               unfiltered_hide_single_multi_level,
1800               filter_test_teardown);
1801
1802   g_test_add ("/FilterModel/unfiltered/hide-single/vroot",
1803               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1804               filter_test_setup_unfiltered,
1805               unfiltered_vroot_hide_single,
1806               filter_test_teardown);
1807   g_test_add ("/FilterModel/unfiltered/hide-single-child/vroot",
1808               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1809               filter_test_setup_unfiltered,
1810               unfiltered_vroot_hide_single_child,
1811               filter_test_teardown);
1812   g_test_add ("/FilterModel/unfiltered/hide-single-multi-level/vroot",
1813               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1814               filter_test_setup_unfiltered,
1815               unfiltered_vroot_hide_single_multi_level,
1816               filter_test_teardown);
1817
1818
1819
1820   g_test_add ("/FilterModel/unfiltered/show-single",
1821               FilterTest, NULL,
1822               filter_test_setup_empty_unfiltered,
1823               unfiltered_show_single,
1824               filter_test_teardown);
1825   g_test_add ("/FilterModel/unfiltered/show-single-child",
1826               FilterTest, NULL,
1827               filter_test_setup_empty_unfiltered,
1828               unfiltered_show_single_child,
1829               filter_test_teardown);
1830   g_test_add ("/FilterModel/unfiltered/show-single-multi-level",
1831               FilterTest, NULL,
1832               filter_test_setup_empty_unfiltered,
1833               unfiltered_show_single_multi_level,
1834               filter_test_teardown);
1835
1836   g_test_add ("/FilterModel/unfiltered/show-single/vroot",
1837               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1838               filter_test_setup_empty_unfiltered,
1839               unfiltered_vroot_show_single,
1840               filter_test_teardown);
1841   g_test_add ("/FilterModel/unfiltered/show-single-child/vroot",
1842               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1843               filter_test_setup_empty_unfiltered,
1844               unfiltered_vroot_show_single_child,
1845               filter_test_teardown);
1846   g_test_add ("/FilterModel/unfiltered/show-single-multi-level/vroot",
1847               FilterTest, gtk_tree_path_new_from_indices (2, -1),
1848               filter_test_setup_empty_unfiltered,
1849               unfiltered_vroot_show_single_multi_level,
1850               filter_test_teardown);
1851
1852
1853   g_test_add_func ("/FilterModel/specific/path-dependent-filter",
1854                    specific_path_dependent_filter);
1855   g_test_add_func ("/FilterModel/specific/append-after-collapse",
1856                    specific_append_after_collapse);
1857   g_test_add_func ("/FilterModel/specific/sort-filter-remove-node",
1858                    specific_sort_filter_remove_node);
1859   g_test_add_func ("/FilterModel/specific/sort-filter-remove-root",
1860                    specific_sort_filter_remove_root);
1861   g_test_add_func ("/FilterModel/specific/root-mixed-visibility",
1862                    specific_root_mixed_visibility);
1863   g_test_add_func ("/FilterModel/specific/filter-add-child",
1864                    specific_filter_add_child);
1865
1866   g_test_add_func ("/FilterModel/specific/bug-300089",
1867                    specific_bug_300089);
1868   g_test_add_func ("/FilterModel/specific/bug-301558",
1869                    specific_bug_301558);
1870   g_test_add_func ("/FilterModel/specific/bug-311955",
1871                    specific_bug_311955);
1872   g_test_add_func ("/FilterModel/specific/bug-346800",
1873                    specific_bug_346800);
1874   g_test_add_func ("/FilterModel/specific/bug-364946",
1875                    specific_bug_364946);
1876   g_test_add_func ("/FilterModel/specific/bug-464173",
1877                    specific_bug_464173);
1878   g_test_add_func ("/FilterModel/specific/bug-540201",
1879                    specific_bug_540201);
1880   g_test_add_func ("/FilterModel/specific/bug-549287",
1881                    specific_bug_549287);
1882
1883   return g_test_run ();
1884 }