]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
e0b6a959774923a8869be8690e37e38c718b0f65
[~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 (FilterTest    *fixture,
92                    gconstpointer  test_data)
93 {
94   fixture->store = create_tree_store (3, TRUE);
95   fixture->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store), NULL));
96   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
97
98   /* We need a tree view that's listening to get ref counting from that
99    * side.
100    */
101   fixture->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (fixture->filter));
102 }
103
104 static void
105 filter_test_setup_empty (FilterTest    *fixture,
106                          gconstpointer  test_data)
107 {
108   fixture->store = create_tree_store (3, FALSE);
109   fixture->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store), NULL));
110   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
111
112   /* We need a tree view that's listening to get ref counting from that
113    * side.
114    */
115   fixture->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (fixture->filter));
116 }
117
118 static void
119 filter_test_setup_unfiltered (FilterTest    *fixture,
120                               gconstpointer  test_data)
121 {
122   fixture->store = create_tree_store (3, TRUE);
123   fixture->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store), NULL));
124
125   /* We need a tree view that's listening to get ref counting from that
126    * side.
127    */
128   fixture->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (fixture->filter));
129 }
130
131 static void
132 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
133                                     gconstpointer  test_data)
134 {
135   fixture->store = create_tree_store (3, FALSE);
136   fixture->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store), NULL));
137
138   /* We need a tree view that's listening to get ref counting from that
139    * side.
140    */
141   fixture->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (fixture->filter));
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 }
149
150 static void
151 filter_test_teardown (FilterTest    *fixture,
152                       gconstpointer  test_data)
153 {
154   g_object_unref (fixture->filter);
155   g_object_unref (fixture->store);
156 }
157
158 /*
159  * Model structure validation
160  */
161
162 static void
163 check_filter_model_recurse (FilterTest  *fixture,
164                             GtkTreePath *store_parent_path,
165                             GtkTreePath *filter_parent_path)
166 {
167   int i;
168   GtkTreeIter store_iter;
169   GtkTreeIter filter_iter;
170   gboolean store_has_next, filter_has_next;
171
172   gtk_tree_path_down (store_parent_path);
173   gtk_tree_path_down (filter_parent_path);
174
175   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
176                                             &store_iter, store_parent_path);
177   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
178                                              &filter_iter, filter_parent_path);
179
180   for (i = 0; i < LEVEL_LENGTH; i++)
181     {
182       gboolean visible;
183
184       g_return_if_fail (store_has_next == TRUE);
185
186       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
187                           &store_iter,
188                           1, &visible,
189                           -1);
190
191       if (visible)
192         {
193           GtkTreePath *tmp;
194           gchar *filter_str, *store_str;
195
196           g_return_if_fail (filter_has_next == TRUE);
197
198           /* Verify path */
199           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
200                                          &filter_iter);
201           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
202
203           /* Verify model content */
204           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
205                               &store_iter,
206                               0, &store_str,
207                               -1);
208           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
209                               &filter_iter,
210                               0, &filter_str,
211                               -1);
212
213           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
214
215           g_free (store_str);
216           g_free (filter_str);
217
218           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
219                                              &filter_iter))
220             {
221               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
222
223               check_filter_model_recurse (fixture,
224                                           gtk_tree_path_copy (store_parent_path),
225                                           tmp);
226             }
227
228           gtk_tree_path_next (filter_parent_path);
229           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
230         }
231
232       gtk_tree_path_next (store_parent_path);
233       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
234     }
235
236   /* Both models should have no more content! */
237   g_return_if_fail (store_has_next == FALSE);
238   g_return_if_fail (filter_has_next == FALSE);
239
240   gtk_tree_path_free (store_parent_path);
241   gtk_tree_path_free (filter_parent_path);
242 }
243
244 static void
245 check_filter_model (FilterTest *fixture)
246 {
247   GtkTreePath *path;
248
249   path = gtk_tree_path_new ();
250
251   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
252 }
253
254 /* Helpers */
255
256 static void
257 check_level_length (GtkTreeModelFilter *filter,
258                     const gchar        *level,
259                     const int           length)
260 {
261   if (!level)
262     {
263       int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
264       g_return_if_fail (l == length);
265     }
266   else
267     {
268       int l;
269       GtkTreeIter iter;
270
271       gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
272                                            &iter, level);
273       l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
274       g_return_if_fail (l == length);
275     }
276 }
277
278 static void
279 set_path_visibility (FilterTest  *fixture,
280                      const gchar *path,
281                      gboolean     visible)
282 {
283   GtkTreeIter store_iter;
284
285   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
286                                        &store_iter, path);
287   gtk_tree_store_set (fixture->store, &store_iter,
288                       1, visible,
289                       -1);
290 }
291
292 /*
293  * The actual tests.
294  */
295
296 static void
297 verify_test_suite (FilterTest    *fixture,
298                    gconstpointer  user_data)
299 {
300   check_filter_model (fixture);
301 }
302
303
304 static void
305 filled_hide_root_level (FilterTest    *fixture,
306                         gconstpointer  user_data)
307 {
308   set_path_visibility (fixture, "2", FALSE);
309   check_filter_model (fixture);
310   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
311
312   set_path_visibility (fixture, "0", FALSE);
313   check_filter_model (fixture);
314   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
315
316   set_path_visibility (fixture, "4", FALSE);
317   check_filter_model (fixture);
318   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
319
320
321   /* Hide remaining */
322   set_path_visibility (fixture, "1", FALSE);
323   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
324
325   set_path_visibility (fixture, "3", FALSE);
326   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
327
328   check_filter_model (fixture);
329
330   /* Show some */
331   set_path_visibility (fixture, "1", TRUE);
332   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
333
334   set_path_visibility (fixture, "3", TRUE);
335   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
336
337   check_filter_model (fixture);
338 }
339
340 static void
341 filled_hide_child_levels (FilterTest    *fixture,
342                           gconstpointer  user_data)
343 {
344   set_path_visibility (fixture, "0:2", FALSE);
345   check_filter_model (fixture);
346   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
347   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
348
349   set_path_visibility (fixture, "0:4", FALSE);
350   check_filter_model (fixture);
351   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
352   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
353
354   set_path_visibility (fixture, "0:4:3", FALSE);
355   check_filter_model (fixture);
356   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
357   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
358
359   set_path_visibility (fixture, "0:4:0", FALSE);
360   set_path_visibility (fixture, "0:4:1", FALSE);
361   set_path_visibility (fixture, "0:4:2", FALSE);
362   set_path_visibility (fixture, "0:4:4", FALSE);
363   check_filter_model (fixture);
364   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
365   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
366
367   set_path_visibility (fixture, "0:4", TRUE);
368   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
369   check_filter_model (fixture);
370   check_level_length (fixture->filter, "0:3", 0);
371
372   set_path_visibility (fixture, "0:2", TRUE);
373   check_filter_model (fixture);
374   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
375   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
376   check_level_length (fixture->filter, "0:4", 0);
377
378   set_path_visibility (fixture, "0:4:2", TRUE);
379   set_path_visibility (fixture, "0:4:4", TRUE);
380   check_level_length (fixture->filter, "0:4", 2);
381 }
382
383 static void
384 empty_show_nodes (FilterTest    *fixture,
385                   gconstpointer  user_data)
386 {
387   check_filter_model (fixture);
388   check_level_length (fixture->filter, NULL, 0);
389
390   set_path_visibility (fixture, "3", TRUE);
391   check_filter_model (fixture);
392   check_level_length (fixture->filter, NULL, 1);
393   check_level_length (fixture->filter, "0", 0);
394
395   set_path_visibility (fixture, "3:2:2", TRUE);
396   check_filter_model (fixture);
397   check_level_length (fixture->filter, NULL, 1);
398   check_level_length (fixture->filter, "0", 0);
399
400   set_path_visibility (fixture, "3:2", TRUE);
401   check_filter_model (fixture);
402   check_level_length (fixture->filter, NULL, 1);
403   check_level_length (fixture->filter, "0", 1);
404   check_level_length (fixture->filter, "0:0", 1);
405   check_level_length (fixture->filter, "0:0:0", 0);
406
407   set_path_visibility (fixture, "3", FALSE);
408   check_filter_model (fixture);
409   check_level_length (fixture->filter, NULL, 0);
410
411   set_path_visibility (fixture, "3:2:1", TRUE);
412   set_path_visibility (fixture, "3", TRUE);
413   check_filter_model (fixture);
414   check_level_length (fixture->filter, NULL, 1);
415   check_level_length (fixture->filter, "0", 1);
416   check_level_length (fixture->filter, "0:0", 2);
417   check_level_length (fixture->filter, "0:0:0", 0);
418 }
419
420
421 static void
422 unfiltered_hide_single (FilterTest    *fixture,
423                         gconstpointer  user_data)
424
425 {
426   set_path_visibility (fixture, "2", FALSE);
427
428   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
429
430   filter_test_enable_filter (fixture);
431
432   check_filter_model (fixture);
433   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
434 }
435
436 static void
437 unfiltered_hide_single_child (FilterTest    *fixture,
438                               gconstpointer  user_data)
439
440 {
441   set_path_visibility (fixture, "2:2", FALSE);
442
443   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
444   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
445
446   filter_test_enable_filter (fixture);
447
448   check_filter_model (fixture);
449   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
450   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
451 }
452
453 static void
454 unfiltered_hide_single_multi_level (FilterTest    *fixture,
455                                     gconstpointer  user_data)
456
457 {
458   set_path_visibility (fixture, "2:2:2", FALSE);
459   set_path_visibility (fixture, "2:2", FALSE);
460
461   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
462   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
463   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
464
465   filter_test_enable_filter (fixture);
466
467   check_filter_model (fixture);
468   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
469   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
470
471   set_path_visibility (fixture, "2:2", TRUE);
472
473   check_filter_model (fixture);
474   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
475   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
476   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
477 }
478
479
480 static void
481 unfiltered_show_single (FilterTest    *fixture,
482                         gconstpointer  user_data)
483
484 {
485   set_path_visibility (fixture, "2", TRUE);
486
487   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
488
489   filter_test_enable_filter (fixture);
490
491   check_filter_model (fixture);
492   check_level_length (fixture->filter, NULL, 1);
493 }
494
495 static void
496 unfiltered_show_single_child (FilterTest    *fixture,
497                               gconstpointer  user_data)
498
499 {
500   set_path_visibility (fixture, "2:2", TRUE);
501
502   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
503   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
504
505   filter_test_enable_filter (fixture);
506
507   check_filter_model (fixture);
508   check_level_length (fixture->filter, NULL, 0);
509
510   set_path_visibility (fixture, "2", TRUE);
511   check_level_length (fixture->filter, NULL, 1);
512   check_level_length (fixture->filter, "2", 1);
513 }
514
515 static void
516 unfiltered_show_single_multi_level (FilterTest    *fixture,
517                                     gconstpointer  user_data)
518
519 {
520   set_path_visibility (fixture, "2:2:2", TRUE);
521   set_path_visibility (fixture, "2:2", TRUE);
522
523   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
524   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
525   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
526
527   filter_test_enable_filter (fixture);
528
529   check_filter_model (fixture);
530   check_level_length (fixture->filter, NULL, 0);
531
532   set_path_visibility (fixture, "2", TRUE);
533   check_filter_model (fixture);
534   check_level_length (fixture->filter, NULL, 1);
535   check_level_length (fixture->filter, "2", 1);
536   check_level_length (fixture->filter, "2:2", 1);
537 }
538
539
540 static gboolean
541 specific_path_dependent_filter_func (GtkTreeModel *model,
542                                      GtkTreeIter  *iter,
543                                      gpointer      data)
544 {
545   GtkTreePath *path;
546
547   path = gtk_tree_model_get_path (model, iter);
548   if (gtk_tree_path_get_indices (path)[0] < 4)
549     return FALSE;
550
551   return TRUE;
552 }
553
554 static void
555 specific_path_dependent_filter (void)
556 {
557   int i;
558   GtkTreeIter iter;
559   GtkListStore *list;
560   GtkTreeModel *sort;
561   GtkTreeModel *filter;
562
563   list = gtk_list_store_new (1, G_TYPE_INT);
564   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
565   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
566   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
567   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
568   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
569   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
570   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
571   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
572
573   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
574   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
575   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
576                                           specific_path_dependent_filter_func,
577                                           NULL, NULL);
578
579   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
580                                         GTK_SORT_DESCENDING);
581
582   for (i = 0; i < 4; i++)
583     {
584       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
585                                          NULL, 1))
586         gtk_list_store_remove (list, &iter);
587
588       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
589                                          NULL, 2))
590         gtk_list_store_remove (list, &iter);
591     }
592 }
593
594
595 static gboolean
596 specific_append_after_collapse_visible_func (GtkTreeModel *model,
597                                              GtkTreeIter  *iter,
598                                              gpointer      data)
599 {
600   gint number;
601   gboolean hide_negative_numbers;
602
603   gtk_tree_model_get (model, iter, 1, &number, -1);
604   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
605
606   return (number >= 0 || !hide_negative_numbers);
607 }
608
609 static void
610 specific_append_after_collapse (void)
611 {
612   /* This test is based on one of the test cases I found in my
613    * old test cases directory.  I unfortunately do not have a record
614    * from who this test case originated.  -Kris.
615    *
616    * General idea:
617    * - Construct tree.
618    * - Show tree, expand, collapse.
619    * - Add a row.
620    */
621
622   GtkTreeIter iter;
623   GtkTreeIter child_iter;
624   GtkTreeIter child_iter2;
625   GtkTreePath *append_path;
626   GtkTreeStore *store;
627   GtkTreeModel *filter;
628   GtkTreeModel *sort;
629
630   GtkWidget *window;
631   GtkWidget *tree_view;
632
633   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
634
635   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
636   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
637                      GINT_TO_POINTER (FALSE));
638   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
639                                           specific_append_after_collapse_visible_func,
640                                           filter, NULL);
641
642   sort = gtk_tree_model_sort_new_with_model (filter);
643
644   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
645   tree_view = gtk_tree_view_new_with_model (sort);
646   gtk_container_add (GTK_CONTAINER (window), tree_view);
647   gtk_widget_realize (tree_view);
648
649   while (gtk_events_pending ())
650     gtk_main_iteration ();
651
652   gtk_tree_store_prepend (store, &iter, NULL);
653   gtk_tree_store_set (store, &iter,
654                       0, "hallo", 1, 1, -1);
655
656   gtk_tree_store_append (store, &child_iter, &iter);
657   gtk_tree_store_set (store, &child_iter,
658                       0, "toemaar", 1, 1, -1);
659
660   gtk_tree_store_append (store, &child_iter2, &child_iter);
661   gtk_tree_store_set (store, &child_iter2,
662                       0, "very deep", 1, 1, -1);
663
664   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
665
666   gtk_tree_store_append (store, &child_iter, &iter);
667   gtk_tree_store_set (store, &child_iter,
668                       0, "sja", 1, 1, -1);
669
670   gtk_tree_store_append (store, &child_iter, &iter);
671   gtk_tree_store_set (store, &child_iter,
672                       0, "some word", 1, -1, -1);
673
674   /* Expand and collapse the tree */
675   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
676   while (gtk_events_pending ())
677     gtk_main_iteration ();
678
679   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
680   while (gtk_events_pending ())
681     gtk_main_iteration ();
682
683   /* Add another it */
684   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
685                      GINT_TO_POINTER (TRUE));
686
687   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
688     {
689       gtk_tree_store_append (store, &child_iter, &iter);
690       gtk_tree_store_set (store, &child_iter,
691                           0, "new new new !!", 1, 1, -1);
692     }
693   gtk_tree_path_free (append_path);
694
695   /* Expand */
696   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
697   while (gtk_events_pending ())
698     gtk_main_iteration ();
699 }
700
701
702 static gint
703 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
704                                                GtkTreeIter   *iter1,
705                                                GtkTreeIter   *iter2,
706                                                gpointer       data)
707 {
708   return -1;
709 }
710
711 static gboolean
712 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
713                                                GtkTreeIter   *iter,
714                                                gpointer       data)
715 {
716   char *item = NULL;
717
718   /* Do reference the model */
719   gtk_tree_model_get (model, iter, 0, &item, -1);
720   g_free (item);
721
722   return FALSE;
723 }
724
725 static void
726 specific_sort_filter_remove_node (void)
727 {
728   /* This test is based on one of the test cases I found in my
729    * old test cases directory.  I unfortunately do not have a record
730    * from who this test case originated.  -Kris.
731    *
732    * General idea:
733    *  - Create tree store, sort, filter models.  The sort model has
734    *    a default sort func that is enabled, filter model a visible func
735    *    that defaults to returning FALSE.
736    *  - Remove a node from the tree store.
737    */
738
739   GtkTreeIter iter;
740   GtkTreeStore *store;
741   GtkTreeModel *filter;
742   GtkTreeModel *sort;
743
744   GtkWidget *window;
745   GtkWidget *tree_view;
746
747   store = gtk_tree_store_new (1, G_TYPE_STRING);
748   gtk_tree_store_append (store, &iter, NULL);
749   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
750
751   gtk_tree_store_append (store, &iter, NULL);
752   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
753
754   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
755   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
756                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
757
758   filter = gtk_tree_model_filter_new (sort, NULL);
759   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
760                                           specific_sort_filter_remove_node_visible_func,
761                                           filter, NULL);
762
763
764   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
765   tree_view = gtk_tree_view_new_with_model (filter);
766   gtk_container_add (GTK_CONTAINER (window), tree_view);
767   gtk_widget_realize (tree_view);
768
769   while (gtk_events_pending ())
770     gtk_main_iteration ();
771
772   /* Remove a node */
773   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
774   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
775   gtk_tree_store_remove (store, &iter);
776
777   while (gtk_events_pending ())
778     gtk_main_iteration ();
779 }
780
781
782 static void
783 specific_sort_filter_remove_root (void)
784 {
785   /* This test is based on one of the test cases I found in my
786    * old test cases directory.  I unfortunately do not have a record
787    * from who this test case originated.  -Kris.
788    */
789
790   GtkTreeModel *model, *sort, *filter;
791   GtkTreeIter root, mid, leaf;
792   GtkTreePath *path;
793
794   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
795   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
796   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
797   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
798
799   path = gtk_tree_model_get_path (model, &mid);
800
801   sort = gtk_tree_model_sort_new_with_model (model);
802   filter = gtk_tree_model_filter_new (sort, path);
803
804   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
805
806   g_object_unref (filter);
807   g_object_unref (sort);
808   g_object_unref (model);
809 }
810
811
812 static void
813 specific_filter_add_child (void)
814 {
815   /* This test is based on one of the test cases I found in my
816    * old test cases directory.  I unfortunately do not have a record
817    * from who this test case originated.  -Kris.
818    */
819
820   GtkTreeIter iter;
821   GtkTreeIter iter_first;
822   GtkTreeIter child;
823   GtkTreeStore *store;
824   GtkTreeModel *filter;
825
826   store = gtk_tree_store_new (1, G_TYPE_STRING);
827
828   gtk_tree_store_append (store, &iter_first, NULL);
829   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
830
831   gtk_tree_store_append (store, &iter, NULL);
832   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
833
834   gtk_tree_store_append (store, &iter, NULL);
835   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
836
837   gtk_tree_store_append (store, &iter, NULL);
838   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
839
840   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
841
842   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
843   gtk_tree_store_append (store, &child, &iter_first);
844   gtk_tree_store_set (store, &child, 0, "Hello", -1);
845 }
846
847
848 static void
849 specific_bug_300089 (void)
850 {
851   /* Test case for GNOME Bugzilla bug 300089.  Written by
852    * Matthias Clasen.
853    */
854   GtkTreeModel *sort_model, *child_model;
855   GtkTreePath *path;
856   GtkTreeIter iter, iter2, sort_iter;
857
858   child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
859
860   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
861   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
862   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
863   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
864
865   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
866   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
867   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
868   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
869
870   gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
871   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
872
873
874   sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
875   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
876                                         0, GTK_SORT_ASCENDING);
877
878   path = gtk_tree_path_new_from_indices (1, 1, -1);
879
880   /* make sure a level is constructed */ 
881   gtk_tree_model_get_iter (sort_model, &sort_iter, path);
882
883   /* change the "E" row in a way that causes it to change position */ 
884   gtk_tree_model_get_iter (child_model, &iter, path);
885   gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
886 }
887
888
889 static int
890 specific_bug_301558_sort_func (GtkTreeModel *model,
891                                GtkTreeIter  *a,
892                                GtkTreeIter  *b,
893                                gpointer      data)
894 {
895   int i, j;
896
897   gtk_tree_model_get (model, a, 0, &i, -1);
898   gtk_tree_model_get (model, b, 0, &j, -1);
899
900   return j - i;
901 }
902
903 static void
904 specific_bug_301558 (void)
905 {
906   /* Test case for GNOME Bugzilla bug 301558 provided by
907    * Markku Vire.
908    */
909   GtkTreeStore *tree;
910   GtkTreeModel *filter;
911   GtkTreeModel *sort;
912   GtkTreeIter root, iter, iter2;
913   GtkWidget *view;
914   int i;
915   gboolean add;
916
917   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
918   gtk_tree_store_append (tree, &iter, NULL);
919   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
920   gtk_tree_store_append (tree, &iter2, &iter);
921   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
922
923   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
924   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
925                                            specific_bug_301558_sort_func,
926                                            NULL, NULL);
927
928   filter = gtk_tree_model_filter_new (sort, NULL);
929   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
930
931   view = gtk_tree_view_new_with_model (filter);
932
933   while (gtk_events_pending ())
934     gtk_main_iteration ();
935
936   add = TRUE;
937
938   for (i = 0; i < 10; i++)
939     {
940       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
941         g_assert_not_reached ();
942
943       if (add)
944         {
945           gtk_tree_store_append (tree, &iter, &root);
946           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
947         }
948       else
949         {
950           int n;
951           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
952           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
953                                          &root, n - 1);
954           gtk_tree_store_remove (tree, &iter);
955         }
956
957       add = !add;
958     }
959 }
960
961
962 static gboolean
963 specific_bug_311955_filter_func (GtkTreeModel *model,
964                                  GtkTreeIter  *iter,
965                                  gpointer      data)
966 {
967   int value;
968
969   gtk_tree_model_get (model, iter, 0, &value, -1);
970
971   return (value != 0);
972 }
973
974 static void
975 specific_bug_311955 (void)
976 {
977   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
978    * by Markku Vire.
979    */
980   GtkTreeIter iter, child, root;
981   GtkTreeStore *store;
982   GtkTreeModel *sort;
983   GtkTreeModel *filter;
984
985   GtkWidget *window;
986   GtkWidget *tree_view;
987   int i;
988   int n;
989
990   store = gtk_tree_store_new (1, G_TYPE_INT);
991
992   gtk_tree_store_append (store, &root, NULL);
993   gtk_tree_store_set (store, &root, 0, 33, -1);
994
995   gtk_tree_store_append (store, &iter, &root);
996   gtk_tree_store_set (store, &iter, 0, 50, -1);
997
998   gtk_tree_store_append (store, &iter, NULL);
999   gtk_tree_store_set (store, &iter, 0, 22, -1);
1000
1001   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1002   filter = gtk_tree_model_filter_new (sort, NULL);
1003
1004   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
1005                                           specific_bug_311955_filter_func,
1006                                           NULL, NULL);
1007
1008   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1009   tree_view = gtk_tree_view_new_with_model (filter);
1010   g_object_unref (store);
1011
1012   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
1013
1014   while (gtk_events_pending ())
1015     gtk_main_iteration ();
1016
1017   /* Fill model */
1018   for (i = 0; i < 4; i++)
1019     {
1020       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1021
1022       gtk_tree_store_append (store, &iter, &root);
1023
1024       if (i < 3)
1025         gtk_tree_store_set (store, &iter, 0, i, -1);
1026
1027       if (i % 2 == 0)
1028         {
1029           gtk_tree_store_append (store, &child, &iter);
1030           gtk_tree_store_set (store, &child, 0, 10, -1);
1031         }
1032     }
1033
1034   while (gtk_events_pending ())
1035     gtk_main_iteration ();
1036
1037   /* Remove bottommost child from the tree. */
1038   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
1039   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
1040
1041   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
1042     {
1043       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
1044         gtk_tree_store_remove (store, &child);
1045     }
1046   else
1047     g_assert_not_reached ();
1048 }
1049
1050 static void
1051 specific_bug_346800 (void)
1052 {
1053   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
1054    * by Jonathan Matthew.
1055    */
1056
1057   GtkTreeIter node_iters[50];
1058   GtkTreeIter child_iters[50];
1059   GtkTreeModel *model;
1060   GtkTreeModelFilter *filter;
1061   GtkTreeStore *store;
1062   GType *columns;
1063   int i;
1064   int items = 50;
1065   columns = g_new (GType, 2);
1066   columns[0] = G_TYPE_STRING;
1067   columns[1] = G_TYPE_BOOLEAN;
1068   store = gtk_tree_store_newv (2, columns);
1069   model = GTK_TREE_MODEL (store);
1070
1071   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
1072   gtk_tree_model_filter_set_visible_column (filter, 1);
1073
1074   for (i=0; i<items; i++)
1075     {
1076       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
1077
1078       g_malloc (138);
1079       gtk_tree_store_append (store, &node_iters[i], NULL);
1080       gtk_tree_store_set (store, &node_iters[i],
1081                           0, "something",
1082                           1, ((i%6) == 0) ? FALSE : TRUE,
1083                           -1);
1084
1085       g_malloc (47);
1086       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
1087       gtk_tree_store_set (store, &child_iters[i],
1088                           0, "something else",
1089                           1, FALSE,
1090                           -1);
1091       gtk_tree_model_filter_refilter (filter);
1092
1093       if (i > 6)
1094         {
1095           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
1096                               (i & 1) ? TRUE : FALSE, -1);
1097           gtk_tree_model_filter_refilter (filter);
1098
1099           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
1100                               (i & 1) ? FALSE: TRUE, -1);
1101           gtk_tree_model_filter_refilter (filter);
1102         }
1103     }
1104 }
1105
1106
1107 static void
1108 specific_bug_364946 (void)
1109 {
1110   /* This is a test case for GNOME Bugzilla bug 364946.  It was written
1111    * by Andreas Koehler.
1112    */
1113   GtkTreeStore *store;
1114   GtkTreeIter a, aa, aaa, aab, iter;
1115   GtkTreeModel *s_model;
1116
1117   store = gtk_tree_store_new (1, G_TYPE_STRING);
1118
1119   gtk_tree_store_append (store, &a, NULL);
1120   gtk_tree_store_set (store, &a, 0, "0", -1);
1121
1122   gtk_tree_store_append (store, &aa, &a);
1123   gtk_tree_store_set (store, &aa, 0, "0:0", -1);
1124
1125   gtk_tree_store_append (store, &aaa, &aa);
1126   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1127
1128   gtk_tree_store_append (store, &aab, &aa);
1129   gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
1130
1131   s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
1132   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
1133                                         GTK_SORT_ASCENDING);
1134
1135   gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
1136
1137   gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
1138   gtk_tree_store_remove (store, &aaa);
1139   gtk_tree_store_remove (store, &aab);
1140
1141   gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
1142 }
1143
1144 /* main */
1145
1146 int
1147 main (int    argc,
1148       char **argv)
1149 {
1150   gtk_test_init (&argc, &argv, NULL);
1151
1152   g_test_add ("/FilterModel/self/verify-test-suite",
1153               FilterTest, NULL,
1154               filter_test_setup,
1155               verify_test_suite,
1156               filter_test_teardown);
1157
1158   g_test_add ("/FilterModel/filled/hide-root-level",
1159               FilterTest, NULL,
1160               filter_test_setup,
1161               filled_hide_root_level,
1162               filter_test_teardown);
1163   g_test_add ("/FilterModel/filled/hide-child-levels",
1164               FilterTest, NULL,
1165               filter_test_setup,
1166               filled_hide_child_levels,
1167               filter_test_teardown);
1168
1169   g_test_add ("/FilterModel/empty/show-nodes",
1170               FilterTest, NULL,
1171               filter_test_setup_empty,
1172               empty_show_nodes,
1173               filter_test_teardown);
1174
1175   g_test_add ("/FilterModel/unfiltered/hide-single",
1176               FilterTest, NULL,
1177               filter_test_setup_unfiltered,
1178               unfiltered_hide_single,
1179               filter_test_teardown);
1180   g_test_add ("/FilterModel/unfiltered/hide-single-child",
1181               FilterTest, NULL,
1182               filter_test_setup_unfiltered,
1183               unfiltered_hide_single_child,
1184               filter_test_teardown);
1185   g_test_add ("/FilterModel/unfiltered/hide-single-multi-level",
1186               FilterTest, NULL,
1187               filter_test_setup_unfiltered,
1188               unfiltered_hide_single_multi_level,
1189               filter_test_teardown);
1190
1191   g_test_add ("/FilterModel/unfiltered/show-single",
1192               FilterTest, NULL,
1193               filter_test_setup_empty_unfiltered,
1194               unfiltered_show_single,
1195               filter_test_teardown);
1196   g_test_add ("/FilterModel/unfiltered/show-single-child",
1197               FilterTest, NULL,
1198               filter_test_setup_empty_unfiltered,
1199               unfiltered_show_single_child,
1200               filter_test_teardown);
1201   g_test_add ("/FilterModel/unfiltered/show-single-multi-level",
1202               FilterTest, NULL,
1203               filter_test_setup_empty_unfiltered,
1204               unfiltered_show_single_multi_level,
1205               filter_test_teardown);
1206
1207
1208   g_test_add_func ("/FilterModel/specific/path-dependent-filter",
1209                    specific_path_dependent_filter);
1210   g_test_add_func ("/FilterModel/specific/append-after-collapse",
1211                    specific_append_after_collapse);
1212   g_test_add_func ("/FilterModel/specific/sort-filter-remove-node",
1213                    specific_sort_filter_remove_node);
1214   g_test_add_func ("/FilterModel/specific/sort-filter-remove-root",
1215                    specific_sort_filter_remove_root);
1216   g_test_add_func ("/FilterModel/specific/filter-add-child",
1217                    specific_filter_add_child);
1218
1219   g_test_add_func ("/FilterModel/specific/bug-300089",
1220                    specific_bug_300089);
1221   g_test_add_func ("/FilterModel/specific/bug-301558",
1222                    specific_bug_301558);
1223   g_test_add_func ("/FilterModel/specific/bug-311955",
1224                    specific_bug_311955);
1225   g_test_add_func ("/FilterModel/specific/bug-346800",
1226                    specific_bug_346800);
1227   g_test_add_func ("/FilterModel/specific/bug-364946",
1228                    specific_bug_364946);
1229
1230   return g_test_run ();
1231 }