]> Pileus Git - ~andy/gtk/blob - gtk/tests/filtermodel.c
0185e25f89584732a35ce12b9b29afc8f26ebd9d
[~andy/gtk] / gtk / tests / filtermodel.c
1 /* Extensive GtkTreeModelFilter tests.
2  * Copyright (C) 2009,2011  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 #include "treemodel.h"
23 #include "gtktreemodelrefcount.h"
24
25 /* Left to do:
26  *   - Proper coverage checking to see if the unit tests cover
27  *     all possible cases.
28  *   - Check if the iterator stamp is incremented at the correct times.
29  */
30
31
32 /*
33  * Model creation
34  */
35
36 #define LEVEL_LENGTH 5
37
38 static void
39 create_tree_store_set_values (GtkTreeStore *store,
40                               GtkTreeIter  *iter,
41                               gboolean      visible)
42 {
43   GtkTreePath *path;
44   gchar *path_string;
45
46   path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
47   path_string = gtk_tree_path_to_string (path);
48
49   gtk_tree_store_set (store, iter,
50                       0, path_string,
51                       1, visible,
52                       -1);
53
54   gtk_tree_path_free (path);
55   g_free (path_string);
56 }
57
58 static void
59 create_tree_store_recurse (int           depth,
60                            GtkTreeStore *store,
61                            GtkTreeIter  *parent,
62                            gboolean      visible)
63 {
64   int i;
65
66   for (i = 0; i < LEVEL_LENGTH; i++)
67     {
68       GtkTreeIter iter;
69
70       gtk_tree_store_insert (store, &iter, parent, i);
71       create_tree_store_set_values (store, &iter, visible);
72
73       if (depth > 0)
74         create_tree_store_recurse (depth - 1, store, &iter, visible);
75     }
76 }
77
78 static GtkTreeStore *
79 create_tree_store (int      depth,
80                    gboolean visible)
81 {
82   GtkTreeStore *store;
83
84   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
85
86   create_tree_store_recurse (depth, store, NULL, visible);
87
88   return store;
89 }
90
91 /*
92  * Signal monitor
93  */
94
95 typedef enum
96 {
97   ROW_INSERTED,
98   ROW_DELETED,
99   ROW_CHANGED,
100   ROW_HAS_CHILD_TOGGLED,
101   ROWS_REORDERED,
102   LAST_SIGNAL
103 }
104 SignalName;
105
106 static const char *
107 signal_name_to_string (SignalName signal)
108 {
109   switch (signal)
110     {
111       case ROW_INSERTED:
112           return "row-inserted";
113
114       case ROW_DELETED:
115           return "row-deleted";
116
117       case ROW_CHANGED:
118           return "row-changed";
119
120       case ROW_HAS_CHILD_TOGGLED:
121           return "row-has-child-toggled";
122
123       case ROWS_REORDERED:
124           return "rows-reordered";
125
126       default:
127           /* Fall through */
128           break;
129     }
130
131   return "(unknown)";
132 }
133
134 typedef struct
135 {
136   SignalName signal;
137   GtkTreePath *path;
138
139   /* For rows-reordered */
140   int *new_order;
141   int len;
142 }
143 Signal;
144
145
146 static Signal *
147 signal_new (SignalName signal, GtkTreePath *path)
148 {
149   Signal *s;
150
151   s = g_new0 (Signal, 1);
152   s->signal = signal;
153   s->path = gtk_tree_path_copy (path);
154   s->new_order = NULL;
155
156   return s;
157 }
158
159 static Signal *
160 signal_new_with_order (SignalName signal, GtkTreePath *path,
161                        int *new_order, int len)
162 {
163   Signal *s = signal_new (signal, path);
164
165   s->new_order = new_order;
166   s->len = len;
167
168   return s;
169 }
170
171 static void
172 signal_free (Signal *s)
173 {
174   if (s->path)
175     gtk_tree_path_free (s->path);
176
177   g_free (s);
178 }
179
180
181 typedef struct
182 {
183   GQueue *queue;
184   GtkTreeModel *client;
185   gulong signal_ids[LAST_SIGNAL];
186 }
187 SignalMonitor;
188
189
190 static void
191 signal_monitor_generic_handler (SignalMonitor *m,
192                                 SignalName     signal,
193                                 GtkTreeModel  *model,
194                                 GtkTreeIter   *iter,
195                                 GtkTreePath   *path,
196                                 int           *new_order)
197 {
198   Signal *s;
199
200   if (g_queue_is_empty (m->queue))
201     {
202       gchar *path_str;
203
204       path_str = gtk_tree_path_to_string (path);
205       g_error ("Signal queue empty, got signal %s path %s\n",
206                signal_name_to_string (signal), path_str);
207       g_free (path_str);
208
209       g_assert_not_reached ();
210     }
211
212   if (m->client != model)
213     {
214       g_error ("Model mismatch; expected %p, got %p\n",
215                m->client, model);
216       g_assert_not_reached ();
217     }
218
219   s = g_queue_peek_tail (m->queue);
220
221 #if 0
222   /* For debugging: output signals that are coming in.  Leaks memory. */
223   g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
224            gtk_tree_path_to_string (path));
225 #endif
226
227   if (s->signal != signal ||
228       (gtk_tree_path_get_depth (s->path) == 0 &&
229        gtk_tree_path_get_depth (path) != 0) ||
230       (gtk_tree_path_get_depth (s->path) != 0 &&
231        gtk_tree_path_compare (s->path, path) != 0))
232     {
233       gchar *path_str, *s_path_str;
234
235       s_path_str = gtk_tree_path_to_string (s->path);
236       path_str = gtk_tree_path_to_string (path);
237
238       g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
239                signal_name_to_string (s->signal), s_path_str,
240                signal_name_to_string (signal), path_str);
241
242       g_free (s_path_str);
243       g_free (path_str);
244
245       g_assert_not_reached ();
246     }
247
248   if (signal == ROWS_REORDERED && s->new_order != NULL)
249     {
250       int i, len;
251
252       g_assert (new_order != NULL);
253
254       len = gtk_tree_model_iter_n_children (model, iter);
255       g_assert (s->len == len);
256
257       for (i = 0; i < len; i++)
258         g_assert (s->new_order[i] == new_order[i]);
259     }
260
261   s = g_queue_pop_tail (m->queue);
262
263   signal_free (s);
264 }
265
266 static void
267 signal_monitor_row_inserted (GtkTreeModel *model,
268                              GtkTreePath  *path,
269                              GtkTreeIter  *iter,
270                              gpointer      data)
271 {
272   signal_monitor_generic_handler (data, ROW_INSERTED,
273                                   model, iter, path, NULL);
274 }
275
276 static void
277 signal_monitor_row_deleted (GtkTreeModel *model,
278                             GtkTreePath  *path,
279                             gpointer      data)
280 {
281   signal_monitor_generic_handler (data, ROW_DELETED,
282                                   model, NULL, path, NULL);
283 }
284
285 static void
286 signal_monitor_row_changed (GtkTreeModel *model,
287                             GtkTreePath  *path,
288                             GtkTreeIter  *iter,
289                             gpointer      data)
290 {
291   signal_monitor_generic_handler (data, ROW_CHANGED,
292                                   model, iter, path, NULL);
293 }
294
295 static void
296 signal_monitor_row_has_child_toggled (GtkTreeModel *model,
297                                       GtkTreePath  *path,
298                                       GtkTreeIter  *iter,
299                                       gpointer      data)
300 {
301   signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
302                                   model, iter, path, NULL);
303 }
304
305 static void
306 signal_monitor_rows_reordered (GtkTreeModel *model,
307                                GtkTreePath  *path,
308                                GtkTreeIter  *iter,
309                                gint         *new_order,
310                                gpointer      data)
311 {
312   signal_monitor_generic_handler (data, ROWS_REORDERED,
313                                   model, iter, path, new_order);
314 }
315
316 static SignalMonitor *
317 signal_monitor_new (GtkTreeModel *client)
318 {
319   SignalMonitor *m;
320
321   m = g_new0 (SignalMonitor, 1);
322   m->client = g_object_ref (client);
323   m->queue = g_queue_new ();
324
325   m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
326                                                   "row-inserted",
327                                                   G_CALLBACK (signal_monitor_row_inserted),
328                                                   m);
329   m->signal_ids[ROW_DELETED] = g_signal_connect (client,
330                                                  "row-deleted",
331                                                  G_CALLBACK (signal_monitor_row_deleted),
332                                                  m);
333   m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
334                                                  "row-changed",
335                                                  G_CALLBACK (signal_monitor_row_changed),
336                                                  m);
337   m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
338                                                            "row-has-child-toggled",
339                                                            G_CALLBACK (signal_monitor_row_has_child_toggled),
340                                                            m);
341   m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
342                                                     "rows-reordered",
343                                                     G_CALLBACK (signal_monitor_rows_reordered),
344                                                     m);
345
346   return m;
347 }
348
349 static void
350 signal_monitor_free (SignalMonitor *m)
351 {
352   int i;
353
354   for (i = 0; i < LAST_SIGNAL; i++)
355     g_signal_handler_disconnect (m->client, m->signal_ids[i]);
356
357   g_object_unref (m->client);
358
359   if (m->queue)
360     g_queue_free (m->queue);
361
362   g_free (m);
363 }
364
365 static void
366 signal_monitor_assert_is_empty (SignalMonitor *m)
367 {
368   g_assert (g_queue_is_empty (m->queue));
369 }
370
371 static void
372 signal_monitor_append_signal_path (SignalMonitor *m,
373                                    SignalName     signal,
374                                    GtkTreePath   *path)
375 {
376   Signal *s;
377
378   s = signal_new (signal, path);
379   g_queue_push_head (m->queue, s);
380 }
381
382 static void
383 signal_monitor_append_signal_reordered (SignalMonitor *m,
384                                         SignalName     signal,
385                                         GtkTreePath   *path,
386                                         int           *new_order,
387                                         int            len)
388 {
389   Signal *s;
390
391   s = signal_new_with_order (signal, path, new_order, len);
392   g_queue_push_head (m->queue, s);
393 }
394
395 static void
396 signal_monitor_append_signal (SignalMonitor *m,
397                               SignalName     signal,
398                               const gchar   *path_string)
399 {
400   Signal *s;
401   GtkTreePath *path;
402
403   path = gtk_tree_path_new_from_string (path_string);
404
405   s = signal_new (signal, path);
406   g_queue_push_head (m->queue, s);
407
408   gtk_tree_path_free (path);
409 }
410
411 /*
412  * Fixture
413  */
414
415 typedef struct
416 {
417   GtkWidget *tree_view;
418
419   GtkTreeStore *store;
420   GtkTreeModelFilter *filter;
421
422   SignalMonitor *monitor;
423
424   guint block_signals : 1;
425 } FilterTest;
426
427
428 static void
429 filter_test_store_signal (FilterTest *fixture)
430 {
431   if (fixture->block_signals)
432     g_signal_stop_emission_by_name (fixture->store, "row-changed");
433 }
434
435
436 static void
437 filter_test_setup_generic (FilterTest    *fixture,
438                            gconstpointer  test_data,
439                            int            depth,
440                            gboolean       empty,
441                            gboolean       unfiltered)
442 {
443   const GtkTreePath *vroot = test_data;
444   GtkTreeModel *filter;
445
446   fixture->store = create_tree_store (depth, !empty);
447
448   g_signal_connect_swapped (fixture->store, "row-changed",
449                             G_CALLBACK (filter_test_store_signal), fixture);
450
451   /* Please forgive me for casting const away. */
452   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
453                                       (GtkTreePath *)vroot);
454   fixture->filter = GTK_TREE_MODEL_FILTER (filter);
455
456   if (!unfiltered)
457     gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
458
459   /* We need a tree view that's listening to get ref counting from that
460    * side.
461    */
462   fixture->tree_view = gtk_tree_view_new_with_model (filter);
463
464   fixture->monitor = signal_monitor_new (filter);
465 }
466
467 static void
468 filter_test_setup_expand_root (FilterTest *fixture)
469 {
470   int i;
471   GtkTreePath *path;
472
473   path = gtk_tree_path_new_from_indices (0, -1);
474
475   for (i = 0; i < LEVEL_LENGTH; i++)
476     {
477       gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
478                                 path, FALSE);
479       gtk_tree_path_next (path);
480     }
481   gtk_tree_path_free (path);
482 }
483
484 static void
485 filter_test_setup (FilterTest    *fixture,
486                    gconstpointer  test_data)
487 {
488   filter_test_setup_generic (fixture, test_data, 3, FALSE, FALSE);
489 }
490
491 static void
492 filter_test_setup_empty (FilterTest    *fixture,
493                          gconstpointer  test_data)
494 {
495   filter_test_setup_generic (fixture, test_data, 3, TRUE, FALSE);
496 }
497
498 static void
499 filter_test_setup_unfiltered (FilterTest    *fixture,
500                               gconstpointer  test_data)
501 {
502   filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
503 }
504
505 static void
506 filter_test_setup_unfiltered_root_expanded (FilterTest    *fixture,
507                                             gconstpointer  test_data)
508 {
509   filter_test_setup_unfiltered (fixture, test_data);
510   filter_test_setup_expand_root (fixture);
511 }
512
513 static void
514 filter_test_setup_empty_unfiltered (FilterTest    *fixture,
515                                     gconstpointer  test_data)
516 {
517   filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
518 }
519
520 static void
521 filter_test_setup_empty_unfiltered_root_expanded (FilterTest    *fixture,
522                                                   gconstpointer  test_data)
523 {
524   filter_test_setup_empty_unfiltered (fixture, test_data);
525   filter_test_setup_expand_root (fixture);
526 }
527
528 static GtkTreePath *
529 strip_virtual_root (GtkTreePath *path,
530                     GtkTreePath *root_path)
531 {
532   GtkTreePath *real_path;
533
534   if (root_path)
535     {
536       int j;
537       int depth = gtk_tree_path_get_depth (path);
538       int root_depth = gtk_tree_path_get_depth (root_path);
539
540       real_path = gtk_tree_path_new ();
541
542       for (j = 0; j < depth - root_depth; j++)
543         gtk_tree_path_append_index (real_path,
544                                     gtk_tree_path_get_indices (path)[root_depth + j]);
545     }
546   else
547     real_path = gtk_tree_path_copy (path);
548
549   return real_path;
550 }
551
552 static int
553 count_visible (FilterTest  *fixture,
554                GtkTreePath *store_path)
555 {
556   int i;
557   int n_visible = 0;
558   GtkTreeIter iter;
559
560   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
561                            &iter, store_path);
562
563   for (i = 0; i < LEVEL_LENGTH; i++)
564     {
565       gboolean visible;
566
567       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
568                           1, &visible,
569                           -1);
570
571       if (visible)
572         n_visible++;
573     }
574
575   return n_visible;
576 }
577
578 static void
579 filter_test_append_refilter_signals_recurse (FilterTest  *fixture,
580                                              GtkTreePath *store_path,
581                                              GtkTreePath *filter_path,
582                                              int          depth,
583                                              GtkTreePath *root_path)
584 {
585   int i;
586   int rows_deleted = 0;
587   GtkTreeIter iter;
588
589   gtk_tree_path_down (store_path);
590   gtk_tree_path_down (filter_path);
591
592   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
593                            &iter, store_path);
594
595   for (i = 0; i < LEVEL_LENGTH; i++)
596     {
597       gboolean visible;
598       GtkTreePath *real_path;
599
600       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
601                           1, &visible,
602                           -1);
603
604       if (root_path &&
605           (!gtk_tree_path_is_descendant (store_path, root_path)
606            || !gtk_tree_path_compare (store_path, root_path)))
607         {
608           if (!gtk_tree_path_compare (store_path, root_path))
609             {
610               if (depth > 1
611                   && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
612                                                     &iter))
613                 {
614                   GtkTreePath *store_copy;
615                   GtkTreePath *filter_copy;
616
617                   store_copy = gtk_tree_path_copy (store_path);
618                   filter_copy = gtk_tree_path_copy (filter_path);
619                   filter_test_append_refilter_signals_recurse (fixture,
620                                                                store_copy,
621                                                                filter_copy,
622                                                                depth - 1,
623                                                                root_path);
624                   gtk_tree_path_free (store_copy);
625                   gtk_tree_path_free (filter_copy);
626                 }
627             }
628
629           gtk_tree_path_next (store_path);
630           gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
631
632           if (visible)
633             gtk_tree_path_next (filter_path);
634
635           continue;
636         }
637
638       real_path = strip_virtual_root (filter_path, root_path);
639
640       if (visible)
641         {
642           /* This row will be inserted */
643           signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
644                                              real_path);
645
646           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
647                                              &iter))
648             {
649               signal_monitor_append_signal_path (fixture->monitor,
650                                                  ROW_HAS_CHILD_TOGGLED,
651                                                  real_path);
652
653               if (depth > 1)
654                 {
655                   GtkTreePath *store_copy;
656                   GtkTreePath *filter_copy;
657
658                   store_copy = gtk_tree_path_copy (store_path);
659                   filter_copy = gtk_tree_path_copy (filter_path);
660                   filter_test_append_refilter_signals_recurse (fixture,
661                                                                store_copy,
662                                                                filter_copy,
663                                                                depth - 1,
664                                                                root_path);
665                   gtk_tree_path_free (store_copy);
666                   gtk_tree_path_free (filter_copy);
667                 }
668               else if (depth == 1)
669                 {
670                   GtkTreePath *tmp_path;
671
672                   /* If all child rows are invisible, then the last row to
673                    * become invisible will emit row-has-child-toggled on the
674                    * parent.
675                    */
676
677                   tmp_path = gtk_tree_path_copy (store_path);
678                   gtk_tree_path_append_index (tmp_path, 0);
679
680                   if (count_visible (fixture, tmp_path) == 0)
681                     signal_monitor_append_signal_path (fixture->monitor,
682                                                        ROW_HAS_CHILD_TOGGLED,
683                                                        real_path);
684
685                   gtk_tree_path_free (tmp_path);
686                 }
687             }
688
689           gtk_tree_path_next (filter_path);
690         }
691       else
692         {
693           /* This row will be deleted */
694           rows_deleted++;
695           signal_monitor_append_signal_path (fixture->monitor, ROW_DELETED,
696                                              real_path);
697         }
698
699       gtk_tree_path_free (real_path);
700
701       gtk_tree_path_next (store_path);
702       gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
703     }
704
705   if (rows_deleted == LEVEL_LENGTH
706       && gtk_tree_path_get_depth (filter_path) > 1)
707     {
708       GtkTreePath *real_path;
709
710       gtk_tree_path_up (store_path);
711       gtk_tree_path_up (filter_path);
712
713       /* A row-has-child-toggled will be emitted on the parent */
714       if (!root_path
715           || (root_path
716               && gtk_tree_path_is_descendant (store_path, root_path)
717               && gtk_tree_path_compare (store_path, root_path)))
718         {
719           real_path = strip_virtual_root (filter_path, root_path);
720           signal_monitor_append_signal_path (fixture->monitor,
721                                              ROW_HAS_CHILD_TOGGLED,
722                                              real_path);
723
724           gtk_tree_path_free (real_path);
725         }
726     }
727 }
728
729 static void
730 filter_test_append_refilter_signals (FilterTest *fixture,
731                                      int         depth)
732 {
733   /* A special function that walks the tree store like the
734    * model validation functions below.
735    */
736   GtkTreePath *path;
737   GtkTreePath *filter_path;
738
739   path = gtk_tree_path_new ();
740   filter_path = gtk_tree_path_new ();
741   filter_test_append_refilter_signals_recurse (fixture,
742                                                path,
743                                                filter_path,
744                                                depth,
745                                                NULL);
746   gtk_tree_path_free (path);
747   gtk_tree_path_free (filter_path);
748 }
749
750 static void
751 filter_test_append_refilter_signals_with_vroot (FilterTest  *fixture,
752                                                 int          depth,
753                                                 GtkTreePath *root_path)
754 {
755   /* A special function that walks the tree store like the
756    * model validation functions below.
757    */
758   GtkTreePath *path;
759   GtkTreePath *filter_path;
760
761   path = gtk_tree_path_new ();
762   filter_path = gtk_tree_path_new ();
763   filter_test_append_refilter_signals_recurse (fixture,
764                                                path,
765                                                filter_path,
766                                                depth,
767                                                root_path);
768   gtk_tree_path_free (path);
769   gtk_tree_path_free (filter_path);
770 }
771
772 static void
773 filter_test_enable_filter (FilterTest *fixture)
774 {
775   gtk_tree_model_filter_set_visible_column (fixture->filter, 1);
776   gtk_tree_model_filter_refilter (fixture->filter);
777 }
778
779 static void
780 filter_test_block_signals (FilterTest *fixture)
781 {
782   fixture->block_signals = TRUE;
783 }
784
785 static void
786 filter_test_unblock_signals (FilterTest *fixture)
787 {
788   fixture->block_signals = FALSE;
789 }
790
791 static void
792 filter_test_teardown (FilterTest    *fixture,
793                       gconstpointer  test_data)
794 {
795   signal_monitor_free (fixture->monitor);
796
797   gtk_widget_destroy (fixture->tree_view);
798
799   g_object_unref (fixture->filter);
800   g_object_unref (fixture->store);
801 }
802
803 /*
804  * Model structure validation
805  */
806
807 static void
808 check_filter_model_recurse (FilterTest  *fixture,
809                             GtkTreePath *store_parent_path,
810                             GtkTreePath *filter_parent_path)
811 {
812   int i;
813   GtkTreeIter store_iter;
814   GtkTreeIter filter_iter;
815   gboolean store_has_next, filter_has_next;
816
817   gtk_tree_path_down (store_parent_path);
818   gtk_tree_path_down (filter_parent_path);
819
820   store_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
821                                             &store_iter, store_parent_path);
822   filter_has_next = gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->filter),
823                                              &filter_iter, filter_parent_path);
824
825   for (i = 0; i < LEVEL_LENGTH; i++)
826     {
827       gboolean visible;
828
829       g_return_if_fail (store_has_next == TRUE);
830
831       gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
832                           &store_iter,
833                           1, &visible,
834                           -1);
835
836       if (visible)
837         {
838           GtkTreePath *tmp;
839           gchar *filter_str, *store_str;
840
841           g_return_if_fail (filter_has_next == TRUE);
842
843           /* Verify path */
844           tmp = gtk_tree_model_get_path (GTK_TREE_MODEL (fixture->filter),
845                                          &filter_iter);
846           g_return_if_fail (gtk_tree_path_compare (tmp, filter_parent_path) == 0);
847
848           /* Verify model content */
849           gtk_tree_model_get (GTK_TREE_MODEL (fixture->store),
850                               &store_iter,
851                               0, &store_str,
852                               -1);
853           gtk_tree_model_get (GTK_TREE_MODEL (fixture->filter),
854                               &filter_iter,
855                               0, &filter_str,
856                               -1);
857
858           g_return_if_fail (g_strcmp0 (store_str, filter_str) == 0);
859
860           g_free (store_str);
861           g_free (filter_str);
862
863           if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->filter),
864                                              &filter_iter))
865             {
866               g_return_if_fail (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store), &store_iter));
867
868               check_filter_model_recurse (fixture,
869                                           gtk_tree_path_copy (store_parent_path),
870                                           tmp);
871             }
872           else
873             /* Only when we do not recurse we need to free tmp */
874             gtk_tree_path_free (tmp);
875
876           gtk_tree_path_next (filter_parent_path);
877           filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
878         }
879
880       gtk_tree_path_next (store_parent_path);
881       store_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &store_iter);
882     }
883
884   /* Both models should have no more content! */
885   g_return_if_fail (store_has_next == FALSE);
886   g_return_if_fail (filter_has_next == FALSE);
887
888   gtk_tree_path_free (store_parent_path);
889   gtk_tree_path_free (filter_parent_path);
890 }
891
892 static void
893 check_filter_model (FilterTest *fixture)
894 {
895   GtkTreePath *path;
896
897   if (fixture->monitor)
898     signal_monitor_assert_is_empty (fixture->monitor);
899
900   path = gtk_tree_path_new ();
901
902   check_filter_model_recurse (fixture, path, gtk_tree_path_copy (path));
903 }
904
905 static void
906 check_filter_model_with_root (FilterTest  *fixture,
907                               GtkTreePath *path)
908 {
909   if (fixture->monitor)
910     signal_monitor_assert_is_empty (fixture->monitor);
911
912   check_filter_model_recurse (fixture,
913                               gtk_tree_path_copy (path),
914                               gtk_tree_path_new ());
915 }
916
917 /* Helpers */
918
919 static void
920 check_level_length (GtkTreeModelFilter *filter,
921                     const gchar        *level,
922                     const int           expected_length)
923 {
924   if (!level)
925     {
926       int model_length;
927
928       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
929       g_assert_cmpint (model_length, ==, expected_length);
930     }
931   else
932     {
933       int model_length;
934       gboolean retrieved_iter = FALSE;
935       GtkTreeIter iter;
936
937       retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
938                                                             &iter, level);
939       g_return_if_fail (retrieved_iter);
940       model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
941       g_assert_cmpint (model_length, ==, expected_length);
942     }
943 }
944
945 static void
946 set_path_visibility (FilterTest  *fixture,
947                      const gchar *path,
948                      gboolean     visible)
949 {
950   GtkTreeIter store_iter;
951
952   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
953                                        &store_iter, path);
954   gtk_tree_store_set (fixture->store, &store_iter,
955                       1, visible,
956                       -1);
957 }
958
959 #if 0
960 static void
961 insert_path_with_visibility (FilterTest  *fixture,
962                              const gchar *path_string,
963                              gboolean     visible)
964 {
965   int position;
966   GtkTreePath *path;
967   GtkTreeIter parent, iter;
968
969   path = gtk_tree_path_new_from_string (path_string);
970   position = gtk_tree_path_get_indices (path)[gtk_tree_path_get_depth (path)];
971   gtk_tree_path_up (path);
972
973   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &parent, path))
974     {
975       gtk_tree_store_insert (fixture->store, &iter, &parent, position);
976       create_tree_store_set_values (fixture->store, &iter, visible);
977     }
978   gtk_tree_path_free (path);
979 }
980 #endif
981
982 /*
983  * The actual tests.
984  */
985
986 static void
987 verify_test_suite (FilterTest    *fixture,
988                    gconstpointer  user_data)
989 {
990   check_filter_model (fixture);
991 }
992
993 static void
994 verify_test_suite_vroot (FilterTest    *fixture,
995                          gconstpointer  user_data)
996 {
997   check_filter_model_with_root (fixture, (GtkTreePath *)user_data);
998 }
999
1000
1001 static void
1002 filled_hide_root_level (FilterTest    *fixture,
1003                         gconstpointer  user_data)
1004 {
1005   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1006   set_path_visibility (fixture, "2", FALSE);
1007   check_filter_model (fixture);
1008   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1009
1010   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1011   set_path_visibility (fixture, "0", FALSE);
1012   check_filter_model (fixture);
1013   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1014
1015   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1016   set_path_visibility (fixture, "4", FALSE);
1017   check_filter_model (fixture);
1018   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
1019
1020
1021   /* Hide remaining */
1022   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1023   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1024
1025   set_path_visibility (fixture, "1", FALSE);
1026   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1027
1028   set_path_visibility (fixture, "3", FALSE);
1029   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 5);
1030
1031   check_filter_model (fixture);
1032
1033   /* Show some */
1034   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1035   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1036   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1037   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1038
1039   set_path_visibility (fixture, "1", TRUE);
1040   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1041
1042   set_path_visibility (fixture, "3", TRUE);
1043   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 3);
1044
1045   check_filter_model (fixture);
1046 }
1047
1048 static void
1049 filled_hide_child_levels (FilterTest    *fixture,
1050                           gconstpointer  user_data)
1051 {
1052   set_path_visibility (fixture, "0:2", FALSE);
1053   check_filter_model (fixture);
1054   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1055   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1056
1057   set_path_visibility (fixture, "0:4", FALSE);
1058   check_filter_model (fixture);
1059   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1060   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1061
1062   set_path_visibility (fixture, "0:4:3", FALSE);
1063   check_filter_model (fixture);
1064   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1065   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1066
1067   set_path_visibility (fixture, "0:4:0", FALSE);
1068   set_path_visibility (fixture, "0:4:1", FALSE);
1069   set_path_visibility (fixture, "0:4:2", FALSE);
1070   set_path_visibility (fixture, "0:4:4", FALSE);
1071   check_filter_model (fixture);
1072   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1073   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1074
1075   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1076   set_path_visibility (fixture, "0:4", TRUE);
1077   check_filter_model (fixture);
1078   check_level_length (fixture->filter, "0:3", 0);
1079
1080   set_path_visibility (fixture, "0:2", TRUE);
1081   check_filter_model (fixture);
1082   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1083   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1084   check_level_length (fixture->filter, "0:4", 0);
1085
1086   /* Once 0:4:0 got inserted, 0:4 became a parent.  Because 0:4 is
1087    * not visible, not signals are emitted.
1088    */
1089   set_path_visibility (fixture, "0:4:2", TRUE);
1090   set_path_visibility (fixture, "0:4:4", TRUE);
1091   signal_monitor_assert_is_empty (fixture->monitor);
1092   check_level_length (fixture->filter, "0:4", 2);
1093 }
1094
1095 static void
1096 filled_hide_child_levels_root_expanded (FilterTest    *fixture,
1097                                         gconstpointer  user_data)
1098 {
1099   GtkTreePath *path;
1100
1101   path = gtk_tree_path_new_from_indices (0, -1);
1102   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
1103   gtk_tree_path_free (path);
1104
1105   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1106   set_path_visibility (fixture, "0:2", FALSE);
1107   check_filter_model (fixture);
1108   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1109   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1110
1111   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1112   set_path_visibility (fixture, "0:4", FALSE);
1113   check_filter_model (fixture);
1114   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1115   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1116
1117   set_path_visibility (fixture, "0:4:3", FALSE);
1118   check_filter_model (fixture);
1119   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1120   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1121
1122   set_path_visibility (fixture, "0:4:0", FALSE);
1123   set_path_visibility (fixture, "0:4:1", FALSE);
1124   set_path_visibility (fixture, "0:4:2", FALSE);
1125   set_path_visibility (fixture, "0:4:4", FALSE);
1126   check_filter_model (fixture);
1127   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1128   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1129
1130   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1131   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1132   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1133   set_path_visibility (fixture, "0:4", TRUE);
1134   check_filter_model (fixture);
1135   check_level_length (fixture->filter, "0:3", 0);
1136
1137   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1138   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1139   set_path_visibility (fixture, "0:2", TRUE);
1140   check_filter_model (fixture);
1141   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1142   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1143   check_level_length (fixture->filter, "0:4", 0);
1144
1145   /* has-child-toggled for 0:4 is required.  */
1146   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1147   set_path_visibility (fixture, "0:4:2", TRUE);
1148   set_path_visibility (fixture, "0:4:4", TRUE);
1149   signal_monitor_assert_is_empty (fixture->monitor);
1150   check_level_length (fixture->filter, "0:4", 2);
1151 }
1152
1153
1154 static void
1155 filled_vroot_hide_root_level (FilterTest    *fixture,
1156                               gconstpointer  user_data)
1157 {
1158   GtkTreePath *path = (GtkTreePath *)user_data;
1159
1160   /* These changes do not affect the filter's root level */
1161   set_path_visibility (fixture, "0", FALSE);
1162   check_filter_model_with_root (fixture, path);
1163   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1164   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1165
1166   set_path_visibility (fixture, "4", FALSE);
1167   check_filter_model_with_root (fixture, path);
1168   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1169   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1170
1171   /* Even though we set the virtual root parent node to FALSE,
1172    * the virtual root contents remain.
1173    */
1174   set_path_visibility (fixture, "2", FALSE);
1175   check_filter_model_with_root (fixture, path);
1176   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1177   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1178
1179   /* No change */
1180   set_path_visibility (fixture, "1", FALSE);
1181   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1182   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1183
1184   set_path_visibility (fixture, "3", FALSE);
1185   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1186   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1187
1188   check_filter_model_with_root (fixture, path);
1189
1190   /* Show some */
1191   set_path_visibility (fixture, "2", TRUE);
1192   check_filter_model_with_root (fixture, path);
1193   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1194   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1195
1196   set_path_visibility (fixture, "1", TRUE);
1197   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1198   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1199
1200   set_path_visibility (fixture, "3", TRUE);
1201   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1202   check_level_length (fixture->filter, "0", LEVEL_LENGTH);
1203
1204   check_filter_model_with_root (fixture, path);
1205
1206   /* Now test changes in the virtual root level */
1207   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "2");
1208   set_path_visibility (fixture, "2:2", FALSE);
1209   check_filter_model_with_root (fixture, path);
1210   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1211
1212   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "3");
1213   set_path_visibility (fixture, "2:4", FALSE);
1214   check_filter_model_with_root (fixture, path);
1215   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1216
1217   set_path_visibility (fixture, "1:4", FALSE);
1218   check_filter_model_with_root (fixture, path);
1219   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1220
1221   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "3");
1222   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "3");
1223   set_path_visibility (fixture, "2:4", TRUE);
1224   check_filter_model_with_root (fixture, path);
1225   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1226
1227   set_path_visibility (fixture, "2", FALSE);
1228   check_filter_model_with_root (fixture, path);
1229   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1230
1231   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1232   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1233   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1234   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1235   set_path_visibility (fixture, "2:0", FALSE);
1236   set_path_visibility (fixture, "2:1", FALSE);
1237   set_path_visibility (fixture, "2:2", FALSE);
1238   set_path_visibility (fixture, "2:3", FALSE);
1239   set_path_visibility (fixture, "2:4", FALSE);
1240   check_filter_model_with_root (fixture, path);
1241   check_level_length (fixture->filter, NULL, 0);
1242
1243   set_path_visibility (fixture, "2", TRUE);
1244   check_filter_model_with_root (fixture, path);
1245   check_level_length (fixture->filter, NULL, 0);
1246
1247   set_path_visibility (fixture, "1:4", FALSE);
1248   check_filter_model_with_root (fixture, path);
1249   check_level_length (fixture->filter, NULL, 0);
1250
1251   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1252   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1253   set_path_visibility (fixture, "2:4", TRUE);
1254   check_filter_model_with_root (fixture, path);
1255   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 4);
1256
1257   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1258   set_path_visibility (fixture, "2:4", FALSE);
1259   check_filter_model_with_root (fixture, path);
1260   check_level_length (fixture->filter, NULL, 0);
1261
1262   set_path_visibility (fixture, "2", FALSE);
1263   check_filter_model_with_root (fixture, path);
1264   check_level_length (fixture->filter, NULL, 0);
1265
1266   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1267   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1268   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1269   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1270   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2");
1271   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1272   set_path_visibility (fixture, "2:0", TRUE);
1273   set_path_visibility (fixture, "2:1", TRUE);
1274   set_path_visibility (fixture, "2:2", TRUE);
1275   check_filter_model_with_root (fixture, path);
1276   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1277
1278   set_path_visibility (fixture, "2", TRUE);
1279   check_filter_model_with_root (fixture, path);
1280   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 2);
1281 }
1282
1283 static void
1284 filled_vroot_hide_child_levels (FilterTest    *fixture,
1285                                 gconstpointer  user_data)
1286 {
1287   GtkTreePath *path = (GtkTreePath *)user_data;
1288
1289   set_path_visibility (fixture, "2:0:2", FALSE);
1290   check_filter_model_with_root (fixture, path);
1291   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1292   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1293
1294   set_path_visibility (fixture, "2:0:4", FALSE);
1295   check_filter_model_with_root (fixture, path);
1296   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1297   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1298
1299   set_path_visibility (fixture, "2:0:4:3", FALSE);
1300   check_filter_model_with_root (fixture, path);
1301   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1302   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1303
1304   set_path_visibility (fixture, "2:0:4:0", FALSE);
1305   set_path_visibility (fixture, "2:0:4:1", FALSE);
1306   set_path_visibility (fixture, "2:0:4:2", FALSE);
1307   set_path_visibility (fixture, "2:0:4:4", FALSE);
1308   check_filter_model_with_root (fixture, path);
1309   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1310   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1311
1312   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1313   set_path_visibility (fixture, "2:0:4", TRUE);
1314   check_filter_model_with_root (fixture, path);
1315   check_level_length (fixture->filter, "0:3", 0);
1316
1317   set_path_visibility (fixture, "2:0:2", TRUE);
1318   check_filter_model_with_root (fixture, path);
1319   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1320   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1321   check_level_length (fixture->filter, "0:4", 0);
1322
1323   /* Once 0:4:0 got inserted, 0:4 became a parent */
1324   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1325   set_path_visibility (fixture, "2:0:4:2", TRUE);
1326   set_path_visibility (fixture, "2:0:4:4", TRUE);
1327   check_level_length (fixture->filter, "0:4", 2);
1328 }
1329
1330 static void
1331 filled_vroot_hide_child_levels_root_expanded (FilterTest    *fixture,
1332                                               gconstpointer  user_data)
1333 {
1334   GtkTreePath *path = (GtkTreePath *)user_data;
1335   GtkTreePath *tmp_path;
1336
1337   tmp_path = gtk_tree_path_new_from_indices (0, -1);
1338   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), tmp_path, FALSE);
1339   gtk_tree_path_free (tmp_path);
1340
1341   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
1342   set_path_visibility (fixture, "2:0:2", FALSE);
1343   check_filter_model_with_root (fixture, path);
1344   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1345   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
1346
1347   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
1348   set_path_visibility (fixture, "2:0:4", FALSE);
1349   check_filter_model_with_root (fixture, path);
1350   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1351   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1352
1353   set_path_visibility (fixture, "2:0:4:3", FALSE);
1354   check_filter_model_with_root (fixture, path);
1355   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1356   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1357
1358   set_path_visibility (fixture, "2:0:4:0", FALSE);
1359   set_path_visibility (fixture, "2:0:4:1", FALSE);
1360   set_path_visibility (fixture, "2:0:4:2", FALSE);
1361   set_path_visibility (fixture, "2:0:4:4", FALSE);
1362   check_filter_model_with_root (fixture, path);
1363   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1364   check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
1365
1366   /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
1367   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
1368   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
1369   set_path_visibility (fixture, "2:0:4", TRUE);
1370   check_filter_model_with_root (fixture, path);
1371   check_level_length (fixture->filter, "0:3", 0);
1372
1373   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
1374   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
1375   set_path_visibility (fixture, "2:0:2", TRUE);
1376   check_filter_model_with_root (fixture, path);
1377   check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
1378   check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
1379   check_level_length (fixture->filter, "0:4", 0);
1380
1381   /* Once 0:4:0 got inserted, 0:4 became a parent */
1382   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
1383   set_path_visibility (fixture, "2:0:4:2", TRUE);
1384   set_path_visibility (fixture, "2:0:4:4", TRUE);
1385   check_level_length (fixture->filter, "0:4", 2);
1386 }
1387
1388 static void
1389 empty_show_nodes (FilterTest    *fixture,
1390                   gconstpointer  user_data)
1391 {
1392   check_filter_model (fixture);
1393   check_level_length (fixture->filter, NULL, 0);
1394
1395   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1396   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1397   set_path_visibility (fixture, "3", TRUE);
1398   check_filter_model (fixture);
1399   check_level_length (fixture->filter, NULL, 1);
1400   check_level_length (fixture->filter, "0", 0);
1401
1402   set_path_visibility (fixture, "3:2:2", TRUE);
1403   check_filter_model (fixture);
1404   check_level_length (fixture->filter, NULL, 1);
1405   check_level_length (fixture->filter, "0", 0);
1406
1407   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1408   set_path_visibility (fixture, "3:2", TRUE);
1409   check_filter_model (fixture);
1410   check_level_length (fixture->filter, NULL, 1);
1411   check_level_length (fixture->filter, "0", 1);
1412   check_level_length (fixture->filter, "0:0", 1);
1413   check_level_length (fixture->filter, "0:0:0", 0);
1414
1415   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1416   set_path_visibility (fixture, "3", FALSE);
1417   check_filter_model (fixture);
1418   check_level_length (fixture->filter, NULL, 0);
1419
1420   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1421   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1422   set_path_visibility (fixture, "3:2:1", TRUE);
1423   set_path_visibility (fixture, "3", TRUE);
1424   check_filter_model (fixture);
1425   check_level_length (fixture->filter, NULL, 1);
1426   check_level_length (fixture->filter, "0", 1);
1427   check_level_length (fixture->filter, "0:0", 2);
1428   check_level_length (fixture->filter, "0:0:0", 0);
1429 }
1430
1431 static void
1432 empty_show_multiple_nodes (FilterTest    *fixture,
1433                            gconstpointer  user_data)
1434 {
1435   GtkTreeIter iter;
1436   GtkTreePath *changed_path;
1437
1438   check_filter_model (fixture);
1439   check_level_length (fixture->filter, NULL, 0);
1440
1441   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1442   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1443   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1444   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1445
1446   /* We simulate a change in visible func condition with this.  The
1447    * visibility state of multiple nodes changes at once, we emit row-changed
1448    * for these nodes (and others) after that.
1449    */
1450   filter_test_block_signals (fixture);
1451   set_path_visibility (fixture, "3", TRUE);
1452   set_path_visibility (fixture, "4", TRUE);
1453   filter_test_unblock_signals (fixture);
1454
1455   changed_path = gtk_tree_path_new ();
1456   gtk_tree_path_append_index (changed_path, 2);
1457   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1458                            &iter, changed_path);
1459   /* Invisible node - so no signals expected */
1460   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1461                               changed_path, &iter);
1462
1463   gtk_tree_path_next (changed_path);
1464   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1465   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1466                               changed_path, &iter);
1467
1468   gtk_tree_path_next (changed_path);
1469   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1470   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1471                               changed_path, &iter);
1472
1473   gtk_tree_path_free (changed_path);
1474
1475   check_filter_model (fixture);
1476   check_level_length (fixture->filter, NULL, 2);
1477   check_level_length (fixture->filter, "0", 0);
1478
1479   set_path_visibility (fixture, "3:2:2", TRUE);
1480   check_filter_model (fixture);
1481   check_level_length (fixture->filter, NULL, 2);
1482   check_level_length (fixture->filter, "0", 0);
1483
1484   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1485   set_path_visibility (fixture, "3:2", TRUE);
1486   check_filter_model (fixture);
1487   check_level_length (fixture->filter, NULL, 2);
1488   check_level_length (fixture->filter, "0", 1);
1489   check_level_length (fixture->filter, "0:0", 1);
1490   check_level_length (fixture->filter, "0:0:0", 0);
1491
1492   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1493   set_path_visibility (fixture, "3", FALSE);
1494   check_filter_model (fixture);
1495   check_level_length (fixture->filter, NULL, 1);
1496
1497   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1498   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1499   set_path_visibility (fixture, "3:2:1", TRUE);
1500   set_path_visibility (fixture, "3", TRUE);
1501   check_filter_model (fixture);
1502   check_level_length (fixture->filter, NULL, 2);
1503   check_level_length (fixture->filter, "0", 1);
1504   check_level_length (fixture->filter, "0:0", 2);
1505   check_level_length (fixture->filter, "0:0:0", 0);
1506 }
1507
1508 static void
1509 empty_vroot_show_nodes (FilterTest    *fixture,
1510                         gconstpointer  user_data)
1511 {
1512   GtkTreePath *path = (GtkTreePath *)user_data;
1513
1514   check_filter_model_with_root (fixture, path);
1515   check_level_length (fixture->filter, NULL, 0);
1516
1517   set_path_visibility (fixture, "2", TRUE);
1518   check_filter_model_with_root (fixture, path);
1519   check_level_length (fixture->filter, NULL, 0);
1520
1521   set_path_visibility (fixture, "2:2:2", TRUE);
1522   check_filter_model_with_root (fixture, path);
1523   check_level_length (fixture->filter, NULL, 0);
1524
1525   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1526   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1527   set_path_visibility (fixture, "2:2", TRUE);
1528   check_filter_model_with_root (fixture, path);
1529   check_level_length (fixture->filter, NULL, 1);
1530   check_level_length (fixture->filter, "0", 1);
1531   check_level_length (fixture->filter, "0:0", 0);
1532
1533   set_path_visibility (fixture, "3", TRUE);
1534   check_filter_model_with_root (fixture, path);
1535   check_level_length (fixture->filter, NULL, 1);
1536
1537   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1538   set_path_visibility (fixture, "2:2", FALSE);
1539   check_filter_model_with_root (fixture, path);
1540   check_level_length (fixture->filter, NULL, 0);
1541
1542   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1543   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1544   set_path_visibility (fixture, "2:2:1", TRUE);
1545   set_path_visibility (fixture, "2:2", TRUE);
1546   check_filter_model_with_root (fixture, path);
1547   check_level_length (fixture->filter, NULL, 1);
1548   check_level_length (fixture->filter, "0", 2);
1549   check_level_length (fixture->filter, "0:1", 0);
1550 }
1551
1552 static void
1553 empty_vroot_show_multiple_nodes (FilterTest    *fixture,
1554                                  gconstpointer  user_data)
1555 {
1556   GtkTreeIter iter;
1557   GtkTreePath *changed_path;
1558   GtkTreePath *path = (GtkTreePath *)user_data;
1559
1560   check_filter_model_with_root (fixture, path);
1561   check_level_length (fixture->filter, NULL, 0);
1562
1563   /* We simulate a change in visible func condition with this.  The
1564    * visibility state of multiple nodes changes at once, we emit row-changed
1565    * for these nodes (and others) after that.
1566    */
1567   filter_test_block_signals (fixture);
1568   set_path_visibility (fixture, "2", TRUE);
1569   set_path_visibility (fixture, "3", TRUE);
1570   filter_test_unblock_signals (fixture);
1571
1572   changed_path = gtk_tree_path_new ();
1573   gtk_tree_path_append_index (changed_path, 1);
1574   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1575                            &iter, changed_path);
1576   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1577                               changed_path, &iter);
1578
1579   gtk_tree_path_next (changed_path);
1580   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1581   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1582                               changed_path, &iter);
1583
1584   gtk_tree_path_next (changed_path);
1585   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1586   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1587                               changed_path, &iter);
1588
1589   gtk_tree_path_next (changed_path);
1590   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1591   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1592                               changed_path, &iter);
1593
1594   gtk_tree_path_free (changed_path);
1595
1596   check_filter_model_with_root (fixture, path);
1597   check_level_length (fixture->filter, NULL, 0);
1598
1599   set_path_visibility (fixture, "2:2:2", TRUE);
1600   check_filter_model_with_root (fixture, path);
1601   check_level_length (fixture->filter, NULL, 0);
1602
1603   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1604   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1605   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
1606   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
1607
1608   /* Again, we simulate a call to refilter */
1609   filter_test_block_signals (fixture);
1610   set_path_visibility (fixture, "2:2", TRUE);
1611   set_path_visibility (fixture, "2:3", TRUE);
1612   filter_test_unblock_signals (fixture);
1613
1614   changed_path = gtk_tree_path_new ();
1615   gtk_tree_path_append_index (changed_path, 2);
1616   gtk_tree_path_append_index (changed_path, 1);
1617   gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
1618                            &iter, changed_path);
1619   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1620                               changed_path, &iter);
1621
1622   gtk_tree_path_next (changed_path);
1623   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1624   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1625                               changed_path, &iter);
1626
1627   gtk_tree_path_next (changed_path);
1628   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1629   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1630                               changed_path, &iter);
1631
1632   gtk_tree_path_next (changed_path);
1633   gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
1634   gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
1635                               changed_path, &iter);
1636
1637   gtk_tree_path_free (changed_path);
1638
1639   check_filter_model_with_root (fixture, path);
1640   check_level_length (fixture->filter, NULL, 2);
1641   check_level_length (fixture->filter, "0", 1);
1642   check_level_length (fixture->filter, "0:0", 0);
1643
1644   set_path_visibility (fixture, "3", TRUE);
1645   check_filter_model_with_root (fixture, path);
1646   check_level_length (fixture->filter, NULL, 2);
1647
1648   signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
1649   set_path_visibility (fixture, "2:2", FALSE);
1650   check_filter_model_with_root (fixture, path);
1651   check_level_length (fixture->filter, NULL, 1);
1652
1653   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
1654   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
1655   set_path_visibility (fixture, "2:2:1", TRUE);
1656   set_path_visibility (fixture, "2:2", TRUE);
1657   check_filter_model_with_root (fixture, path);
1658   check_level_length (fixture->filter, NULL, 2);
1659   check_level_length (fixture->filter, "0", 2);
1660   check_level_length (fixture->filter, "0:1", 0);
1661 }
1662
1663
1664 static void
1665 unfiltered_hide_single (FilterTest    *fixture,
1666                         gconstpointer  user_data)
1667
1668 {
1669   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1670   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1671   set_path_visibility (fixture, "2", FALSE);
1672
1673   signal_monitor_assert_is_empty (fixture->monitor);
1674   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1675
1676   /* The view only shows the root level, so we only expect signals
1677    * for the root level.
1678    */
1679   filter_test_append_refilter_signals (fixture, 1);
1680   filter_test_enable_filter (fixture);
1681
1682   check_filter_model (fixture);
1683   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1684 }
1685
1686 static void
1687 unfiltered_hide_single_root_expanded (FilterTest    *fixture,
1688                                       gconstpointer  user_data)
1689
1690 {
1691   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1692   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1693   set_path_visibility (fixture, "2", FALSE);
1694
1695   signal_monitor_assert_is_empty (fixture->monitor);
1696   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1697
1698   filter_test_append_refilter_signals (fixture, 2);
1699   filter_test_enable_filter (fixture);
1700
1701   check_filter_model (fixture);
1702   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1703 }
1704
1705 static void
1706 unfiltered_hide_single_child (FilterTest    *fixture,
1707                               gconstpointer  user_data)
1708
1709 {
1710   /* This row is not shown, so its signal is not propagated */
1711   set_path_visibility (fixture, "2:2", FALSE);
1712
1713   signal_monitor_assert_is_empty (fixture->monitor);
1714   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1715   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1716
1717   /* The view only shows the root level, so we only expect signals
1718    * for the root level.
1719    */
1720   filter_test_append_refilter_signals (fixture, 0);
1721   filter_test_enable_filter (fixture);
1722
1723   check_filter_model (fixture);
1724   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1725   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1726 }
1727
1728 static void
1729 unfiltered_hide_single_child_root_expanded (FilterTest    *fixture,
1730                                             gconstpointer  user_data)
1731
1732 {
1733   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1734   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1735   set_path_visibility (fixture, "2:2", FALSE);
1736
1737   signal_monitor_assert_is_empty (fixture->monitor);
1738   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1739   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1740
1741   filter_test_append_refilter_signals (fixture, 2);
1742   filter_test_enable_filter (fixture);
1743
1744   check_filter_model (fixture);
1745   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1746   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1747 }
1748
1749 static void
1750 unfiltered_hide_single_multi_level (FilterTest    *fixture,
1751                                     gconstpointer  user_data)
1752
1753 {
1754   /* This row is not shown, so its signal is not propagated */
1755   set_path_visibility (fixture, "2:2:2", FALSE);
1756
1757   /* This row is not shown, so its signal is not propagated */
1758   set_path_visibility (fixture, "2:2", FALSE);
1759
1760   signal_monitor_assert_is_empty (fixture->monitor);
1761   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1762   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1763   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1764
1765   /* The view only shows the root level, so we only expect signals
1766    * for the root level.
1767    */
1768   filter_test_append_refilter_signals (fixture, 1);
1769   filter_test_enable_filter (fixture);
1770
1771   check_filter_model (fixture);
1772   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1773   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1774
1775   set_path_visibility (fixture, "2:2", TRUE);
1776
1777   check_filter_model (fixture);
1778   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1779   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1780   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1781 }
1782
1783 static void
1784 unfiltered_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1785                                                   gconstpointer  user_data)
1786
1787 {
1788   /* This row is not shown, so its signal is not propagated */
1789   set_path_visibility (fixture, "2:2:2", FALSE);
1790
1791   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1792   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1793   set_path_visibility (fixture, "2:2", FALSE);
1794
1795   signal_monitor_assert_is_empty (fixture->monitor);
1796   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1797   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1798   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1799
1800   filter_test_append_refilter_signals (fixture, 2);
1801   filter_test_enable_filter (fixture);
1802
1803   check_filter_model (fixture);
1804   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1805   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1806
1807   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1808   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1809   set_path_visibility (fixture, "2:2", TRUE);
1810
1811   check_filter_model (fixture);
1812   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1813   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1814   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1815 }
1816
1817
1818
1819 static void
1820 unfiltered_vroot_hide_single (FilterTest    *fixture,
1821                               gconstpointer  user_data)
1822
1823 {
1824   GtkTreePath *path = (GtkTreePath *)user_data;
1825
1826   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1827   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1828   set_path_visibility (fixture, "2:2", FALSE);
1829
1830   signal_monitor_assert_is_empty (fixture->monitor);
1831   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1832
1833   /* The view only shows the root level, so we only expect signals
1834    * for the root level.  (Though for the depth argument, we have to
1835    * take the virtual root into account).
1836    */
1837   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1838   filter_test_enable_filter (fixture);
1839
1840   check_filter_model_with_root (fixture, path);
1841   check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
1842 }
1843
1844 static void
1845 unfiltered_vroot_hide_single_child (FilterTest    *fixture,
1846                                     gconstpointer  user_data)
1847
1848 {
1849   GtkTreePath *path = (GtkTreePath *)user_data;
1850
1851   /* Not visible, so no signal will be received. */
1852   set_path_visibility (fixture, "2:2:2", FALSE);
1853
1854   signal_monitor_assert_is_empty (fixture->monitor);
1855   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1856   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1857
1858   /* The view only shows the root level, so we only expect signals
1859    * for the root level.  (Though for the depth argument, we have to
1860    * take the virtual root into account).
1861    */
1862   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1863   filter_test_enable_filter (fixture);
1864
1865   check_filter_model_with_root (fixture, path);
1866   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1867   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1868 }
1869
1870 static void
1871 unfiltered_vroot_hide_single_child_root_expanded (FilterTest    *fixture,
1872                                                   gconstpointer  user_data)
1873
1874 {
1875   GtkTreePath *path = (GtkTreePath *)user_data;
1876
1877   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1878   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1879   set_path_visibility (fixture, "2:2:2", FALSE);
1880
1881   signal_monitor_assert_is_empty (fixture->monitor);
1882   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1883   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1884
1885   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1886   filter_test_enable_filter (fixture);
1887
1888   check_filter_model_with_root (fixture, path);
1889   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1890   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1891 }
1892
1893 static void
1894 unfiltered_vroot_hide_single_multi_level (FilterTest    *fixture,
1895                                           gconstpointer  user_data)
1896
1897 {
1898   GtkTreePath *path = (GtkTreePath *)user_data;
1899
1900   /* This row is not shown, so its signal is not propagated */
1901   set_path_visibility (fixture, "2:2:2:2", FALSE);
1902
1903   /* Not shown, so no signal */
1904   set_path_visibility (fixture, "2:2:2", FALSE);
1905
1906   signal_monitor_assert_is_empty (fixture->monitor);
1907   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1908   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1909   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1910
1911   /* We only expect signals for the root level.  The depth is 2
1912    * because we have to take the virtual root into account.
1913    */
1914   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
1915   filter_test_enable_filter (fixture);
1916
1917   check_filter_model_with_root (fixture, path);
1918   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1919   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1920
1921   /* Not shown, so no signal */
1922   set_path_visibility (fixture, "2:2:2", TRUE);
1923
1924   check_filter_model_with_root (fixture, path);
1925   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1926   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1927   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1928 }
1929
1930 static void
1931 unfiltered_vroot_hide_single_multi_level_root_expanded (FilterTest    *fixture,
1932                                                         gconstpointer  user_data)
1933
1934 {
1935   GtkTreePath *path = (GtkTreePath *)user_data;
1936
1937   /* This row is not shown, so its signal is not propagated */
1938   set_path_visibility (fixture, "2:2:2:2", FALSE);
1939
1940   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
1941   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1942   set_path_visibility (fixture, "2:2:2", FALSE);
1943
1944   signal_monitor_assert_is_empty (fixture->monitor);
1945   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1946   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1947   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
1948
1949   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
1950   filter_test_enable_filter (fixture);
1951
1952   check_filter_model_with_root (fixture, path);
1953   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1954   check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
1955
1956   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "2:2");
1957   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
1958   set_path_visibility (fixture, "2:2:2", TRUE);
1959
1960   check_filter_model_with_root (fixture, path);
1961   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1962   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1963   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
1964 }
1965
1966 static void
1967 unfiltered_show_single (FilterTest    *fixture,
1968                         gconstpointer  user_data)
1969
1970 {
1971   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
1972   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
1973   set_path_visibility (fixture, "2", TRUE);
1974
1975   signal_monitor_assert_is_empty (fixture->monitor);
1976   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1977
1978   /* We only expect signals for the root level */
1979   filter_test_append_refilter_signals (fixture, 1);
1980   filter_test_enable_filter (fixture);
1981
1982   check_filter_model (fixture);
1983   check_level_length (fixture->filter, NULL, 1);
1984 }
1985
1986 static void
1987 unfiltered_show_single_child (FilterTest    *fixture,
1988                               gconstpointer  user_data)
1989
1990 {
1991   set_path_visibility (fixture, "2:2", TRUE);
1992
1993   signal_monitor_assert_is_empty (fixture->monitor);
1994   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
1995   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
1996
1997   /* We only expect signals for the root level */
1998   filter_test_append_refilter_signals (fixture, 1);
1999   filter_test_enable_filter (fixture);
2000
2001   check_filter_model (fixture);
2002   check_level_length (fixture->filter, NULL, 0);
2003
2004   /* From here we are filtered, "2" in the real model is "0" in the filter
2005    * model.
2006    */
2007   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2008   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2009   set_path_visibility (fixture, "2", TRUE);
2010   signal_monitor_assert_is_empty (fixture->monitor);
2011   check_level_length (fixture->filter, NULL, 1);
2012   check_level_length (fixture->filter, "0", 1);
2013 }
2014
2015 static void
2016 unfiltered_show_single_child_root_expanded (FilterTest    *fixture,
2017                                             gconstpointer  user_data)
2018
2019 {
2020   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
2021   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
2022   set_path_visibility (fixture, "2:2", TRUE);
2023
2024   signal_monitor_assert_is_empty (fixture->monitor);
2025   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2026   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2027
2028   filter_test_append_refilter_signals (fixture, 2);
2029   filter_test_enable_filter (fixture);
2030
2031   check_filter_model (fixture);
2032   check_level_length (fixture->filter, NULL, 0);
2033
2034   /* From here we are filtered, "2" in the real model is "0" in the filter
2035    * model.
2036    */
2037   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2038   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2039   set_path_visibility (fixture, "2", TRUE);
2040   signal_monitor_assert_is_empty (fixture->monitor);
2041   check_level_length (fixture->filter, NULL, 1);
2042   check_level_length (fixture->filter, "0", 1);
2043 }
2044
2045 static void
2046 unfiltered_show_single_multi_level (FilterTest    *fixture,
2047                                     gconstpointer  user_data)
2048
2049 {
2050   /* The view is not showing these rows (collapsed state), so it is not
2051    * referenced.  The signal should not go through.
2052    */
2053   set_path_visibility (fixture, "2:2:2", TRUE);
2054   set_path_visibility (fixture, "2:2", TRUE);
2055
2056   signal_monitor_assert_is_empty (fixture->monitor);
2057   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2058   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2059   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
2060
2061   /* We only expect signals for the first level */
2062   filter_test_append_refilter_signals (fixture, 1);
2063   filter_test_enable_filter (fixture);
2064
2065   check_filter_model (fixture);
2066   check_level_length (fixture->filter, NULL, 0);
2067
2068   /* From here we are filtered, "2" in the real model is "0" in the filter
2069    * model.
2070    */
2071   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2072   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2073   set_path_visibility (fixture, "2", TRUE);
2074   check_filter_model (fixture);
2075   check_level_length (fixture->filter, NULL, 1);
2076   check_level_length (fixture->filter, "0", 1);
2077   check_level_length (fixture->filter, "0:0", 1);
2078 }
2079
2080 static void
2081 unfiltered_show_single_multi_level_root_expanded (FilterTest    *fixture,
2082                                                   gconstpointer  user_data)
2083
2084 {
2085   /* The view is not showing this row (collapsed state), so it is not
2086    * referenced.  The signal should not go through.
2087    */
2088   set_path_visibility (fixture, "2:2:2", TRUE);
2089
2090   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
2091   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
2092   set_path_visibility (fixture, "2:2", TRUE);
2093
2094   signal_monitor_assert_is_empty (fixture->monitor);
2095   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2096   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2097   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
2098
2099   filter_test_append_refilter_signals (fixture, 2);
2100   filter_test_enable_filter (fixture);
2101
2102   check_filter_model (fixture);
2103   check_level_length (fixture->filter, NULL, 0);
2104
2105   /* From here we are filtered, "2" in the real model is "0" in the filter
2106    * model.
2107    */
2108   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2109   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2110   set_path_visibility (fixture, "2", TRUE);
2111   check_filter_model (fixture);
2112   check_level_length (fixture->filter, NULL, 1);
2113   check_level_length (fixture->filter, "0", 1);
2114   check_level_length (fixture->filter, "0:0", 1);
2115 }
2116
2117 static void
2118 unfiltered_vroot_show_single (FilterTest    *fixture,
2119                               gconstpointer  user_data)
2120
2121 {
2122   GtkTreePath *path = (GtkTreePath *)user_data;
2123
2124   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
2125   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
2126   set_path_visibility (fixture, "2:2", TRUE);
2127
2128   signal_monitor_assert_is_empty (fixture->monitor);
2129   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2130
2131   /* The view only shows the root level, so the filter model only has
2132    * the first two levels cached.
2133    */
2134   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
2135   filter_test_enable_filter (fixture);
2136
2137   check_filter_model_with_root (fixture, path);
2138   check_level_length (fixture->filter, NULL, 1);
2139 }
2140
2141 static void
2142 unfiltered_vroot_show_single_child (FilterTest    *fixture,
2143                                     gconstpointer  user_data)
2144
2145 {
2146   GtkTreePath *path = (GtkTreePath *)user_data;
2147
2148   set_path_visibility (fixture, "2:2:2", TRUE);
2149
2150   signal_monitor_assert_is_empty (fixture->monitor);
2151   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2152   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2153
2154   /* The view only shows the root level, so the filter model only has
2155    * the first two levels cached.
2156    */
2157   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
2158   filter_test_enable_filter (fixture);
2159
2160   check_filter_model_with_root (fixture, path);
2161   check_level_length (fixture->filter, NULL, 0);
2162
2163   /* From here we are filtered, "2" in the real model is "0" in the filter
2164    * model.
2165    */
2166   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2167   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2168   set_path_visibility (fixture, "2:2", TRUE);
2169   signal_monitor_assert_is_empty (fixture->monitor);
2170   check_level_length (fixture->filter, NULL, 1);
2171   check_level_length (fixture->filter, "0", 1);
2172 }
2173
2174 static void
2175 unfiltered_vroot_show_single_child_root_expanded (FilterTest    *fixture,
2176                                                   gconstpointer  user_data)
2177
2178 {
2179   GtkTreePath *path = (GtkTreePath *)user_data;
2180
2181   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
2182   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
2183   set_path_visibility (fixture, "2:2:2", TRUE);
2184
2185   signal_monitor_assert_is_empty (fixture->monitor);
2186   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2187   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2188
2189   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
2190   filter_test_enable_filter (fixture);
2191
2192   check_filter_model_with_root (fixture, path);
2193   check_level_length (fixture->filter, NULL, 0);
2194
2195   /* From here we are filtered, "2" in the real model is "0" in the filter
2196    * model.
2197    */
2198   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2199   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2200   set_path_visibility (fixture, "2:2", TRUE);
2201   signal_monitor_assert_is_empty (fixture->monitor);
2202   check_level_length (fixture->filter, NULL, 1);
2203   check_level_length (fixture->filter, "0", 1);
2204 }
2205
2206
2207 static void
2208 unfiltered_vroot_show_single_multi_level (FilterTest    *fixture,
2209                                           gconstpointer  user_data)
2210
2211 {
2212   GtkTreePath *path = (GtkTreePath *)user_data;
2213
2214   /* The view is not showing this row (collapsed state), so it is not
2215    * referenced.  The signal should not go through.
2216    */
2217   set_path_visibility (fixture, "2:2:2:2", TRUE);
2218
2219   set_path_visibility (fixture, "2:2:2", TRUE);
2220
2221   signal_monitor_assert_is_empty (fixture->monitor);
2222   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2223   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2224   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
2225
2226   /* We only expect signals for the root level */
2227   filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
2228   filter_test_enable_filter (fixture);
2229
2230   check_filter_model_with_root (fixture, path);
2231   check_level_length (fixture->filter, NULL, 0);
2232
2233   /* From here we are filtered, "2" in the real model is "0" in the filter
2234    * model.
2235    */
2236   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2237   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2238   set_path_visibility (fixture, "2:2", TRUE);
2239   check_filter_model_with_root (fixture, path);
2240   check_level_length (fixture->filter, NULL, 1);
2241   check_level_length (fixture->filter, "0", 1);
2242   check_level_length (fixture->filter, "0:0", 1);
2243 }
2244
2245 static void
2246 unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest    *fixture,
2247                                                         gconstpointer  user_data)
2248
2249 {
2250   GtkTreePath *path = (GtkTreePath *)user_data;
2251
2252   /* The view is not showing this row (collapsed state), so it is not
2253    * referenced.  The signal should not go through.
2254    */
2255   set_path_visibility (fixture, "2:2:2:2", TRUE);
2256
2257   signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
2258   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
2259   set_path_visibility (fixture, "2:2:2", TRUE);
2260
2261   signal_monitor_assert_is_empty (fixture->monitor);
2262   check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
2263   check_level_length (fixture->filter, "2", LEVEL_LENGTH);
2264   check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
2265
2266   filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
2267   filter_test_enable_filter (fixture);
2268
2269   check_filter_model_with_root (fixture, path);
2270   check_level_length (fixture->filter, NULL, 0);
2271
2272   /* From here we are filtered, "2" in the real model is "0" in the filter
2273    * model.
2274    */
2275   signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
2276   signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
2277   set_path_visibility (fixture, "2:2", TRUE);
2278   check_filter_model_with_root (fixture, path);
2279   check_level_length (fixture->filter, NULL, 1);
2280   check_level_length (fixture->filter, "0", 1);
2281   check_level_length (fixture->filter, "0:0", 1);
2282 }
2283
2284 static void
2285 unfiltered_rows_reordered_root_level (FilterTest    *fixture,
2286                                       gconstpointer  user_data)
2287 {
2288   int order0[] = { 1, 2, 3, 4, 0 };
2289   int order1[] = { 0, 2, 1, 3, 4 };
2290   int order2[] = { 4, 0, 1, 2, 3 };
2291   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
2292   GtkTreePath *path;
2293
2294   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2295                                        &iter0, "0");
2296   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2297                                        &iter1, "1");
2298   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2299                                        &iter2, "2");
2300   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2301                                        &iter3, "3");
2302   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2303                                        &iter4, "4");
2304
2305   path = gtk_tree_path_new ();
2306   signal_monitor_append_signal_reordered (fixture->monitor,
2307                                           ROWS_REORDERED,
2308                                           path, order0, 5);
2309   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2310   signal_monitor_assert_is_empty (fixture->monitor);
2311
2312   signal_monitor_append_signal_reordered (fixture->monitor,
2313                                           ROWS_REORDERED,
2314                                           path, order1, 5);
2315   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
2316   signal_monitor_assert_is_empty (fixture->monitor);
2317
2318   signal_monitor_append_signal_reordered (fixture->monitor,
2319                                           ROWS_REORDERED,
2320                                           path, order2, 5);
2321   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2322   signal_monitor_assert_is_empty (fixture->monitor);
2323
2324   gtk_tree_path_free (path);
2325 }
2326
2327 static void
2328 unfiltered_rows_reordered_child_level (FilterTest    *fixture,
2329                                        gconstpointer  user_data)
2330 {
2331   int order0[] = { 1, 2, 3, 4, 0 };
2332   int order1[] = { 0, 2, 1, 3, 4 };
2333   int order2[] = { 4, 0, 1, 2, 3 };
2334   GtkTreeIter iter0, iter1, iter2, iter3, iter4;
2335   GtkTreePath *path;
2336
2337   /* Expand row 0 */
2338   path = gtk_tree_path_new_from_indices (0, -1);
2339   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2340
2341   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2342                                        &iter0, "0:0");
2343   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2344                                        &iter1, "0:1");
2345   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2346                                        &iter2, "0:2");
2347   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2348                                        &iter3, "0:3");
2349   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2350                                        &iter4, "0:4");
2351
2352   signal_monitor_append_signal_reordered (fixture->monitor,
2353                                           ROWS_REORDERED,
2354                                           path, order0, 5);
2355   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2356   signal_monitor_assert_is_empty (fixture->monitor);
2357
2358   signal_monitor_append_signal_reordered (fixture->monitor,
2359                                           ROWS_REORDERED,
2360                                           path, order1, 5);
2361   gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
2362   signal_monitor_assert_is_empty (fixture->monitor);
2363
2364   signal_monitor_append_signal_reordered (fixture->monitor,
2365                                           ROWS_REORDERED,
2366                                           path, order2, 5);
2367   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2368   signal_monitor_assert_is_empty (fixture->monitor);
2369
2370   gtk_tree_path_free (path);
2371 }
2372
2373 static void
2374 filtered_rows_reordered_root_level_first_hidden (FilterTest    *fixture,
2375                                                  gconstpointer  user_data)
2376 {
2377   int order0[] = { 1, 2, 3, 0 };
2378   int order1[] = { 0, 2, 1, 3 };
2379   int order2[] = { 3, 0, 1, 2 };
2380   GtkTreeIter iter1, iter2, iter3, iter4;
2381   GtkTreePath *path;
2382
2383   /* Hide middle path */
2384   signal_monitor_append_signal (fixture->monitor,
2385                                 ROW_DELETED, "0");
2386   set_path_visibility (fixture, "0", FALSE);
2387   signal_monitor_assert_is_empty (fixture->monitor);
2388
2389   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2390                                        &iter1, "1");
2391   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2392                                        &iter2, "2");
2393   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2394                                        &iter3, "3");
2395   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2396                                        &iter4, "4");
2397
2398   path = gtk_tree_path_new ();
2399   signal_monitor_append_signal_reordered (fixture->monitor,
2400                                           ROWS_REORDERED,
2401                                           path, order0, 4);
2402   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2403   signal_monitor_assert_is_empty (fixture->monitor);
2404
2405   signal_monitor_append_signal_reordered (fixture->monitor,
2406                                           ROWS_REORDERED,
2407                                           path, order1, 4);
2408   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2409   signal_monitor_assert_is_empty (fixture->monitor);
2410
2411   signal_monitor_append_signal_reordered (fixture->monitor,
2412                                           ROWS_REORDERED,
2413                                           path, order2, 4);
2414   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2415   signal_monitor_assert_is_empty (fixture->monitor);
2416
2417   gtk_tree_path_free (path);
2418 }
2419
2420 static void
2421 filtered_rows_reordered_root_level_middle_hidden (FilterTest    *fixture,
2422                                                   gconstpointer  user_data)
2423 {
2424   int order0[] = { 1, 2, 3, 0 };
2425   int order1[] = { 0, 2, 1, 3 };
2426   int order2[] = { 3, 0, 1, 2 };
2427   GtkTreeIter iter0, iter1, iter3, iter4;
2428   GtkTreePath *path;
2429
2430   /* Hide middle path */
2431   signal_monitor_append_signal (fixture->monitor,
2432                                 ROW_DELETED, "2");
2433   set_path_visibility (fixture, "2", FALSE);
2434   signal_monitor_assert_is_empty (fixture->monitor);
2435
2436   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2437                                        &iter0, "0");
2438   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2439                                        &iter1, "1");
2440   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2441                                        &iter3, "3");
2442   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2443                                        &iter4, "4");
2444
2445   path = gtk_tree_path_new ();
2446   signal_monitor_append_signal_reordered (fixture->monitor,
2447                                           ROWS_REORDERED,
2448                                           path, order0, 4);
2449   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2450   signal_monitor_assert_is_empty (fixture->monitor);
2451
2452   signal_monitor_append_signal_reordered (fixture->monitor,
2453                                           ROWS_REORDERED,
2454                                           path, order1, 4);
2455   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2456   signal_monitor_assert_is_empty (fixture->monitor);
2457
2458   signal_monitor_append_signal_reordered (fixture->monitor,
2459                                           ROWS_REORDERED,
2460                                           path, order2, 4);
2461   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2462   signal_monitor_assert_is_empty (fixture->monitor);
2463
2464   gtk_tree_path_free (path);
2465 }
2466
2467 static void
2468 filtered_rows_reordered_child_level_first_hidden (FilterTest    *fixture,
2469                                                   gconstpointer  user_data)
2470 {
2471   int order0[] = { 1, 2, 3, 0 };
2472   int order1[] = { 0, 2, 1, 3 };
2473   int order2[] = { 3, 0, 1, 2 };
2474   GtkTreeIter iter1, iter2, iter3, iter4;
2475   GtkTreePath *path;
2476
2477   /* Expand row 0 */
2478   path = gtk_tree_path_new_from_indices (0, -1);
2479   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, TRUE);
2480
2481   /* Hide middle path */
2482   signal_monitor_append_signal (fixture->monitor,
2483                                 ROW_DELETED, "0:0");
2484   set_path_visibility (fixture, "0:0", FALSE);
2485   signal_monitor_assert_is_empty (fixture->monitor);
2486
2487   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2488                                        &iter1, "0:1");
2489   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2490                                        &iter2, "0:2");
2491   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2492                                        &iter3, "0:3");
2493   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2494                                        &iter4, "0:4");
2495
2496   signal_monitor_append_signal_reordered (fixture->monitor,
2497                                           ROWS_REORDERED,
2498                                           path, order0, 4);
2499   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2500   signal_monitor_assert_is_empty (fixture->monitor);
2501
2502   signal_monitor_append_signal_reordered (fixture->monitor,
2503                                           ROWS_REORDERED,
2504                                           path, order1, 4);
2505   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2506   signal_monitor_assert_is_empty (fixture->monitor);
2507
2508   signal_monitor_append_signal_reordered (fixture->monitor,
2509                                           ROWS_REORDERED,
2510                                           path, order2, 4);
2511   gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
2512   signal_monitor_assert_is_empty (fixture->monitor);
2513
2514   gtk_tree_path_free (path);
2515 }
2516
2517 static void
2518 filtered_rows_reordered_child_level_middle_hidden (FilterTest    *fixture,
2519                                                    gconstpointer  user_data)
2520 {
2521   int order0[] = { 1, 2, 3, 0 };
2522   int order1[] = { 0, 2, 1, 3 };
2523   int order2[] = { 3, 0, 1, 2 };
2524   GtkTreeIter iter0, iter1, iter3, iter4;
2525   GtkTreePath *path;
2526
2527   /* Expand row 0 */
2528   path = gtk_tree_path_new_from_indices (0, -1);
2529   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2530
2531   /* Hide middle path */
2532   signal_monitor_append_signal (fixture->monitor,
2533                                 ROW_DELETED, "0:2");
2534   set_path_visibility (fixture, "0:2", FALSE);
2535   signal_monitor_assert_is_empty (fixture->monitor);
2536
2537   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2538                                        &iter0, "0:0");
2539   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2540                                        &iter1, "0:1");
2541   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2542                                        &iter3, "0:3");
2543   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2544                                        &iter4, "0:4");
2545
2546   signal_monitor_append_signal_reordered (fixture->monitor,
2547                                           ROWS_REORDERED,
2548                                           path, order0, 4);
2549   gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
2550   signal_monitor_assert_is_empty (fixture->monitor);
2551
2552   signal_monitor_append_signal_reordered (fixture->monitor,
2553                                           ROWS_REORDERED,
2554                                           path, order1, 4);
2555   gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
2556   signal_monitor_assert_is_empty (fixture->monitor);
2557
2558   signal_monitor_append_signal_reordered (fixture->monitor,
2559                                           ROWS_REORDERED,
2560                                           path, order2, 4);
2561   gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
2562   signal_monitor_assert_is_empty (fixture->monitor);
2563
2564   gtk_tree_path_free (path);
2565 }
2566
2567 static void
2568 filtered_rows_reordered_child_level_4_hidden (FilterTest    *fixture,
2569                                               gconstpointer  user_data)
2570 {
2571   int order0[] = { 0 };
2572   GtkTreeIter iter1, iter4;
2573   GtkTreePath *path;
2574
2575   /* Expand row 0 */
2576   path = gtk_tree_path_new_from_indices (0, -1);
2577   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2578
2579   /* Hide last 4 paths */
2580   signal_monitor_append_signal (fixture->monitor,
2581                                 ROW_DELETED, "0:4");
2582   signal_monitor_append_signal (fixture->monitor,
2583                                 ROW_DELETED, "0:3");
2584   signal_monitor_append_signal (fixture->monitor,
2585                                 ROW_DELETED, "0:2");
2586   signal_monitor_append_signal (fixture->monitor,
2587                                 ROW_DELETED, "0:0");
2588   set_path_visibility (fixture, "0:4", FALSE);
2589   set_path_visibility (fixture, "0:3", FALSE);
2590   set_path_visibility (fixture, "0:2", FALSE);
2591   set_path_visibility (fixture, "0:0", FALSE);
2592   signal_monitor_assert_is_empty (fixture->monitor);
2593
2594   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2595                                        &iter1, "0:1");
2596   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2597                                        &iter4, "0:4");
2598
2599   signal_monitor_append_signal_reordered (fixture->monitor,
2600                                           ROWS_REORDERED,
2601                                           path, order0, 1);
2602   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2603   signal_monitor_assert_is_empty (fixture->monitor);
2604
2605   gtk_tree_path_free (path);
2606 }
2607
2608 static void
2609 filtered_rows_reordered_child_level_all_hidden (FilterTest    *fixture,
2610                                                 gconstpointer  user_data)
2611 {
2612   GtkTreeIter iter1, iter4;
2613   GtkTreePath *path;
2614
2615   /* Expand row 0 */
2616   path = gtk_tree_path_new_from_indices (0, -1);
2617   gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
2618   gtk_tree_path_free (path);
2619
2620   /* Hide last 4 paths */
2621   signal_monitor_append_signal (fixture->monitor,
2622                                 ROW_DELETED, "0:4");
2623   signal_monitor_append_signal (fixture->monitor,
2624                                 ROW_DELETED, "0:3");
2625   signal_monitor_append_signal (fixture->monitor,
2626                                 ROW_DELETED, "0:2");
2627   signal_monitor_append_signal (fixture->monitor,
2628                                 ROW_DELETED, "0:1");
2629   signal_monitor_append_signal (fixture->monitor,
2630                                 ROW_DELETED, "0:0");
2631   signal_monitor_append_signal (fixture->monitor,
2632                                 ROW_HAS_CHILD_TOGGLED, "0");
2633   set_path_visibility (fixture, "0:4", FALSE);
2634   set_path_visibility (fixture, "0:3", FALSE);
2635   set_path_visibility (fixture, "0:2", FALSE);
2636   set_path_visibility (fixture, "0:1", FALSE);
2637   set_path_visibility (fixture, "0:0", FALSE);
2638   signal_monitor_assert_is_empty (fixture->monitor);
2639
2640   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2641                                        &iter1, "0:1");
2642   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
2643                                        &iter4, "0:4");
2644
2645   gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
2646   signal_monitor_assert_is_empty (fixture->monitor);
2647 }
2648
2649 static void
2650 insert_before (void)
2651 {
2652   GtkTreeStore *store;
2653   GtkTreeModel *filter;
2654   GtkWidget *tree_view;
2655   SignalMonitor *monitor;
2656   GtkTreeIter iter;
2657   GtkTreeIter last_iter;
2658   GtkTreePath *path;
2659
2660   /* This tests two aspects of the row-inserted handling:
2661    *   1) If the newly inserted node was already handled by building
2662    *      the root level, don't handle it a second time.
2663    *   2) Offsets of existing nodes must be updated when a new
2664    *      node is inserted.
2665    */
2666
2667   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2668   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2669   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2670                                             1);
2671
2672   tree_view = gtk_tree_view_new_with_model (filter);
2673   monitor = signal_monitor_new (filter);
2674
2675   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
2676
2677   /* Insert 0 */
2678   path = gtk_tree_path_new_from_indices (0, -1);
2679   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2680   gtk_tree_path_free (path);
2681
2682   gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
2683                                      0, "Foo", 1, TRUE, -1);
2684
2685   signal_monitor_assert_is_empty (monitor);
2686   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2687
2688   /* Insert 1 */
2689   path = gtk_tree_path_new_from_indices (1, -1);
2690   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2691   gtk_tree_path_free (path);
2692
2693   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2694                                      0, "Foo", 1, TRUE, -1);
2695   last_iter = iter;
2696
2697   signal_monitor_assert_is_empty (monitor);
2698   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2699
2700   /* Insert on 1 again -- invisible */
2701   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2702                                      0, "Foo", 1, FALSE, -1);
2703
2704   signal_monitor_assert_is_empty (monitor);
2705   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
2706
2707   /* Insert on 1 again -- visible */
2708   path = gtk_tree_path_new_from_indices (1, -1);
2709   signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
2710   gtk_tree_path_free (path);
2711
2712   gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
2713                                      0, "Foo", 1, TRUE, -1);
2714
2715   signal_monitor_assert_is_empty (monitor);
2716   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2717
2718   /* Modify the iter that should be at the last position and check the
2719    * signal we get.
2720    */
2721   path = gtk_tree_path_new_from_indices (2, -1);
2722   signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
2723   gtk_tree_path_free (path);
2724
2725   gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
2726
2727   signal_monitor_assert_is_empty (monitor);
2728   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
2729 }
2730
2731 static void
2732 insert_child (void)
2733 {
2734   GtkTreeStore *store;
2735   GtkTreeModel *filter;
2736   GtkWidget *tree_view;
2737   SignalMonitor *monitor;
2738   GtkTreeIter parent, iter;
2739   GtkTreePath *path;
2740
2741   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
2742
2743   gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
2744                                      0, "Parent", 1, TRUE, -1);
2745
2746
2747   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
2748   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
2749                                             1);
2750
2751   tree_view = gtk_tree_view_new_with_model (filter);
2752   monitor = signal_monitor_new (filter);
2753
2754   /* Insert child -- invisible */
2755   path = gtk_tree_path_new_from_indices (0, -1);
2756   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2757   /* The signal is received twice, once a pass through from GtkTreeStore
2758    * and one generated by GtkTreeModelFilter.  Not accurate, but cannot
2759    * hurt.
2760    */
2761   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2762   gtk_tree_path_free (path);
2763
2764   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2765                                      0, "Child", 1, FALSE, -1);
2766
2767   signal_monitor_assert_is_empty (monitor);
2768   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2769
2770   /* Insert child */
2771   path = gtk_tree_path_new_from_indices (0, 0, -1);
2772   gtk_tree_path_up (path); /* 0 */
2773   signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
2774   gtk_tree_path_free (path);
2775
2776   gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
2777                                      0, "Child", 1, TRUE, -1);
2778
2779   signal_monitor_assert_is_empty (monitor);
2780   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2781
2782   /* Insert child -- invisible */
2783   gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
2784                                      0, "Child", 1, FALSE, -1);
2785
2786   signal_monitor_assert_is_empty (monitor);
2787   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
2788 }
2789
2790
2791
2792 static void
2793 remove_node (void)
2794 {
2795   GtkTreeIter iter, iter1, iter2, iter3;
2796   GtkListStore *list;
2797   GtkTreeModel *filter;
2798   GtkWidget *view G_GNUC_UNUSED;
2799
2800   list = gtk_list_store_new (1, G_TYPE_INT);
2801   gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
2802   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
2803   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
2804   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
2805   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
2806   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
2807   gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
2808   gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
2809
2810   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
2811   view = gtk_tree_view_new_with_model (filter);
2812
2813   gtk_list_store_remove (list, &iter1);
2814   gtk_list_store_remove (list, &iter3);
2815   gtk_list_store_remove (list, &iter2);
2816
2817   gtk_widget_destroy (view);
2818   g_object_unref (filter);
2819   g_object_unref (list);
2820 }
2821
2822 static void
2823 remove_node_vroot (void)
2824 {
2825   GtkTreeIter parent, root;
2826   GtkTreeIter iter, iter1, iter2, iter3;
2827   GtkTreeStore *tree;
2828   GtkTreeModel *filter;
2829   GtkTreePath *path;
2830   GtkWidget *view G_GNUC_UNUSED;
2831
2832   tree = gtk_tree_store_new (1, G_TYPE_INT);
2833   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2834   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2835
2836   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2837   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2838   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2839   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2840   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2841   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2842   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2843   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2844
2845   path = gtk_tree_path_new_from_indices (0, 0, -1);
2846   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2847   gtk_tree_path_free (path);
2848
2849   view = gtk_tree_view_new_with_model (filter);
2850
2851   gtk_tree_store_remove (tree, &iter1);
2852   gtk_tree_store_remove (tree, &iter3);
2853   gtk_tree_store_remove (tree, &iter2);
2854
2855   gtk_widget_destroy (view);
2856   g_object_unref (filter);
2857   g_object_unref (tree);
2858 }
2859
2860 static void
2861 remove_vroot_ancestor (void)
2862 {
2863   GtkTreeIter parent, root;
2864   GtkTreeIter iter, iter1, iter2, iter3;
2865   GtkTreeStore *tree;
2866   GtkTreeModel *filter;
2867   GtkTreePath *path;
2868   GtkWidget *view G_GNUC_UNUSED;
2869
2870   tree = gtk_tree_store_new (1, G_TYPE_INT);
2871   gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
2872   gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
2873
2874   gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
2875   gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
2876   gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
2877   gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
2878   gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
2879   gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
2880   gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
2881   gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
2882
2883   path = gtk_tree_path_new_from_indices (0, 0, -1);
2884   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
2885   gtk_tree_path_free (path);
2886
2887   view = gtk_tree_view_new_with_model (filter);
2888
2889   gtk_tree_store_remove (tree, &parent);
2890
2891   gtk_widget_destroy (view);
2892   g_object_unref (filter);
2893   g_object_unref (tree);
2894 }
2895
2896 static void
2897 ref_count_single_level (void)
2898 {
2899   GtkTreeIter iter[5];
2900   GtkTreeModel *model;
2901   GtkTreeModelRefCount *ref_model;
2902   GtkTreeModel *filter_model;
2903   GtkWidget *tree_view;
2904
2905   model = gtk_tree_model_ref_count_new ();
2906   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2907
2908   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[0], NULL);
2909   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[1], NULL);
2910   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[2], NULL);
2911   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[3], NULL);
2912   gtk_tree_store_append (GTK_TREE_STORE (model), &iter[4], NULL);
2913
2914   assert_root_level_unreferenced (ref_model);
2915
2916   filter_model = gtk_tree_model_filter_new (model, NULL);
2917   tree_view = gtk_tree_view_new_with_model (filter_model);
2918
2919   assert_node_ref_count (ref_model, &iter[0], 2);
2920   assert_node_ref_count (ref_model, &iter[1], 1);
2921   assert_node_ref_count (ref_model, &iter[2], 1);
2922   assert_node_ref_count (ref_model, &iter[3], 1);
2923   assert_node_ref_count (ref_model, &iter[4], 1);
2924
2925   gtk_widget_destroy (tree_view);
2926
2927   assert_node_ref_count (ref_model, &iter[0], 1);
2928   assert_node_ref_count (ref_model, &iter[1], 0);
2929   assert_node_ref_count (ref_model, &iter[2], 0);
2930   assert_node_ref_count (ref_model, &iter[3], 0);
2931   assert_node_ref_count (ref_model, &iter[4], 0);
2932
2933   g_object_unref (filter_model);
2934
2935   assert_node_ref_count (ref_model, &iter[0], 0);
2936
2937   g_object_unref (ref_model);
2938 }
2939
2940 static void
2941 ref_count_two_levels (void)
2942 {
2943   GtkTreeIter parent1, parent2, iter, iter_first;
2944   GtkTreeModel *model;
2945   GtkTreeModelRefCount *ref_model;
2946   GtkTreeModel *filter_model;
2947   GtkWidget *tree_view;
2948
2949   model = gtk_tree_model_ref_count_new ();
2950   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
2951
2952   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
2953   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
2954   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_first, &parent2);
2955   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2956   gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
2957
2958   assert_entire_model_unreferenced (ref_model);
2959
2960   filter_model = gtk_tree_model_filter_new (model, NULL);
2961   tree_view = gtk_tree_view_new_with_model (filter_model);
2962
2963   /* This is quite confusing:
2964    *  - node 0 has a ref count of 2 because it is referenced as the
2965    *    first node in a level and by the tree view.
2966    *  - node 1 has a ref count of 2 because it is referenced by its
2967    *    child level and by the tree view.
2968    */
2969   assert_root_level_referenced (ref_model, 2);
2970   assert_node_ref_count (ref_model, &iter_first, 1);
2971   assert_node_ref_count (ref_model, &iter, 0);
2972
2973   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
2974
2975   assert_node_ref_count (ref_model, &parent1, 2);
2976   assert_node_ref_count (ref_model, &parent2, 2);
2977   assert_node_ref_count (ref_model, &iter_first, 2);
2978   assert_node_ref_count (ref_model, &iter, 1);
2979
2980   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
2981
2982   /* The child level is not destroyed because its parent is visible */
2983   assert_node_ref_count (ref_model, &parent1, 2);
2984   assert_node_ref_count (ref_model, &parent2, 2);
2985   assert_node_ref_count (ref_model, &iter_first, 1);
2986   assert_node_ref_count (ref_model, &iter, 0);
2987
2988   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
2989
2990   assert_node_ref_count (ref_model, &parent1, 2);
2991   assert_node_ref_count (ref_model, &parent2, 2);
2992   assert_node_ref_count (ref_model, &iter_first, 1);
2993   assert_node_ref_count (ref_model, &iter, 0);
2994
2995   gtk_widget_destroy (tree_view);
2996
2997   assert_root_level_referenced (ref_model, 1);
2998   assert_node_ref_count (ref_model, &iter_first, 1);
2999   assert_node_ref_count (ref_model, &iter, 0);
3000
3001   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3002
3003   /* The first two levels should not be cleared, these are used to
3004    * monitor whether or not the parent must become (in)visible.
3005    */
3006   assert_root_level_referenced (ref_model, 1);
3007   assert_node_ref_count (ref_model, &iter_first, 1);
3008   assert_node_ref_count (ref_model, &iter, 0);
3009
3010   g_object_unref (filter_model);
3011   g_object_unref (ref_model);
3012 }
3013
3014 static void
3015 ref_count_three_levels (void)
3016 {
3017   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3018   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3019   GtkTreeModel *model;
3020   GtkTreeModelRefCount *ref_model;
3021   GtkTreeModel *filter_model;
3022   GtkTreePath *path;
3023   GtkWidget *tree_view;
3024
3025   model = gtk_tree_model_ref_count_new ();
3026   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3027
3028   /* + grandparent1
3029    * + grandparent2
3030    *   + parent1
3031    *     + iter_parent1
3032    *   + parent2
3033    *     + iter_parent2_first
3034    *     + iter_parent2
3035    */
3036
3037   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3038   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3039   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3040   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3041   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3042   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3043   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3044
3045   assert_entire_model_unreferenced (ref_model);
3046
3047   filter_model = gtk_tree_model_filter_new (model, NULL);
3048   tree_view = gtk_tree_view_new_with_model (filter_model);
3049
3050   /* This is quite confusing:
3051    *  - node 0 has a ref count of 2 because it is referenced as the
3052    *    first node in a level and by the tree view.
3053    *  - node 1 has a ref count of 2 because it is referenced by its
3054    *    child level and by the tree view.
3055    */
3056   assert_root_level_referenced (ref_model, 2);
3057   assert_node_ref_count (ref_model, &parent1, 1);
3058   assert_node_ref_count (ref_model, &parent2, 0);
3059   assert_level_unreferenced (ref_model, &parent1);
3060   assert_level_unreferenced (ref_model, &parent2);
3061
3062   path = gtk_tree_path_new_from_indices (1, -1);
3063   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
3064
3065   assert_node_ref_count (ref_model, &grandparent1, 2);
3066   assert_node_ref_count (ref_model, &grandparent2, 2);
3067   assert_node_ref_count (ref_model, &parent1, 3);
3068   assert_node_ref_count (ref_model, &parent2, 2);
3069   assert_node_ref_count (ref_model, &iter_parent1, 1);
3070   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3071   assert_node_ref_count (ref_model, &iter_parent2, 0);
3072
3073   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
3074
3075   assert_node_ref_count (ref_model, &grandparent1, 2);
3076   assert_node_ref_count (ref_model, &grandparent2, 2);
3077   assert_node_ref_count (ref_model, &parent1, 3);
3078   assert_node_ref_count (ref_model, &parent2, 2);
3079   assert_node_ref_count (ref_model, &iter_parent1, 2);
3080   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3081   assert_node_ref_count (ref_model, &iter_parent2, 1);
3082
3083   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3084
3085   assert_node_ref_count (ref_model, &grandparent1, 2);
3086   assert_node_ref_count (ref_model, &grandparent2, 2);
3087   assert_node_ref_count (ref_model, &parent1, 2);
3088   assert_node_ref_count (ref_model, &parent2, 1);
3089   assert_node_ref_count (ref_model, &iter_parent1, 1);
3090   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3091   assert_node_ref_count (ref_model, &iter_parent2, 0);
3092
3093   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3094
3095   assert_node_ref_count (ref_model, &grandparent1, 2);
3096   assert_node_ref_count (ref_model, &grandparent2, 2);
3097   assert_node_ref_count (ref_model, &parent1, 2);
3098   assert_node_ref_count (ref_model, &parent2, 1);
3099   assert_node_ref_count (ref_model, &iter_parent1, 1);
3100   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3101   assert_node_ref_count (ref_model, &iter_parent2, 0);
3102
3103   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
3104
3105   assert_node_ref_count (ref_model, &grandparent1, 2);
3106   assert_node_ref_count (ref_model, &grandparent2, 2);
3107   assert_node_ref_count (ref_model, &parent1, 3);
3108   assert_node_ref_count (ref_model, &parent2, 2);
3109   assert_node_ref_count (ref_model, &iter_parent1, 1);
3110   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3111   assert_node_ref_count (ref_model, &iter_parent2, 0);
3112
3113   gtk_tree_path_append_index (path, 1);
3114   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
3115
3116   assert_node_ref_count (ref_model, &grandparent1, 2);
3117   assert_node_ref_count (ref_model, &grandparent2, 2);
3118   assert_node_ref_count (ref_model, &parent1, 3);
3119   assert_node_ref_count (ref_model, &parent2, 2);
3120   assert_node_ref_count (ref_model, &iter_parent1, 1);
3121   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3122   assert_node_ref_count (ref_model, &iter_parent2, 1);
3123
3124   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
3125
3126   assert_node_ref_count (ref_model, &grandparent1, 2);
3127   assert_node_ref_count (ref_model, &grandparent2, 2);
3128   assert_node_ref_count (ref_model, &parent1, 3);
3129   assert_node_ref_count (ref_model, &parent2, 2);
3130   assert_node_ref_count (ref_model, &iter_parent1, 1);
3131   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3132   assert_node_ref_count (ref_model, &iter_parent2, 0);
3133
3134   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3135
3136   assert_node_ref_count (ref_model, &grandparent1, 2);
3137   assert_node_ref_count (ref_model, &grandparent2, 2);
3138   assert_node_ref_count (ref_model, &parent1, 3);
3139   assert_node_ref_count (ref_model, &parent2, 2);
3140   assert_node_ref_count (ref_model, &iter_parent1, 1);
3141   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3142   assert_node_ref_count (ref_model, &iter_parent2, 0);
3143
3144   gtk_tree_path_up (path);
3145   gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
3146   gtk_tree_path_free (path);
3147
3148   assert_node_ref_count (ref_model, &grandparent1, 2);
3149   assert_node_ref_count (ref_model, &grandparent2, 2);
3150   assert_node_ref_count (ref_model, &parent1, 2);
3151   assert_node_ref_count (ref_model, &parent2, 1);
3152   assert_node_ref_count (ref_model, &iter_parent1, 1);
3153   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3154   assert_node_ref_count (ref_model, &iter_parent2, 0);
3155
3156   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3157
3158   assert_node_ref_count (ref_model, &grandparent1, 2);
3159   assert_node_ref_count (ref_model, &grandparent2, 2);
3160   assert_node_ref_count (ref_model, &parent1, 2);
3161   assert_node_ref_count (ref_model, &parent2, 1);
3162   assert_node_ref_count (ref_model, &iter_parent1, 1);
3163   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3164   assert_node_ref_count (ref_model, &iter_parent2, 0);
3165
3166   gtk_widget_destroy (tree_view);
3167
3168   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3169
3170   /* The first two levels should not be cleared, these are used to
3171    * monitor whether or not the parent must become (in)visible.
3172    */
3173   assert_node_ref_count (ref_model, &grandparent1, 1);
3174   assert_node_ref_count (ref_model, &grandparent2, 1);
3175   assert_node_ref_count (ref_model, &parent1, 1);
3176   assert_node_ref_count (ref_model, &parent2, 0);
3177   assert_node_ref_count (ref_model, &iter_parent1, 0);
3178   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3179   assert_node_ref_count (ref_model, &iter_parent2, 0);
3180
3181   g_object_unref (filter_model);
3182   g_object_unref (ref_model);
3183 }
3184
3185 static void
3186 ref_count_delete_row (void)
3187 {
3188   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3189   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3190   GtkTreeModel *model;
3191   GtkTreeModelRefCount *ref_model;
3192   GtkTreeModel *filter_model;
3193   GtkTreePath *path;
3194   GtkWidget *tree_view;
3195
3196   model = gtk_tree_model_ref_count_new ();
3197   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3198
3199   /* + grandparent1
3200    * + grandparent2
3201    *   + parent1
3202    *     + iter_parent1
3203    *   + parent2
3204    *     + iter_parent2_first
3205    *     + iter_parent2
3206    */
3207
3208   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3209   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3210   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3211   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3212   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3213   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3214   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3215
3216   assert_entire_model_unreferenced (ref_model);
3217
3218   filter_model = gtk_tree_model_filter_new (model, NULL);
3219   tree_view = gtk_tree_view_new_with_model (filter_model);
3220
3221   assert_root_level_referenced (ref_model, 2);
3222   assert_node_ref_count (ref_model, &parent1, 1);
3223   assert_node_ref_count (ref_model, &parent2, 0);
3224   assert_level_unreferenced (ref_model, &parent1);
3225   assert_level_unreferenced (ref_model, &parent2);
3226
3227   path = gtk_tree_path_new_from_indices (1, -1);
3228   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
3229
3230   assert_node_ref_count (ref_model, &grandparent1, 2);
3231   assert_node_ref_count (ref_model, &grandparent2, 2);
3232   assert_node_ref_count (ref_model, &parent1, 3);
3233   assert_node_ref_count (ref_model, &parent2, 2);
3234   assert_node_ref_count (ref_model, &iter_parent1, 2);
3235   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3236   assert_node_ref_count (ref_model, &iter_parent2, 1);
3237
3238   gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
3239
3240   assert_node_ref_count (ref_model, &grandparent1, 2);
3241   assert_node_ref_count (ref_model, &grandparent2, 2);
3242   assert_node_ref_count (ref_model, &parent1, 3);
3243   assert_node_ref_count (ref_model, &parent2, 2);
3244   assert_node_ref_count (ref_model, &iter_parent1, 2);
3245   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3246
3247   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
3248
3249   assert_node_ref_count (ref_model, &grandparent1, 2);
3250   assert_node_ref_count (ref_model, &grandparent2, 2);
3251   assert_node_ref_count (ref_model, &parent2, 3);
3252   assert_level_referenced (ref_model, 2, &parent2);
3253
3254   gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
3255
3256   assert_node_ref_count (ref_model, &grandparent1, 2);
3257
3258   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3259
3260   assert_node_ref_count (ref_model, &grandparent1, 2);
3261
3262   gtk_widget_destroy (tree_view);
3263   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3264
3265   assert_node_ref_count (ref_model, &grandparent1, 1);
3266
3267   g_object_unref (filter_model);
3268
3269   assert_node_ref_count (ref_model, &grandparent1, 0);
3270
3271   g_object_unref (ref_model);
3272 }
3273
3274 static void
3275 ref_count_cleanup (void)
3276 {
3277   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3278   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3279   GtkTreeModel *model;
3280   GtkTreeModelRefCount *ref_model;
3281   GtkTreeModel *filter_model;
3282   GtkWidget *tree_view;
3283
3284   model = gtk_tree_model_ref_count_new ();
3285   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3286
3287   /* + grandparent1
3288    * + grandparent2
3289    *   + parent1
3290    *     + iter_parent1
3291    *   + parent2
3292    *     + iter_parent2_first
3293    *     + iter_parent2
3294    */
3295
3296   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3297   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3298   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3299   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3300   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3301   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3302   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3303
3304   filter_model = gtk_tree_model_filter_new (model, NULL);
3305   tree_view = gtk_tree_view_new_with_model (filter_model);
3306
3307   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3308
3309   assert_node_ref_count (ref_model, &grandparent1, 2);
3310   assert_node_ref_count (ref_model, &grandparent2, 2);
3311   assert_node_ref_count (ref_model, &parent1, 3);
3312   assert_node_ref_count (ref_model, &parent2, 2);
3313   assert_node_ref_count (ref_model, &iter_parent1, 2);
3314   assert_node_ref_count (ref_model, &iter_parent2_first, 2);
3315   assert_node_ref_count (ref_model, &iter_parent2, 1);
3316
3317   gtk_widget_destroy (tree_view);
3318
3319   assert_node_ref_count (ref_model, &grandparent1, 1);
3320   assert_node_ref_count (ref_model, &grandparent2, 1);
3321   assert_node_ref_count (ref_model, &parent1, 2);
3322   assert_node_ref_count (ref_model, &parent2, 1);
3323   assert_node_ref_count (ref_model, &iter_parent1, 1);
3324   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3325   assert_node_ref_count (ref_model, &iter_parent2, 0);
3326
3327   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3328
3329   /* The first two levels should not be cleared, these are used to
3330    * monitor whether or not the parent must become (in)visible.
3331    */
3332   assert_node_ref_count (ref_model, &grandparent1, 1);
3333   assert_node_ref_count (ref_model, &grandparent2, 1);
3334   assert_node_ref_count (ref_model, &parent1, 1);
3335   assert_node_ref_count (ref_model, &parent2, 0);
3336   assert_node_ref_count (ref_model, &iter_parent1, 0);
3337   assert_node_ref_count (ref_model, &iter_parent2_first, 0);
3338   assert_node_ref_count (ref_model, &iter_parent2, 0);
3339
3340   g_object_unref (filter_model);
3341   g_object_unref (ref_model);
3342 }
3343
3344 static void
3345 ref_count_row_ref (void)
3346 {
3347   GtkTreeIter grandparent1, grandparent2, parent1, parent2;
3348   GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
3349   GtkTreeModel *model;
3350   GtkTreeModelRefCount *ref_model;
3351   GtkTreeModel *filter_model;
3352   GtkWidget *tree_view;
3353   GtkTreePath *path;
3354   GtkTreeRowReference *row_ref;
3355
3356   model = gtk_tree_model_ref_count_new ();
3357   ref_model = GTK_TREE_MODEL_REF_COUNT (model);
3358
3359   /* + grandparent1
3360    * + grandparent2
3361    *   + parent1
3362    *     + iter_parent1
3363    *   + parent2
3364    *     + iter_parent2
3365    *     + iter_parent2
3366    */
3367
3368   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
3369   gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
3370   gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
3371   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
3372   gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
3373   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
3374   gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
3375
3376   filter_model = gtk_tree_model_filter_new (model, NULL);
3377   tree_view = gtk_tree_view_new_with_model (filter_model);
3378
3379   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3380   row_ref = gtk_tree_row_reference_new (filter_model, path);
3381   gtk_tree_path_free (path);
3382
3383   assert_node_ref_count (ref_model, &grandparent1, 2);
3384   assert_node_ref_count (ref_model, &grandparent2, 3);
3385   assert_node_ref_count (ref_model, &parent1, 1);
3386   assert_node_ref_count (ref_model, &parent2, 2);
3387   assert_node_ref_count (ref_model, &iter_parent1, 0);
3388   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3389   assert_node_ref_count (ref_model, &iter_parent2, 1);
3390
3391   gtk_tree_row_reference_free (row_ref);
3392
3393   assert_node_ref_count (ref_model, &grandparent1, 2);
3394   assert_node_ref_count (ref_model, &grandparent2, 2);
3395   assert_node_ref_count (ref_model, &parent1, 1);
3396   assert_node_ref_count (ref_model, &parent2, 1);
3397   assert_node_ref_count (ref_model, &iter_parent1, 0);
3398   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3399   assert_node_ref_count (ref_model, &iter_parent2, 0);
3400
3401   path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
3402   row_ref = gtk_tree_row_reference_new (filter_model, path);
3403   gtk_tree_path_free (path);
3404
3405   assert_node_ref_count (ref_model, &grandparent1, 2);
3406   assert_node_ref_count (ref_model, &grandparent2, 3);
3407   assert_node_ref_count (ref_model, &parent1, 1);
3408   assert_node_ref_count (ref_model, &parent2, 2);
3409   assert_node_ref_count (ref_model, &iter_parent1, 0);
3410   assert_node_ref_count (ref_model, &iter_parent2_first, 1);
3411   assert_node_ref_count (ref_model, &iter_parent2, 1);
3412
3413   gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
3414
3415   assert_node_ref_count (ref_model, &grandparent1, 2);
3416   assert_node_ref_count (ref_model, &grandparent2, 2);
3417   assert_node_ref_count (ref_model, &parent1, 1);
3418   assert_node_ref_count (ref_model, &iter_parent1, 0);
3419
3420   gtk_tree_row_reference_free (row_ref);
3421
3422   assert_node_ref_count (ref_model, &grandparent1, 2);
3423   assert_node_ref_count (ref_model, &grandparent2, 2);
3424   assert_node_ref_count (ref_model, &parent1, 1);
3425   assert_node_ref_count (ref_model, &iter_parent1, 0);
3426
3427   gtk_widget_destroy (tree_view);
3428
3429   gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
3430
3431   /* The first two levels should not be cleared, these are used to
3432    * monitor whether or not the parent must become (in)visible.
3433    */
3434   assert_node_ref_count (ref_model, &grandparent1, 1);
3435   assert_node_ref_count (ref_model, &grandparent2, 1);
3436   assert_node_ref_count (ref_model, &parent1, 1);
3437
3438   g_object_unref (filter_model);
3439   g_object_unref (ref_model);
3440 }
3441
3442
3443 static gboolean
3444 specific_path_dependent_filter_func (GtkTreeModel *model,
3445                                      GtkTreeIter  *iter,
3446                                      gpointer      data)
3447 {
3448   GtkTreePath *path;
3449
3450   path = gtk_tree_model_get_path (model, iter);
3451   if (gtk_tree_path_get_indices (path)[0] < 4)
3452     return FALSE;
3453
3454   return TRUE;
3455 }
3456
3457 static void
3458 specific_path_dependent_filter (void)
3459 {
3460   int i;
3461   GtkTreeIter iter;
3462   GtkListStore *list;
3463   GtkTreeModel *sort;
3464   GtkTreeModel *filter;
3465
3466   list = gtk_list_store_new (1, G_TYPE_INT);
3467   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
3468   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
3469   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
3470   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
3471   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
3472   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
3473   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
3474   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
3475
3476   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
3477   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
3478   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3479                                           specific_path_dependent_filter_func,
3480                                           NULL, NULL);
3481
3482   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
3483                                         GTK_SORT_DESCENDING);
3484
3485   for (i = 0; i < 4; i++)
3486     {
3487       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3488                                          NULL, 1))
3489         gtk_list_store_remove (list, &iter);
3490
3491       if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
3492                                          NULL, 2))
3493         gtk_list_store_remove (list, &iter);
3494     }
3495
3496   g_object_unref (filter);
3497   g_object_unref (sort);
3498   g_object_unref (list);
3499 }
3500
3501
3502 static gboolean
3503 specific_append_after_collapse_visible_func (GtkTreeModel *model,
3504                                              GtkTreeIter  *iter,
3505                                              gpointer      data)
3506 {
3507   gint number;
3508   gboolean hide_negative_numbers;
3509
3510   gtk_tree_model_get (model, iter, 1, &number, -1);
3511   hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
3512
3513   return (number >= 0 || !hide_negative_numbers);
3514 }
3515
3516 static void
3517 specific_append_after_collapse (void)
3518 {
3519   /* This test is based on one of the test cases I found in my
3520    * old test cases directory.  I unfortunately do not have a record
3521    * from who this test case originated.  -Kris.
3522    *
3523    * General idea:
3524    * - Construct tree.
3525    * - Show tree, expand, collapse.
3526    * - Add a row.
3527    */
3528
3529   GtkTreeIter iter;
3530   GtkTreeIter child_iter;
3531   GtkTreeIter child_iter2;
3532   GtkTreePath *append_path;
3533   GtkTreeStore *store;
3534   GtkTreeModel *filter;
3535   GtkTreeModel *sort;
3536
3537   GtkWidget *window;
3538   GtkWidget *tree_view;
3539
3540   store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
3541
3542   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
3543   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3544                      GINT_TO_POINTER (FALSE));
3545   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3546                                           specific_append_after_collapse_visible_func,
3547                                           filter, NULL);
3548
3549   sort = gtk_tree_model_sort_new_with_model (filter);
3550
3551   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3552   tree_view = gtk_tree_view_new_with_model (sort);
3553   gtk_container_add (GTK_CONTAINER (window), tree_view);
3554   gtk_widget_realize (tree_view);
3555
3556   while (gtk_events_pending ())
3557     gtk_main_iteration ();
3558
3559   gtk_tree_store_prepend (store, &iter, NULL);
3560   gtk_tree_store_set (store, &iter,
3561                       0, "hallo", 1, 1, -1);
3562
3563   gtk_tree_store_append (store, &child_iter, &iter);
3564   gtk_tree_store_set (store, &child_iter,
3565                       0, "toemaar", 1, 1, -1);
3566
3567   gtk_tree_store_append (store, &child_iter2, &child_iter);
3568   gtk_tree_store_set (store, &child_iter2,
3569                       0, "very deep", 1, 1, -1);
3570
3571   append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
3572
3573   gtk_tree_store_append (store, &child_iter, &iter);
3574   gtk_tree_store_set (store, &child_iter,
3575                       0, "sja", 1, 1, -1);
3576
3577   gtk_tree_store_append (store, &child_iter, &iter);
3578   gtk_tree_store_set (store, &child_iter,
3579                       0, "some word", 1, -1, -1);
3580
3581   /* Expand and collapse the tree */
3582   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3583   while (gtk_events_pending ())
3584     gtk_main_iteration ();
3585
3586   gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
3587   while (gtk_events_pending ())
3588     gtk_main_iteration ();
3589
3590   /* Add another it */
3591   g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
3592                      GINT_TO_POINTER (TRUE));
3593
3594   if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
3595     {
3596       gtk_tree_store_append (store, &child_iter, &iter);
3597       gtk_tree_store_set (store, &child_iter,
3598                           0, "new new new !!", 1, 1, -1);
3599     }
3600   gtk_tree_path_free (append_path);
3601
3602   /* Expand */
3603   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
3604   while (gtk_events_pending ())
3605     gtk_main_iteration ();
3606 }
3607
3608
3609 static gint
3610 specific_sort_filter_remove_node_compare_func (GtkTreeModel  *model,
3611                                                GtkTreeIter   *iter1,
3612                                                GtkTreeIter   *iter2,
3613                                                gpointer       data)
3614 {
3615   return -1;
3616 }
3617
3618 static gboolean
3619 specific_sort_filter_remove_node_visible_func (GtkTreeModel  *model,
3620                                                GtkTreeIter   *iter,
3621                                                gpointer       data)
3622 {
3623   char *item = NULL;
3624
3625   /* Do reference the model */
3626   gtk_tree_model_get (model, iter, 0, &item, -1);
3627   g_free (item);
3628
3629   return FALSE;
3630 }
3631
3632 static void
3633 specific_sort_filter_remove_node (void)
3634 {
3635   /* This test is based on one of the test cases I found in my
3636    * old test cases directory.  I unfortunately do not have a record
3637    * from who this test case originated.  -Kris.
3638    *
3639    * General idea:
3640    *  - Create tree store, sort, filter models.  The sort model has
3641    *    a default sort func that is enabled, filter model a visible func
3642    *    that defaults to returning FALSE.
3643    *  - Remove a node from the tree store.
3644    */
3645
3646   GtkTreeIter iter;
3647   GtkTreeStore *store;
3648   GtkTreeModel *filter;
3649   GtkTreeModel *sort;
3650
3651   GtkWidget *window;
3652   GtkWidget *tree_view;
3653
3654   store = gtk_tree_store_new (1, G_TYPE_STRING);
3655   gtk_tree_store_append (store, &iter, NULL);
3656   gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
3657
3658   gtk_tree_store_append (store, &iter, NULL);
3659   gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
3660
3661   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
3662   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
3663                                            specific_sort_filter_remove_node_compare_func, NULL, NULL);
3664
3665   filter = gtk_tree_model_filter_new (sort, NULL);
3666   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
3667                                           specific_sort_filter_remove_node_visible_func,
3668                                           filter, NULL);
3669
3670
3671   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
3672   tree_view = gtk_tree_view_new_with_model (filter);
3673   gtk_container_add (GTK_CONTAINER (window), tree_view);
3674   gtk_widget_realize (tree_view);
3675
3676   while (gtk_events_pending ())
3677     gtk_main_iteration ();
3678
3679   /* Remove a node */
3680   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
3681   gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
3682   gtk_tree_store_remove (store, &iter);
3683
3684   while (gtk_events_pending ())
3685     gtk_main_iteration ();
3686 }
3687
3688
3689 static void
3690 specific_sort_filter_remove_root (void)
3691 {
3692   /* This test is based on one of the test cases I found in my
3693    * old test cases directory.  I unfortunately do not have a record
3694    * from who this test case originated.  -Kris.
3695    */
3696
3697   GtkTreeModel *model, *sort, *filter;
3698   GtkTreeIter root, mid, leaf;
3699   GtkTreePath *path;
3700
3701   model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
3702   gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
3703   gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
3704   gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
3705
3706   path = gtk_tree_model_get_path (model, &mid);
3707
3708   sort = gtk_tree_model_sort_new_with_model (model);
3709   filter = gtk_tree_model_filter_new (sort, path);
3710
3711   gtk_tree_path_free (path);
3712
3713   gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
3714
3715   g_object_unref (filter);
3716   g_object_unref (sort);
3717   g_object_unref (model);
3718 }
3719
3720
3721 static void
3722 specific_root_mixed_visibility (void)
3723 {
3724   int i;
3725   GtkTreeModel *filter;
3726   /* A bit nasty, apologies */
3727   FilterTest fixture;
3728
3729   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3730
3731   for (i = 0; i < LEVEL_LENGTH; i++)
3732     {
3733       GtkTreeIter iter;
3734
3735       gtk_tree_store_insert (fixture.store, &iter, NULL, i);
3736       if (i % 2 == 0)
3737         create_tree_store_set_values (fixture.store, &iter, TRUE);
3738       else
3739         create_tree_store_set_values (fixture.store, &iter, FALSE);
3740     }
3741
3742   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3743   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3744   fixture.monitor = NULL;
3745
3746   gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
3747
3748   /* In order to trigger the potential bug, we should not access
3749    * the filter model here (so don't call the check functions).
3750    */
3751
3752   /* Change visibility of an odd row to TRUE */
3753   set_path_visibility (&fixture, "3", TRUE);
3754   check_filter_model (&fixture);
3755   check_level_length (fixture.filter, NULL, 4);
3756 }
3757
3758
3759
3760 static gboolean
3761 specific_has_child_filter_filter_func (GtkTreeModel *model,
3762                                        GtkTreeIter  *iter,
3763                                        gpointer      data)
3764 {
3765   return gtk_tree_model_iter_has_child (model, iter);
3766 }
3767
3768 static void
3769 specific_has_child_filter (void)
3770 {
3771   GtkTreeModel *filter;
3772   GtkTreeIter iter, root;
3773   FilterTest fixture; /* This is not how it should be done */
3774   GtkWidget *tree_view;
3775
3776   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3777   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3778   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3779   fixture.monitor = signal_monitor_new (filter);
3780
3781   tree_view = gtk_tree_view_new_with_model (filter);
3782
3783   /* We will filter on parent state using a filter function.  We will
3784    * manually keep the boolean column in sync, so that we can use
3785    * check_filter_model() to check the consistency of the model.
3786    */
3787   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3788    * to be able to check the structure here.  We keep the calls to
3789    * check_filter_model() commented out until then.
3790    */
3791   gtk_tree_model_filter_set_visible_func (fixture.filter,
3792                                           specific_has_child_filter_filter_func,
3793                                           NULL, NULL);
3794
3795   /* The first node will be initially invisible: no signals */
3796   gtk_tree_store_append (fixture.store, &root, NULL);
3797   create_tree_store_set_values (fixture.store, &root, FALSE);
3798
3799   /* check_filter_model (&fixture); */
3800   check_level_length (fixture.filter, NULL, 0);
3801   signal_monitor_assert_is_empty (fixture.monitor);
3802
3803   /* Insert a child node. This will cause the parent to become visible
3804    * since there is a child now.
3805    */
3806   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3807   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3808   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3809
3810   gtk_tree_store_append (fixture.store, &iter, &root);
3811   create_tree_store_set_values (fixture.store, &iter, TRUE);
3812
3813   /* Parent must now be visible.  Do the level length check first,
3814    * to avoid modifying the child model triggering a row-changed to
3815    * the filter model.
3816    */
3817   check_level_length (fixture.filter, NULL, 1);
3818   check_level_length (fixture.filter, "0", 0);
3819   signal_monitor_assert_is_empty (fixture.monitor);
3820
3821   /* This should propagate row-changed */
3822   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3823   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3824
3825   set_path_visibility (&fixture, "0", TRUE);
3826   /* check_filter_model (&fixture); */
3827   signal_monitor_assert_is_empty (fixture.monitor);
3828
3829   /* New root node, no child, so no signal */
3830   gtk_tree_store_append (fixture.store, &root, NULL);
3831   check_level_length (fixture.filter, NULL, 1);
3832   signal_monitor_assert_is_empty (fixture.monitor);
3833
3834   /* When the child comes in, this node will become visible */
3835   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3836   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3837   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3838   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3839   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3840
3841   gtk_tree_store_append (fixture.store, &iter, &root);
3842   check_level_length (fixture.filter, NULL, 2);
3843   check_level_length (fixture.filter, "1", 0);
3844
3845   create_tree_store_set_values (fixture.store, &root, TRUE);
3846   create_tree_store_set_values (fixture.store, &iter, TRUE);
3847
3848   /* check_filter_model (&fixture); */
3849   signal_monitor_assert_is_empty (fixture.monitor);
3850
3851   /* Add another child for 1 */
3852   gtk_tree_store_append (fixture.store, &iter, &root);
3853   create_tree_store_set_values (fixture.store, &iter, TRUE);
3854   check_level_length (fixture.filter, NULL, 2);
3855   check_level_length (fixture.filter, "0", 0);
3856   check_level_length (fixture.filter, "1", 0);
3857   signal_monitor_assert_is_empty (fixture.monitor);
3858
3859   /* Now remove one of the remaining child rows */
3860   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
3861
3862   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
3863                                        &iter, "0:0");
3864   gtk_tree_store_remove (fixture.store, &iter);
3865
3866   check_level_length (fixture.filter, NULL, 1);
3867   check_level_length (fixture.filter, "0", 0);
3868
3869   set_path_visibility (&fixture, "0", FALSE);
3870   /* check_filter_model (&fixture); */
3871   signal_monitor_assert_is_empty (fixture.monitor);
3872 }
3873
3874
3875 static gboolean
3876 specific_root_has_child_filter_filter_func (GtkTreeModel *model,
3877                                             GtkTreeIter  *iter,
3878                                             gpointer      data)
3879 {
3880   int depth;
3881   GtkTreePath *path;
3882
3883   path = gtk_tree_model_get_path (model, iter);
3884   depth = gtk_tree_path_get_depth (path);
3885   gtk_tree_path_free (path);
3886
3887   if (depth > 1)
3888     return TRUE;
3889   /* else */
3890   return gtk_tree_model_iter_has_child (model, iter);
3891 }
3892
3893 static void
3894 specific_root_has_child_filter (void)
3895 {
3896   GtkTreeModel *filter;
3897   GtkTreeIter iter, root;
3898   FilterTest fixture; /* This is not how it should be done ... */
3899   GtkWidget *tree_view;
3900
3901   /* This is a variation on the above test case, specific has-child-filter,
3902    * herein the has-child check for visibility only applies to root level
3903    * nodes.  In this test, children are always visible because we
3904    * only filter based on the "has child" criterion.
3905    */
3906
3907   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
3908   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
3909   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
3910   fixture.monitor = signal_monitor_new (filter);
3911
3912   tree_view = gtk_tree_view_new_with_model (filter);
3913
3914   /* We will filter on parent state using a filter function.  We will
3915    * manually keep the boolean column in sync, so that we can use
3916    * check_filter_model() to check the consistency of the model.
3917    */
3918   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
3919    * to be able to check the structure here.  We keep the calls to
3920    * check_filter_model() commented out until then.
3921    */
3922   gtk_tree_model_filter_set_visible_func (fixture.filter,
3923                                           specific_root_has_child_filter_filter_func,
3924                                           NULL, NULL);
3925
3926   /* Add a first node, this will be invisible initially, so no signal
3927    * should be emitted.
3928    */
3929   gtk_tree_store_append (fixture.store, &root, NULL);
3930   create_tree_store_set_values (fixture.store, &root, FALSE);
3931
3932   signal_monitor_assert_is_empty (fixture.monitor);
3933   /* check_filter_model (&fixture); */
3934   check_level_length (fixture.filter, NULL, 0);
3935
3936   /* Add a child node.  This will cause the parent to become visible,
3937    * so we expect row-inserted signals for both.
3938    */
3939   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
3940   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3941   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3942
3943   gtk_tree_store_append (fixture.store, &iter, &root);
3944   signal_monitor_assert_is_empty (fixture.monitor);
3945
3946   check_level_length (fixture.filter, NULL, 1);
3947   check_level_length (fixture.filter, "0", 1);
3948
3949   /* Modify the content of iter, no signals because the parent is not
3950    * expanded.
3951    */
3952   create_tree_store_set_values (fixture.store, &iter, TRUE);
3953   signal_monitor_assert_is_empty (fixture.monitor);
3954
3955   /* Parent must now be visible.  Do the level length check first,
3956    * to avoid modifying the child model triggering a row-changed to
3957    * the filter model.
3958    */
3959   check_level_length (fixture.filter, NULL, 1);
3960   check_level_length (fixture.filter, "0", 1);
3961
3962   /* Modify path 0 */
3963   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
3964   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
3965
3966   set_path_visibility (&fixture, "0", TRUE);
3967   /* check_filter_model (&fixture); */
3968
3969   signal_monitor_assert_is_empty (fixture.monitor);
3970
3971   /* Insert another node in the root level.  Initially invisible, so
3972    * not expecting any signal.
3973    */
3974   gtk_tree_store_append (fixture.store, &root, NULL);
3975   check_level_length (fixture.filter, NULL, 1);
3976
3977   signal_monitor_assert_is_empty (fixture.monitor);
3978
3979   /* Adding a child node which also makes parent at path 1 visible. */
3980   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
3981   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3982   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3983
3984   gtk_tree_store_append (fixture.store, &iter, &root);
3985   check_level_length (fixture.filter, NULL, 2);
3986   check_level_length (fixture.filter, "1", 1);
3987
3988   signal_monitor_assert_is_empty (fixture.monitor);
3989
3990   /* Check if row-changed is propagated */
3991   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
3992   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
3993
3994   create_tree_store_set_values (fixture.store, &root, TRUE);
3995   create_tree_store_set_values (fixture.store, &iter, TRUE);
3996   /* check_filter_model (&fixture); */
3997   signal_monitor_assert_is_empty (fixture.monitor);
3998
3999   /* Insert another child under node 1 */
4000   gtk_tree_store_append (fixture.store, &iter, &root);
4001   create_tree_store_set_values (fixture.store, &iter, TRUE);
4002   check_level_length (fixture.filter, NULL, 2);
4003   check_level_length (fixture.filter, "0", 1);
4004   check_level_length (fixture.filter, "1", 2);
4005   signal_monitor_assert_is_empty (fixture.monitor);
4006
4007   /* Set a child node to invisible.  This should not yield any
4008    * change, because filtering is only done on whether the root
4009    * node has a child, which it still has.
4010    */
4011   set_path_visibility (&fixture, "0:0", FALSE);
4012   signal_monitor_assert_is_empty (fixture.monitor);
4013
4014   /* Now remove one of the remaining child rows */
4015   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4016   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4017
4018   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4019                                        &iter, "0:0");
4020   gtk_tree_store_remove (fixture.store, &iter);
4021
4022   check_level_length (fixture.filter, NULL, 1);
4023   check_level_length (fixture.filter, "0", 2);
4024   signal_monitor_assert_is_empty (fixture.monitor);
4025
4026   /* Set visibility of 0 to FALSE, no-op for filter model since
4027    * the child 0:0 is already gone
4028    */
4029   set_path_visibility (&fixture, "0", FALSE);
4030   /* check_filter_model (&fixture); */
4031   signal_monitor_assert_is_empty (fixture.monitor);
4032 }
4033
4034 static void
4035 specific_has_child_filter_on_sort_model (void)
4036 {
4037   GtkTreeModel *filter;
4038   GtkTreeModel *sort_model;
4039   GtkTreeIter iter, root;
4040   FilterTest fixture; /* This is not how it should be done */
4041   GtkWidget *tree_view;
4042
4043   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4044   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4045   filter = gtk_tree_model_filter_new (sort_model, NULL);
4046   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4047   fixture.monitor = signal_monitor_new (filter);
4048
4049   tree_view = gtk_tree_view_new_with_model (filter);
4050
4051   /* We will filter on parent state using a filter function.  We will
4052    * manually keep the boolean column in sync, so that we can use
4053    * check_filter_model() to check the consistency of the model.
4054    */
4055   /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
4056    * to be able to check the structure here.  We keep the calls to
4057    * check_filter_model() commented out until then.
4058    */
4059   gtk_tree_model_filter_set_visible_func (fixture.filter,
4060                                           specific_has_child_filter_filter_func,
4061                                           NULL, NULL);
4062
4063   /* The first node will be initially invisible: no signals */
4064   gtk_tree_store_append (fixture.store, &root, NULL);
4065   create_tree_store_set_values (fixture.store, &root, FALSE);
4066
4067   /* check_filter_model (&fixture); */
4068   check_level_length (fixture.filter, NULL, 0);
4069   signal_monitor_assert_is_empty (fixture.monitor);
4070
4071   /* Insert a child node. This will cause the parent to become visible
4072    * since there is a child now.
4073    */
4074   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4075   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4076
4077   gtk_tree_store_append (fixture.store, &iter, &root);
4078   create_tree_store_set_values (fixture.store, &iter, TRUE);
4079
4080   /* Parent must now be visible.  Do the level length check first,
4081    * to avoid modifying the child model triggering a row-changed to
4082    * the filter model.
4083    */
4084   check_level_length (fixture.filter, NULL, 1);
4085   check_level_length (fixture.filter, "0", 0);
4086   signal_monitor_assert_is_empty (fixture.monitor);
4087
4088   /* This should propagate row-changed */
4089   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4090   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4091
4092   set_path_visibility (&fixture, "0", TRUE);
4093   /* check_filter_model (&fixture); */
4094   signal_monitor_assert_is_empty (fixture.monitor);
4095
4096   /* New root node, no child, so no signal */
4097   gtk_tree_store_append (fixture.store, &root, NULL);
4098   check_level_length (fixture.filter, NULL, 1);
4099   signal_monitor_assert_is_empty (fixture.monitor);
4100
4101   /* When the child comes in, this node will become visible */
4102   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4103   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4104   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4105   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4106
4107   gtk_tree_store_append (fixture.store, &iter, &root);
4108   check_level_length (fixture.filter, NULL, 2);
4109   check_level_length (fixture.filter, "1", 0);
4110
4111   create_tree_store_set_values (fixture.store, &root, TRUE);
4112   create_tree_store_set_values (fixture.store, &iter, TRUE);
4113
4114   /* check_filter_model (&fixture); */
4115   signal_monitor_assert_is_empty (fixture.monitor);
4116
4117   /* Add another child for 1 */
4118   gtk_tree_store_append (fixture.store, &iter, &root);
4119   create_tree_store_set_values (fixture.store, &iter, TRUE);
4120   check_level_length (fixture.filter, NULL, 2);
4121   check_level_length (fixture.filter, "0", 0);
4122   check_level_length (fixture.filter, "1", 0);
4123   signal_monitor_assert_is_empty (fixture.monitor);
4124
4125   /* Now remove one of the remaining child rows */
4126   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4127
4128   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4129                                        &iter, "0:0");
4130   gtk_tree_store_remove (fixture.store, &iter);
4131
4132   check_level_length (fixture.filter, NULL, 1);
4133   check_level_length (fixture.filter, "0", 0);
4134
4135   set_path_visibility (&fixture, "0", FALSE);
4136   /* check_filter_model (&fixture); */
4137   signal_monitor_assert_is_empty (fixture.monitor);
4138 }
4139
4140 static gboolean
4141 specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
4142                                                  GtkTreeIter  *iter,
4143                                                  gpointer      data)
4144 {
4145   return gtk_tree_model_iter_n_children (model, iter) >= 2;
4146 }
4147
4148 static void
4149 specific_at_least_2_children_filter (void)
4150 {
4151   GtkTreeModel *filter;
4152   GtkTreeIter iter, root;
4153   FilterTest fixture; /* This is not how it should be done */
4154   GtkWidget *tree_view;
4155
4156   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4157   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
4158   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4159   fixture.monitor = signal_monitor_new (filter);
4160
4161   tree_view = gtk_tree_view_new_with_model (filter);
4162
4163   gtk_tree_model_filter_set_visible_func (fixture.filter,
4164                                           specific_at_least_2_children_filter_filter_func,
4165                                           NULL, NULL);
4166
4167   /* The first node will be initially invisible: no signals */
4168   gtk_tree_store_append (fixture.store, &root, NULL);
4169   create_tree_store_set_values (fixture.store, &root, FALSE);
4170
4171   /* check_filter_model (&fixture); */
4172   check_level_length (fixture.filter, NULL, 0);
4173   signal_monitor_assert_is_empty (fixture.monitor);
4174
4175   /* Insert a child node.  Nothing should happen.
4176    */
4177   gtk_tree_store_append (fixture.store, &iter, &root);
4178   create_tree_store_set_values (fixture.store, &iter, TRUE);
4179
4180   check_level_length (fixture.filter, NULL, 0);
4181   signal_monitor_assert_is_empty (fixture.monitor);
4182
4183   /* Insert a second child node.  This will cause the parent to become
4184    * visible.
4185    */
4186   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4187   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4188
4189   gtk_tree_store_append (fixture.store, &iter, &root);
4190   create_tree_store_set_values (fixture.store, &iter, TRUE);
4191
4192   /* Parent must now be visible.  Do the level length check first,
4193    * to avoid modifying the child model triggering a row-changed to
4194    * the filter model.
4195    */
4196   check_level_length (fixture.filter, NULL, 1);
4197   check_level_length (fixture.filter, "0", 0);
4198   signal_monitor_assert_is_empty (fixture.monitor);
4199
4200   /* This should propagate row-changed */
4201   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4202   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4203
4204   set_path_visibility (&fixture, "0", TRUE);
4205   /* check_filter_model (&fixture); */
4206   signal_monitor_assert_is_empty (fixture.monitor);
4207
4208   /* New root node, no child, so no signal */
4209   gtk_tree_store_append (fixture.store, &root, NULL);
4210   check_level_length (fixture.filter, NULL, 1);
4211   signal_monitor_assert_is_empty (fixture.monitor);
4212
4213   /* First child, no signal, no change */
4214   gtk_tree_store_append (fixture.store, &iter, &root);
4215   check_level_length (fixture.filter, NULL, 1);
4216   signal_monitor_assert_is_empty (fixture.monitor);
4217
4218   /* When the second child comes in, this node will become visible */
4219   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
4220   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4221   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
4222   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
4223
4224   gtk_tree_store_append (fixture.store, &iter, &root);
4225   check_level_length (fixture.filter, NULL, 2);
4226   check_level_length (fixture.filter, "1", 0);
4227
4228   create_tree_store_set_values (fixture.store, &root, TRUE);
4229   create_tree_store_set_values (fixture.store, &iter, TRUE);
4230
4231   /* check_filter_model (&fixture); */
4232   signal_monitor_assert_is_empty (fixture.monitor);
4233
4234   /* Add another child for 1 */
4235   gtk_tree_store_append (fixture.store, &iter, &root);
4236   create_tree_store_set_values (fixture.store, &iter, TRUE);
4237   check_level_length (fixture.filter, NULL, 2);
4238   check_level_length (fixture.filter, "0", 0);
4239   check_level_length (fixture.filter, "1", 0);
4240   signal_monitor_assert_is_empty (fixture.monitor);
4241
4242   /* Now remove one of the remaining child rows */
4243   signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
4244
4245   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
4246                                        &iter, "0:0");
4247   gtk_tree_store_remove (fixture.store, &iter);
4248
4249   check_level_length (fixture.filter, NULL, 1);
4250   check_level_length (fixture.filter, "0", 0);
4251
4252   set_path_visibility (&fixture, "0", FALSE);
4253   /* check_filter_model (&fixture); */
4254   signal_monitor_assert_is_empty (fixture.monitor);
4255 }
4256
4257 static void
4258 specific_at_least_2_children_filter_on_sort_model (void)
4259 {
4260   GtkTreeModel *filter;
4261   GtkTreeModel *sort_model;
4262   GtkTreeIter iter, root;
4263   FilterTest fixture; /* This is not how it should be done */
4264   GtkWidget *tree_view;
4265
4266   fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
4267   sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
4268   filter = gtk_tree_model_filter_new (sort_model, NULL);
4269   fixture.filter = GTK_TREE_MODEL_FILTER (filter);
4270   fixture.monitor = signal_monitor_new (filter);
4271
4272   tree_view = gtk_tree_view_new_with_model (filter);
4273
4274   gtk_tree_model_filter_set_visible_func (fixture.filter,
4275                                           specific_at_least_2_children_filter_filter_func,
4276                                           NULL, NULL);
4277
4278   /* The first node will be initially invisible: no signals */
4279   gtk_tree_store_append (fixture.store, &root, NULL);
4280   create_tree_store_set_values (fixture.store, &root, FALSE);
4281
4282   /* check_filter_model (&fixture); */
4283   check_level_length (fixture.filter, NULL, 0);
4284   signal_monitor_assert_is_empty (fixture.monitor);
4285
4286   /* Insert a child node.  Nothing should happen.
4287    */
4288   gtk_tree_store_append (fixture.store, &iter, &root);
4289   create_tree_store_set_values (fixture.store, &iter, TRUE);
4290
4291   check_level_length (fixture.filter, NULL, 0);
4292   signal_monitor_assert_is_empty (fixture.monitor);
4293
4294     {
4295       GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
4296       GtkTreeRowReference *ref;
4297
4298       ref = gtk_tree_row_reference_new (sort_model, path);
4299       gtk_tree_path_free (path);
4300     }
4301
4302   /* Insert a second child node.  This will cause the parent to become
4303    * visible.
4304    */
4305   signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
4306   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4307
4308   gtk_tree_store_append (fixture.store, &iter, &root);
4309   create_tree_store_set_values (fixture.store, &iter, TRUE);
4310
4311   /* Parent must now be visible.  Do the level length check first,
4312    * to avoid modifying the child model triggering a row-changed to
4313    * the filter model.
4314    */
4315   check_level_length (fixture.filter, NULL, 1);
4316   check_level_length (fixture.filter, "0", 0);
4317   signal_monitor_assert_is_empty (fixture.monitor);
4318
4319   /* This should propagate row-changed */
4320   signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
4321   signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
4322
4323   set_path_visibility (&fixture, "0", TRUE);
4324   /* check_filter_model (&fixture); */
4325   signal_monitor_assert_is_empty (fixture.monitor);
4326
4327   /* New root node, no child, so no signal */
4328   gtk_tree_store_append (fixture.store, &root, NULL);
4329   check_level_length (fixture.filter, NULL, 1);
4330   signal_monitor_assert_is_empty (fixture.monitor);
4331 }
4332
4333
4334 static void
4335 specific_filter_add_child (void)
4336 {
4337   /* This test is based on one of the test cases I found in my
4338    * old test cases directory.  I unfortunately do not have a record
4339    * from who this test case originated.  -Kris.
4340    */
4341
4342   GtkTreeIter iter;
4343   GtkTreeIter iter_first;
4344   GtkTreeIter child;
4345   GtkTreeStore *store;
4346   GtkTreeModel *filter G_GNUC_UNUSED;
4347
4348   store = gtk_tree_store_new (1, G_TYPE_STRING);
4349
4350   gtk_tree_store_append (store, &iter_first, NULL);
4351   gtk_tree_store_set (store, &iter_first, 0, "Hello", -1);
4352
4353   gtk_tree_store_append (store, &iter, NULL);
4354   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4355
4356   gtk_tree_store_append (store, &iter, NULL);
4357   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4358
4359   gtk_tree_store_append (store, &iter, NULL);
4360   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4361
4362   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4363
4364   gtk_tree_store_set (store, &iter, 0, "Hello", -1);
4365   gtk_tree_store_append (store, &child, &iter_first);
4366   gtk_tree_store_set (store, &child, 0, "Hello", -1);
4367 }
4368
4369 static void
4370 specific_list_store_clear (void)
4371 {
4372   GtkTreeIter iter;
4373   GtkListStore *list;
4374   GtkTreeModel *filter;
4375   GtkWidget *view G_GNUC_UNUSED;
4376
4377   list = gtk_list_store_new (1, G_TYPE_INT);
4378   gtk_list_store_insert_with_values (list, &iter, 0, 0, 1, -1);
4379   gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
4380   gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
4381   gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
4382   gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
4383   gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
4384   gtk_list_store_insert_with_values (list, &iter, 6, 0, 7, -1);
4385   gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
4386
4387   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
4388   view = gtk_tree_view_new_with_model (filter);
4389
4390   gtk_list_store_clear (list);
4391 }
4392
4393 static void
4394 specific_sort_ref_leaf_and_remove_ancestor (void)
4395 {
4396   GtkTreeIter iter, child, child2, child3;
4397   GtkTreeStore *tree;
4398   GtkTreeModel *sort;
4399   GtkTreePath *path;
4400   GtkTreeRowReference *rowref;
4401   GtkWidget *view G_GNUC_UNUSED;
4402
4403   tree = gtk_tree_store_new (1, G_TYPE_INT);
4404   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4405   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4406   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4407   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4408
4409   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4410   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4411   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4412
4413   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4414   view = gtk_tree_view_new_with_model (sort);
4415   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4416
4417   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4418   rowref = gtk_tree_row_reference_new (sort, path);
4419   gtk_tree_path_free (path);
4420
4421   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4422   rowref = gtk_tree_row_reference_new (sort, path);
4423   gtk_tree_path_free (path);
4424
4425   path = gtk_tree_path_new_from_indices (3, 0, -1);
4426   rowref = gtk_tree_row_reference_new (sort, path);
4427   gtk_tree_path_free (path);
4428
4429   path = gtk_tree_path_new_from_indices (3, -1);
4430   rowref = gtk_tree_row_reference_new (sort, path);
4431   gtk_tree_path_free (path);
4432
4433   /* Deleting a parent */
4434   path = gtk_tree_path_new_from_indices (3, 0, -1);
4435   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4436   gtk_tree_store_remove (tree, &iter);
4437   gtk_tree_path_free (path);
4438
4439   gtk_tree_row_reference_free (rowref);
4440 }
4441
4442 static void
4443 specific_ref_leaf_and_remove_ancestor (void)
4444 {
4445   GtkTreeIter iter, child, child2, child3;
4446   GtkTreeStore *tree;
4447   GtkTreeModel *filter;
4448   GtkTreePath *path;
4449   GtkTreeRowReference *rowref;
4450   GtkWidget *view G_GNUC_UNUSED;
4451
4452   tree = gtk_tree_store_new (1, G_TYPE_INT);
4453   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4454   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4455   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4456   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4457
4458   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4459   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4460   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4461
4462   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
4463   view = gtk_tree_view_new_with_model (filter);
4464   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4465
4466   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4467   rowref = gtk_tree_row_reference_new (filter, path);
4468   gtk_tree_path_free (path);
4469
4470   path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
4471   rowref = gtk_tree_row_reference_new (filter, path);
4472   gtk_tree_path_free (path);
4473
4474   path = gtk_tree_path_new_from_indices (3, 0, -1);
4475   rowref = gtk_tree_row_reference_new (filter, path);
4476   gtk_tree_path_free (path);
4477
4478   path = gtk_tree_path_new_from_indices (3, -1);
4479   rowref = gtk_tree_row_reference_new (filter, path);
4480   gtk_tree_path_free (path);
4481
4482   /* Deleting a parent */
4483   path = gtk_tree_path_new_from_indices (3, 0, -1);
4484   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4485   gtk_tree_store_remove (tree, &iter);
4486   gtk_tree_path_free (path);
4487
4488   gtk_tree_row_reference_free (rowref);
4489 }
4490
4491 static void
4492 specific_virtual_ref_leaf_and_remove_ancestor (void)
4493 {
4494   GtkTreeIter iter, child, child2, child3;
4495   GtkTreeStore *tree;
4496   GtkTreeModel *filter;
4497   GtkTreePath *path;
4498   GtkTreeRowReference *rowref;
4499   GtkWidget *view G_GNUC_UNUSED;
4500
4501   tree = gtk_tree_store_new (1, G_TYPE_INT);
4502   gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
4503   gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
4504   gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
4505   gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
4506
4507   gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
4508   gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
4509   gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
4510
4511   /* Set a virtual root of 3:0 */
4512   path = gtk_tree_path_new_from_indices (3, 0, -1);
4513   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
4514   gtk_tree_path_free (path);
4515
4516   view = gtk_tree_view_new_with_model (filter);
4517   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
4518
4519   path = gtk_tree_path_new_from_indices (0, 0, -1);
4520   rowref = gtk_tree_row_reference_new (filter, path);
4521   gtk_tree_path_free (path);
4522
4523   path = gtk_tree_path_new_from_indices (0, 0, -1);
4524   rowref = gtk_tree_row_reference_new (filter, path);
4525   gtk_tree_path_free (path);
4526
4527   path = gtk_tree_path_new_from_indices (0, -1);
4528   rowref = gtk_tree_row_reference_new (filter, path);
4529   gtk_tree_path_free (path);
4530
4531   /* Deleting the virtual root */
4532   path = gtk_tree_path_new_from_indices (3, 0, -1);
4533   gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
4534   gtk_tree_store_remove (tree, &iter);
4535   gtk_tree_path_free (path);
4536
4537   gtk_tree_row_reference_free (rowref);
4538 }
4539
4540
4541 static int
4542 specific_bug_301558_sort_func (GtkTreeModel *model,
4543                                GtkTreeIter  *a,
4544                                GtkTreeIter  *b,
4545                                gpointer      data)
4546 {
4547   int i, j;
4548
4549   gtk_tree_model_get (model, a, 0, &i, -1);
4550   gtk_tree_model_get (model, b, 0, &j, -1);
4551
4552   return j - i;
4553 }
4554
4555 static void
4556 specific_bug_301558 (void)
4557 {
4558   /* Test case for GNOME Bugzilla bug 301558 provided by
4559    * Markku Vire.
4560    */
4561   GtkTreeStore *tree;
4562   GtkTreeModel *filter;
4563   GtkTreeModel *sort;
4564   GtkTreeIter root, iter, iter2;
4565   GtkWidget *view G_GNUC_UNUSED;
4566   int i;
4567   gboolean add;
4568
4569   g_test_bug ("301558");
4570
4571   tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
4572   gtk_tree_store_append (tree, &iter, NULL);
4573   gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
4574   gtk_tree_store_append (tree, &iter2, &iter);
4575   gtk_tree_store_set (tree, &iter2, 0, 73, 1, TRUE, -1);
4576
4577   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
4578   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
4579                                            specific_bug_301558_sort_func,
4580                                            NULL, NULL);
4581
4582   filter = gtk_tree_model_filter_new (sort, NULL);
4583   gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter), 1);
4584
4585   view = gtk_tree_view_new_with_model (filter);
4586
4587   while (gtk_events_pending ())
4588     gtk_main_iteration ();
4589
4590   add = TRUE;
4591
4592   for (i = 0; i < 10; i++)
4593     {
4594       if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tree), &root))
4595         g_assert_not_reached ();
4596
4597       if (add)
4598         {
4599           gtk_tree_store_append (tree, &iter, &root);
4600           gtk_tree_store_set (tree, &iter, 0, 456, 1, TRUE, -1);
4601         }
4602       else
4603         {
4604           int n;
4605           n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree), &root);
4606           gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (tree), &iter,
4607                                          &root, n - 1);
4608           gtk_tree_store_remove (tree, &iter);
4609         }
4610
4611       add = !add;
4612     }
4613 }
4614
4615
4616 static gboolean
4617 specific_bug_311955_filter_func (GtkTreeModel *model,
4618                                  GtkTreeIter  *iter,
4619                                  gpointer      data)
4620 {
4621   int value;
4622
4623   gtk_tree_model_get (model, iter, 0, &value, -1);
4624
4625   return (value != 0);
4626 }
4627
4628 static void
4629 specific_bug_311955 (void)
4630 {
4631   /* This is a test case for GNOME Bugzilla bug 311955.  It was written
4632    * by Markku Vire.
4633    */
4634   GtkTreeIter iter, child, root;
4635   GtkTreeStore *store;
4636   GtkTreeModel *sort;
4637   GtkTreeModel *filter;
4638
4639   GtkWidget *window G_GNUC_UNUSED;
4640   GtkWidget *tree_view;
4641   int i;
4642   int n;
4643   GtkTreePath *path;
4644
4645   g_test_bug ("311955");
4646
4647   store = gtk_tree_store_new (1, G_TYPE_INT);
4648
4649   gtk_tree_store_append (store, &root, NULL);
4650   gtk_tree_store_set (store, &root, 0, 33, -1);
4651
4652   gtk_tree_store_append (store, &iter, &root);
4653   gtk_tree_store_set (store, &iter, 0, 50, -1);
4654
4655   gtk_tree_store_append (store, &iter, NULL);
4656   gtk_tree_store_set (store, &iter, 0, 22, -1);
4657
4658   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4659   filter = gtk_tree_model_filter_new (sort, NULL);
4660
4661   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4662                                           specific_bug_311955_filter_func,
4663                                           NULL, NULL);
4664
4665   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
4666   tree_view = gtk_tree_view_new_with_model (filter);
4667   g_object_unref (store);
4668
4669   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4670
4671   while (gtk_events_pending ())
4672     gtk_main_iteration ();
4673
4674   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
4675   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4676
4677   /* Fill model */
4678   for (i = 0; i < 4; i++)
4679     {
4680       gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4681
4682       gtk_tree_store_append (store, &iter, &root);
4683
4684       if (i < 3)
4685         gtk_tree_store_set (store, &iter, 0, i, -1);
4686
4687       if (i % 2 == 0)
4688         {
4689           gtk_tree_store_append (store, &child, &iter);
4690           gtk_tree_store_set (store, &child, 0, 10, -1);
4691         }
4692     }
4693
4694   while (gtk_events_pending ())
4695     gtk_main_iteration ();
4696
4697   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4698   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
4699
4700   /* Remove bottommost child from the tree. */
4701   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
4702   n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
4703
4704   if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
4705     {
4706       if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
4707         gtk_tree_store_remove (store, &child);
4708     }
4709   else
4710     g_assert_not_reached ();
4711
4712   path = gtk_tree_path_new_from_indices (0, 2, -1);
4713   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4714   gtk_tree_path_free (path);
4715
4716   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4717   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4718 }
4719
4720 static void
4721 specific_bug_311955_clean (void)
4722 {
4723   /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
4724    * which is easier to understand.
4725    */
4726   GtkTreeIter iter, child, grandchild;
4727   GtkTreeStore *store;
4728   GtkTreeModel *sort;
4729   GtkTreeModel *filter;
4730
4731   GtkWidget *tree_view;
4732   GtkTreePath *path;
4733
4734   store = gtk_tree_store_new (1, G_TYPE_INT);
4735
4736   gtk_tree_store_append (store, &iter, NULL);
4737   gtk_tree_store_set (store, &iter, 0, 1, -1);
4738
4739   gtk_tree_store_append (store, &child, &iter);
4740   gtk_tree_store_set (store, &child, 0, 1, -1);
4741
4742   sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
4743   filter = gtk_tree_model_filter_new (sort, NULL);
4744
4745   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4746                                           specific_bug_311955_filter_func,
4747                                           NULL, NULL);
4748
4749   tree_view = gtk_tree_view_new_with_model (filter);
4750   g_object_unref (store);
4751
4752   gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
4753
4754   while (gtk_events_pending ())
4755     gtk_main_iteration ();
4756
4757   check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
4758   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
4759
4760   gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
4761
4762   gtk_tree_store_append (store, &child, &iter);
4763   gtk_tree_store_set (store, &child, 0, 0, -1);
4764
4765   gtk_tree_store_append (store, &child, &iter);
4766   gtk_tree_store_set (store, &child, 0, 1, -1);
4767
4768   gtk_tree_store_append (store, &child, &iter);
4769   gtk_tree_store_set (store, &child, 0, 1, -1);
4770
4771   gtk_tree_store_append (store, &grandchild, &child);
4772   gtk_tree_store_set (store, &grandchild, 0, 1, -1);
4773
4774   gtk_tree_store_append (store, &child, &iter);
4775   /* Don't set a value: assume 0 */
4776
4777   /* Remove leaf node, check trigger row-has-child-toggled */
4778   path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
4779   gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
4780   gtk_tree_path_free (path);
4781   gtk_tree_store_remove (store, &iter);
4782
4783   path = gtk_tree_path_new_from_indices (0, 2, -1);
4784   gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
4785   gtk_tree_path_free (path);
4786
4787   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
4788   check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
4789
4790   gtk_widget_destroy (tree_view);
4791 }
4792
4793 static void
4794 specific_bug_346800 (void)
4795 {
4796   /* This is a test case for GNOME Bugzilla bug 346800.  It was written
4797    * by Jonathan Matthew.
4798    */
4799
4800   GtkTreeIter node_iters[50];
4801   GtkTreeIter child_iters[50];
4802   GtkTreeModel *model;
4803   GtkTreeModelFilter *filter;
4804   GtkTreeStore *store;
4805   GType *columns;
4806   int i;
4807   int items = 50;
4808   columns = g_new (GType, 2);
4809   columns[0] = G_TYPE_STRING;
4810   columns[1] = G_TYPE_BOOLEAN;
4811   store = gtk_tree_store_newv (2, columns);
4812   model = GTK_TREE_MODEL (store);
4813
4814   g_test_bug ("346800");
4815
4816   filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
4817   gtk_tree_model_filter_set_visible_column (filter, 1);
4818
4819   for (i=0; i<items; i++)
4820     {
4821       /* allocate random amounts of junk, otherwise the filter model's arrays can expand without moving */
4822
4823       g_malloc (138);
4824       gtk_tree_store_append (store, &node_iters[i], NULL);
4825       gtk_tree_store_set (store, &node_iters[i],
4826                           0, "something",
4827                           1, ((i%6) == 0) ? FALSE : TRUE,
4828                           -1);
4829
4830       g_malloc (47);
4831       gtk_tree_store_append (store, &child_iters[i], &node_iters[i]);
4832       gtk_tree_store_set (store, &child_iters[i],
4833                           0, "something else",
4834                           1, FALSE,
4835                           -1);
4836       gtk_tree_model_filter_refilter (filter);
4837
4838       if (i > 6)
4839         {
4840           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-1], 1,
4841                               (i & 1) ? TRUE : FALSE, -1);
4842           gtk_tree_model_filter_refilter (filter);
4843
4844           gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
4845                               (i & 1) ? FALSE: TRUE, -1);
4846           gtk_tree_model_filter_refilter (filter);
4847         }
4848     }
4849 }
4850
4851 static gboolean
4852 specific_bug_464173_visible_func (GtkTreeModel *model,
4853                                   GtkTreeIter  *iter,
4854                                   gpointer      data)
4855 {
4856   gboolean *visible = (gboolean *)data;
4857
4858   return *visible;
4859 }
4860
4861 static void
4862 specific_bug_464173 (void)
4863 {
4864   /* Test case for GNOME Bugzilla bug 464173, test case written
4865    * by Andreas Koehler.
4866    */
4867   GtkTreeStore *model;
4868   GtkTreeModelFilter *f_model;
4869   GtkTreeIter iter1, iter2;
4870   GtkWidget *view G_GNUC_UNUSED;
4871   gboolean visible = TRUE;
4872
4873   g_test_bug ("464173");
4874
4875   model = gtk_tree_store_new (1, G_TYPE_STRING);
4876   gtk_tree_store_append (model, &iter1, NULL);
4877   gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
4878   gtk_tree_store_append (model, &iter2, &iter1);
4879   gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
4880
4881   f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
4882   gtk_tree_model_filter_set_visible_func (f_model,
4883                                           specific_bug_464173_visible_func,
4884                                           &visible, NULL);
4885
4886   view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
4887
4888   visible = FALSE;
4889   gtk_tree_model_filter_refilter (f_model);
4890 }
4891
4892
4893 static gboolean
4894 specific_bug_540201_filter_func (GtkTreeModel *model,
4895                                  GtkTreeIter  *iter,
4896                                  gpointer      data)
4897 {
4898   gboolean has_children;
4899
4900   has_children = gtk_tree_model_iter_has_child (model, iter);
4901
4902   return has_children;
4903 }
4904
4905 static void
4906 specific_bug_540201 (void)
4907 {
4908   /* Test case for GNOME Bugzilla bug 540201, steps provided by
4909    * Charles Day.
4910    */
4911   GtkTreeIter iter, root;
4912   GtkTreeStore *store;
4913   GtkTreeModel *filter;
4914
4915   GtkWidget *tree_view G_GNUC_UNUSED;
4916
4917   g_test_bug ("540201");
4918
4919   store = gtk_tree_store_new (1, G_TYPE_INT);
4920
4921   gtk_tree_store_append (store, &root, NULL);
4922   gtk_tree_store_set (store, &root, 0, 33, -1);
4923
4924   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4925   tree_view = gtk_tree_view_new_with_model (filter);
4926
4927   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
4928                                           specific_bug_540201_filter_func,
4929                                           NULL, NULL);
4930
4931   gtk_tree_store_append (store, &iter, &root);
4932   gtk_tree_store_set (store, &iter, 0, 50, -1);
4933
4934   gtk_tree_store_append (store, &iter, &root);
4935   gtk_tree_store_set (store, &iter, 0, 22, -1);
4936
4937
4938   gtk_tree_store_append (store, &root, NULL);
4939   gtk_tree_store_set (store, &root, 0, 33, -1);
4940
4941   gtk_tree_store_append (store, &iter, &root);
4942   gtk_tree_store_set (store, &iter, 0, 22, -1);
4943 }
4944
4945
4946 static gboolean
4947 specific_bug_549287_visible_func (GtkTreeModel *model,
4948                                   GtkTreeIter  *iter,
4949                                   gpointer      data)
4950 {
4951   gboolean result = FALSE;
4952
4953   result = gtk_tree_model_iter_has_child (model, iter);
4954
4955   return result;
4956 }
4957
4958 static void
4959 specific_bug_549287 (void)
4960 {
4961   /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
4962
4963   int i;
4964   GtkTreeStore *store;
4965   GtkTreeModel *filtered;
4966   GtkWidget *view G_GNUC_UNUSED;
4967   GtkTreeIter iter;
4968   GtkTreeIter *swap, *parent, *child;
4969
4970   g_test_bug ("529287");
4971
4972   store = gtk_tree_store_new (1, G_TYPE_STRING);
4973   filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
4974   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
4975                                           specific_bug_549287_visible_func,
4976                                           NULL, NULL);
4977
4978   view = gtk_tree_view_new_with_model (filtered);
4979
4980   for (i = 0; i < 4; i++)
4981     {
4982       if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
4983         {
4984           parent = gtk_tree_iter_copy (&iter);
4985           child = gtk_tree_iter_copy (&iter);
4986
4987           while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
4988                                                 child, parent, 0))
4989             {
4990
4991               swap = parent;
4992               parent = child;
4993               child = swap;
4994             }
4995
4996           gtk_tree_store_append (store, child, parent);
4997           gtk_tree_store_set (store, child,
4998                               0, "Something",
4999                               -1);
5000
5001           gtk_tree_iter_free (parent);
5002           gtk_tree_iter_free (child);
5003         }
5004       else
5005         {
5006           gtk_tree_store_append (store, &iter, NULL);
5007           gtk_tree_store_set (store, &iter,
5008                               0, "Something",
5009                               -1);
5010         }
5011
5012       /* since we inserted something, we changed the visibility conditions: */
5013       gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
5014     }
5015 }
5016
5017 static gboolean
5018 specific_bug_621076_visible_func (GtkTreeModel *model,
5019                                   GtkTreeIter  *iter,
5020                                   gpointer      data)
5021 {
5022   gboolean visible = FALSE;
5023   gchar *str = NULL;
5024
5025   gtk_tree_model_get (model, iter, 0, &str, -1);
5026   if (str != NULL && g_str_has_prefix (str, "visible"))
5027     {
5028       visible = TRUE;
5029     }
5030   else
5031     {
5032       GtkTreeIter child_iter;
5033       gboolean valid;
5034
5035       /* Recursively check if we have a visible child */
5036       for (valid = gtk_tree_model_iter_children (model, &child_iter, iter);
5037            valid; valid = gtk_tree_model_iter_next (model, &child_iter))
5038         {
5039           if (specific_bug_621076_visible_func (model, &child_iter, data))
5040             {
5041               visible = TRUE;
5042               break;
5043             }
5044         }
5045     }
5046
5047   if (str)
5048     g_free (str);
5049
5050   return visible;
5051 }
5052
5053 static void
5054 specific_bug_621076 (void)
5055 {
5056   /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
5057
5058   /* This test case differs from has-child-filter and root-has-child-filter
5059    * in that the visible function both filters on content and model
5060    * structure.  Also, it is recursive.
5061    */
5062
5063   GtkTreeStore *store;
5064   GtkTreeModel *filter;
5065   GtkWidget *view;
5066   GtkTreeIter group_iter;
5067   GtkTreeIter item_iter;
5068   SignalMonitor *monitor;
5069
5070   g_test_bug ("621076");
5071
5072   store = gtk_tree_store_new (1, G_TYPE_STRING);
5073   filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
5074   gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
5075                                           specific_bug_621076_visible_func,
5076                                           NULL, NULL);
5077
5078   view = gtk_tree_view_new_with_model (filter);
5079   g_object_ref_sink (view);
5080
5081   monitor = signal_monitor_new (filter);
5082
5083   signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
5084   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5085                                      0, "visible-group-0",
5086                                      -1);
5087   signal_monitor_assert_is_empty (monitor);
5088
5089   /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
5090    * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
5091    * visible-group-0 to tell the view that row can be expanded. */
5092   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5093   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
5094   group_iter = item_iter;
5095   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5096                                      0, "visible-0:0",
5097                                      -1);
5098   signal_monitor_assert_is_empty (monitor);
5099
5100   signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
5101   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5102                                      0, "visible-group-1",
5103                                      -1);
5104   signal_monitor_assert_is_empty (monitor);
5105
5106   /* We are adding an hidden item inside visible-group-1, so
5107    * ROW_HAS_CHILD_TOGGLED should not be emitted.  It is emitted though,
5108    * because the signal originating at TreeStore will be propagated,
5109    * as well a generated signal because the state of the parent *could*
5110    * change by a change in the model.
5111    */
5112   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5113   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5114   group_iter = item_iter;
5115   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5116                                      0, "group-1:0",
5117                                      -1);
5118   signal_monitor_assert_is_empty (monitor);
5119
5120   /* This group is invisible and its parent too. Nothing should be emitted */
5121   group_iter = item_iter;
5122   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5123                                      0, "group-1:0:0",
5124                                      -1);
5125   signal_monitor_assert_is_empty (monitor);
5126
5127   /* Adding a visible item in this group hierarchy will make all nodes
5128    * in this path visible.  The first level should simply tell the view
5129    * that it now has a child, and the view will load the tree if needed
5130    * (depends on the expanded state).
5131    */
5132   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5133   group_iter = item_iter;
5134   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5135                                      0, "visible-1:0:0:0",
5136                                      -1);
5137   signal_monitor_assert_is_empty (monitor);
5138
5139   check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
5140
5141   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5142                                      0, "group-2",
5143                                      -1);
5144   signal_monitor_assert_is_empty (monitor);
5145
5146   /* Parent is invisible, and adding this invisible item won't change that,
5147    * so no signal should be emitted. */
5148   group_iter = item_iter;
5149   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5150                                      0, "invisible-2:0",
5151                                      -1);
5152   signal_monitor_assert_is_empty (monitor);
5153
5154   /* This makes group-2 visible, so it gets inserted and tells it has
5155    * children.
5156    */
5157   signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
5158   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5159   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5160                                      0, "visible-2:1",
5161                                      -1);
5162   signal_monitor_assert_is_empty (monitor);
5163
5164   /* group-2 is already visible, so this time it is a normal insertion */
5165   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5166                                      0, "visible-2:2",
5167                                      -1);
5168   signal_monitor_assert_is_empty (monitor);
5169
5170
5171   gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
5172                                      0, "group-3",
5173                                      -1);
5174   signal_monitor_assert_is_empty (monitor);
5175
5176   /* Parent is invisible, and adding this invisible item won't change that,
5177    * so no signal should be emitted. */
5178   group_iter = item_iter;
5179   gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
5180                                      0, "invisible-3:0",
5181                                      -1);
5182   signal_monitor_assert_is_empty (monitor);
5183
5184   gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
5185                                      0, "invisible-3:1",
5186                                      -1);
5187   signal_monitor_assert_is_empty (monitor);
5188
5189   /* This will make group 3 visible. */
5190   signal_monitor_append_signal (monitor, ROW_INSERTED, "3");
5191   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5192   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3");
5193   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5194   signal_monitor_assert_is_empty (monitor);
5195
5196   /* Make sure all groups are expanded, so the filter has the tree cached */
5197   gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5198   while (gtk_events_pending ())
5199     gtk_main_iteration ();
5200
5201   /* Should only yield a row-changed */
5202   signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0");
5203   gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1);
5204   signal_monitor_assert_is_empty (monitor);
5205
5206   /* Now remove/hide some items. If a group loses its last item, the group
5207    * should be deleted instead of the item.
5208    */
5209
5210   signal_monitor_append_signal (monitor, ROW_DELETED, "2:1");
5211   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2");
5212   gtk_tree_store_remove (store, &item_iter);
5213   signal_monitor_assert_is_empty (monitor);
5214
5215   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5216   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5217   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5218   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1");
5219   gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1);
5220   signal_monitor_assert_is_empty (monitor);
5221
5222   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0");
5223   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0");
5224   signal_monitor_append_signal (monitor, ROW_DELETED, "1:0");
5225   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
5226   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0");
5227   gtk_tree_store_remove (store, &item_iter);
5228   signal_monitor_assert_is_empty (monitor);
5229
5230   /* Hide a group using row-changed instead of row-deleted */
5231   /* Caution: group 2 is gone, so offsets of the signals have moved. */
5232   signal_monitor_append_signal (monitor, ROW_DELETED, "2:0");
5233   signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
5234   signal_monitor_append_signal (monitor, ROW_DELETED, "2");
5235   gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter,
5236                                        "3:1");
5237   gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1);
5238   signal_monitor_assert_is_empty (monitor);
5239
5240 #if 0
5241   {
5242     GtkWidget *window;
5243     GtkTreeViewColumn *col;
5244
5245     gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
5246
5247     col = gtk_tree_view_column_new_with_attributes ("foo",
5248         gtk_cell_renderer_text_new (),
5249         "text", 0, NULL);
5250     gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
5251
5252     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
5253     g_signal_connect (window, "delete-event",
5254         G_CALLBACK (gtk_widget_destroy), NULL);
5255     g_signal_connect (window, "destroy",
5256         G_CALLBACK (gtk_main_quit), NULL);
5257
5258     gtk_container_add (GTK_CONTAINER (window), view);
5259
5260     gtk_widget_show (view);
5261     gtk_widget_show (window);
5262
5263     gtk_main ();
5264   }
5265 #endif
5266
5267   /* Cleanup */
5268   signal_monitor_free (monitor);
5269   g_object_unref (view);
5270   g_object_unref (store);
5271   g_object_unref (filter);
5272 }
5273
5274 /* main */
5275
5276 void
5277 register_filter_model_tests (void)
5278 {
5279   g_test_add ("/TreeModelFilter/self/verify-test-suite",
5280               FilterTest, NULL,
5281               filter_test_setup,
5282               verify_test_suite,
5283               filter_test_teardown);
5284
5285   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
5286               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5287               filter_test_setup,
5288               verify_test_suite_vroot,
5289               filter_test_teardown);
5290   g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
5291               FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
5292               filter_test_setup,
5293               verify_test_suite_vroot,
5294               filter_test_teardown);
5295
5296
5297   g_test_add ("/TreeModelFilter/filled/hide-root-level",
5298               FilterTest, NULL,
5299               filter_test_setup,
5300               filled_hide_root_level,
5301               filter_test_teardown);
5302   g_test_add ("/TreeModelFilter/filled/hide-child-levels",
5303               FilterTest, NULL,
5304               filter_test_setup,
5305               filled_hide_child_levels,
5306               filter_test_teardown);
5307   g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
5308               FilterTest, NULL,
5309               filter_test_setup,
5310               filled_hide_child_levels_root_expanded,
5311               filter_test_teardown);
5312
5313   g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
5314               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5315               filter_test_setup,
5316               filled_vroot_hide_root_level,
5317               filter_test_teardown);
5318   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
5319               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5320               filter_test_setup,
5321               filled_vroot_hide_child_levels,
5322               filter_test_teardown);
5323   g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
5324               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5325               filter_test_setup,
5326               filled_vroot_hide_child_levels_root_expanded,
5327               filter_test_teardown);
5328
5329
5330   g_test_add ("/TreeModelFilter/empty/show-nodes",
5331               FilterTest, NULL,
5332               filter_test_setup_empty,
5333               empty_show_nodes,
5334               filter_test_teardown);
5335   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
5336               FilterTest, NULL,
5337               filter_test_setup_empty,
5338               empty_show_multiple_nodes,
5339               filter_test_teardown);
5340
5341   g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
5342               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5343               filter_test_setup_empty,
5344               empty_vroot_show_nodes,
5345               filter_test_teardown);
5346   g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
5347               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5348               filter_test_setup_empty,
5349               empty_vroot_show_multiple_nodes,
5350               filter_test_teardown);
5351
5352
5353   g_test_add ("/TreeModelFilter/unfiltered/hide-single",
5354               FilterTest, NULL,
5355               filter_test_setup_unfiltered,
5356               unfiltered_hide_single,
5357               filter_test_teardown);
5358   g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
5359               FilterTest, NULL,
5360               filter_test_setup_unfiltered_root_expanded,
5361               unfiltered_hide_single_root_expanded,
5362               filter_test_teardown);
5363   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
5364               FilterTest, NULL,
5365               filter_test_setup_unfiltered,
5366               unfiltered_hide_single_child,
5367               filter_test_teardown);
5368   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
5369               FilterTest, NULL,
5370               filter_test_setup_unfiltered_root_expanded,
5371               unfiltered_hide_single_child_root_expanded,
5372               filter_test_teardown);
5373   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
5374               FilterTest, NULL,
5375               filter_test_setup_unfiltered,
5376               unfiltered_hide_single_multi_level,
5377               filter_test_teardown);
5378   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
5379               FilterTest, NULL,
5380               filter_test_setup_unfiltered_root_expanded,
5381               unfiltered_hide_single_multi_level_root_expanded,
5382               filter_test_teardown);
5383
5384   g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
5385               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5386               filter_test_setup_unfiltered,
5387               unfiltered_vroot_hide_single,
5388               filter_test_teardown);
5389   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
5390               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5391               filter_test_setup_unfiltered,
5392               unfiltered_vroot_hide_single_child,
5393               filter_test_teardown);
5394   g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
5395               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5396               filter_test_setup_unfiltered_root_expanded,
5397               unfiltered_vroot_hide_single_child_root_expanded,
5398               filter_test_teardown);
5399   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
5400               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5401               filter_test_setup_unfiltered,
5402               unfiltered_vroot_hide_single_multi_level,
5403               filter_test_teardown);
5404   g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
5405               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5406               filter_test_setup_unfiltered_root_expanded,
5407               unfiltered_vroot_hide_single_multi_level_root_expanded,
5408               filter_test_teardown);
5409
5410
5411
5412   g_test_add ("/TreeModelFilter/unfiltered/show-single",
5413               FilterTest, NULL,
5414               filter_test_setup_empty_unfiltered,
5415               unfiltered_show_single,
5416               filter_test_teardown);
5417   g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
5418               FilterTest, NULL,
5419               filter_test_setup_empty_unfiltered,
5420               unfiltered_show_single_child,
5421               filter_test_teardown);
5422   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
5423               FilterTest, NULL,
5424               filter_test_setup_empty_unfiltered_root_expanded,
5425               unfiltered_show_single_child_root_expanded,
5426               filter_test_teardown);
5427   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
5428               FilterTest, NULL,
5429               filter_test_setup_empty_unfiltered,
5430               unfiltered_show_single_multi_level,
5431               filter_test_teardown);
5432   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
5433               FilterTest, NULL,
5434               filter_test_setup_empty_unfiltered_root_expanded,
5435               unfiltered_show_single_multi_level_root_expanded,
5436               filter_test_teardown);
5437
5438   g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
5439               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5440               filter_test_setup_empty_unfiltered,
5441               unfiltered_vroot_show_single,
5442               filter_test_teardown);
5443   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
5444               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5445               filter_test_setup_empty_unfiltered,
5446               unfiltered_vroot_show_single_child,
5447               filter_test_teardown);
5448   g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
5449               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5450               filter_test_setup_empty_unfiltered_root_expanded,
5451               unfiltered_vroot_show_single_child_root_expanded,
5452               filter_test_teardown);
5453   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
5454               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5455               filter_test_setup_empty_unfiltered,
5456               unfiltered_vroot_show_single_multi_level,
5457               filter_test_teardown);
5458   g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
5459               FilterTest, gtk_tree_path_new_from_indices (2, -1),
5460               filter_test_setup_empty_unfiltered_root_expanded,
5461               unfiltered_vroot_show_single_multi_level_root_expanded,
5462               filter_test_teardown);
5463
5464
5465   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
5466               FilterTest, NULL,
5467               filter_test_setup_unfiltered,
5468               unfiltered_rows_reordered_root_level,
5469               filter_test_teardown);
5470   g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
5471               FilterTest, NULL,
5472               filter_test_setup_unfiltered,
5473               unfiltered_rows_reordered_child_level,
5474               filter_test_teardown);
5475
5476   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
5477               FilterTest, NULL,
5478               filter_test_setup,
5479               filtered_rows_reordered_root_level_first_hidden,
5480               filter_test_teardown);
5481   g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
5482               FilterTest, NULL,
5483               filter_test_setup,
5484               filtered_rows_reordered_root_level_middle_hidden,
5485               filter_test_teardown);
5486   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
5487               FilterTest, NULL,
5488               filter_test_setup,
5489               filtered_rows_reordered_child_level_first_hidden,
5490               filter_test_teardown);
5491   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
5492               FilterTest, NULL,
5493               filter_test_setup,
5494               filtered_rows_reordered_child_level_middle_hidden,
5495               filter_test_teardown);
5496   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
5497               FilterTest, NULL,
5498               filter_test_setup,
5499               filtered_rows_reordered_child_level_4_hidden,
5500               filter_test_teardown);
5501   g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
5502               FilterTest, NULL,
5503               filter_test_setup,
5504               filtered_rows_reordered_child_level_all_hidden,
5505               filter_test_teardown);
5506
5507   /* Inserts in child models after creation of filter model */
5508   g_test_add_func ("/TreeModelFilter/insert/before",
5509                    insert_before);
5510   g_test_add_func ("/TreeModelFilter/insert/child",
5511                    insert_child);
5512
5513   /* Removals from child model after creating of filter model */
5514   g_test_add_func ("/TreeModelFilter/remove/node",
5515                    remove_node);
5516   g_test_add_func ("/TreeModelFilter/remove/node-vroot",
5517                    remove_node_vroot);
5518   g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
5519                    remove_vroot_ancestor);
5520
5521   /* Reference counting */
5522   g_test_add_func ("/TreeModelFilter/ref-count/single-level",
5523                    ref_count_single_level);
5524   g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
5525                    ref_count_two_levels);
5526   g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
5527                    ref_count_three_levels);
5528   g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
5529                    ref_count_delete_row);
5530   g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
5531                    ref_count_cleanup);
5532   g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
5533                    ref_count_row_ref);
5534
5535   g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
5536                    specific_path_dependent_filter);
5537   g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
5538                    specific_append_after_collapse);
5539   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
5540                    specific_sort_filter_remove_node);
5541   g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
5542                    specific_sort_filter_remove_root);
5543   g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
5544                    specific_root_mixed_visibility);
5545   g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
5546                    specific_has_child_filter);
5547   g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
5548                    specific_has_child_filter_on_sort_model);
5549   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
5550                    specific_at_least_2_children_filter);
5551   g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
5552                    specific_at_least_2_children_filter_on_sort_model);
5553   g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
5554                    specific_root_has_child_filter);
5555   g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
5556                    specific_filter_add_child);
5557   g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
5558                    specific_list_store_clear);
5559   g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
5560                    specific_sort_ref_leaf_and_remove_ancestor);
5561   g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
5562                    specific_ref_leaf_and_remove_ancestor);
5563   g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
5564                    specific_virtual_ref_leaf_and_remove_ancestor);
5565
5566   g_test_add_func ("/TreeModelFilter/specific/bug-301558",
5567                    specific_bug_301558);
5568   g_test_add_func ("/TreeModelFilter/specific/bug-311955",
5569                    specific_bug_311955);
5570   g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
5571                    specific_bug_311955_clean);
5572   g_test_add_func ("/TreeModelFilter/specific/bug-346800",
5573                    specific_bug_346800);
5574   g_test_add_func ("/TreeModelFilter/specific/bug-464173",
5575                    specific_bug_464173);
5576   g_test_add_func ("/TreeModelFilter/specific/bug-540201",
5577                    specific_bug_540201);
5578   g_test_add_func ("/TreeModelFilter/specific/bug-549287",
5579                    specific_bug_549287);
5580   g_test_add_func ("/TreeModelFilter/specific/bug-621076",
5581                    specific_bug_621076);
5582 }