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