From 22adfc67e532795da7b12a8402922108ccb9bd2c Mon Sep 17 00:00:00 2001 From: Xavier Claessens Date: Fri, 20 May 2011 20:25:24 +0200 Subject: [PATCH] Add thorough unit test for bug #621076 Minor edits and additions by Kristian Rietveld. --- gtk/tests/filtermodel.c | 259 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c index 946ec717b7..667572976c 100644 --- a/gtk/tests/filtermodel.c +++ b/gtk/tests/filtermodel.c @@ -3250,6 +3250,263 @@ specific_bug_549287 (void) } } +static gboolean +specific_bug_621076_visible_func (GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + gboolean visible = FALSE; + gchar *str; + + gtk_tree_model_get (model, iter, 0, &str, -1); + if (str != NULL && g_str_has_prefix (str, "visible")) + { + visible = TRUE; + } + else + { + GtkTreeIter child_iter; + gboolean valid; + + /* Recursively check if we have a visible child */ + for (valid = gtk_tree_model_iter_children (model, &child_iter, iter); + valid; valid = gtk_tree_model_iter_next (model, &child_iter)) + { + gtk_tree_model_get (model, &child_iter, 0, &str, -1); + if (specific_bug_621076_visible_func (model, &child_iter, data)) + { + visible = TRUE; + break; + } + } + } + + return visible; +} + +static void +specific_bug_621076 (void) +{ + /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */ + + /* This test case differs from has-child-filter and root-has-child-filter + * in that the visible function both filters on content and model + * structure. Also, it is recursive. + */ + + GtkTreeStore *store; + GtkTreeModel *filter; + GtkWidget *view; + GtkTreeIter group_iter; + GtkTreeIter item_iter; + SignalMonitor *monitor; + + g_test_bug ("621076"); + + store = gtk_tree_store_new (1, G_TYPE_STRING); + filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter), + specific_bug_621076_visible_func, + NULL, NULL); + + view = gtk_tree_view_new_with_model (filter); + g_object_ref_sink (view); + + monitor = signal_monitor_new (filter); + + signal_monitor_append_signal (monitor, ROW_INSERTED, "0"); + gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1, + 0, "visible-group-0", + -1); + signal_monitor_assert_is_empty (monitor); + + /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted + * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on + * visible-group-0 to tell the view that row can be expanded. */ + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0"); + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1, + 0, "visible-0:0", + -1); + signal_monitor_assert_is_empty (monitor); + + signal_monitor_append_signal (monitor, ROW_INSERTED, "1"); + gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1, + 0, "visible-group-1", + -1); + signal_monitor_assert_is_empty (monitor); + + /* We are adding an hidden item inside visible-group-1, so + * ROW_HAS_CHILD_TOGGLED should not be emitted. It is emitted though, + * because the signal originating at TreeStore will be propagated, + * as well a generated signal because the state of the parent *could* + * change by a change in the model. + */ + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1"); + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1, + 0, "group-1:0", + -1); + signal_monitor_assert_is_empty (monitor); + + /* This group is invisible and its parent too. Nothing should be emitted */ + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1, + 0, "group-1:0:0", + -1); + signal_monitor_assert_is_empty (monitor); + + /* Adding a visible item in this group hierarchy will make all nodes + * in this path visible. The first level should simply tell the view + * that it now has a child, and the view will load the tree if needed + * (depends on the expanded state). + */ + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1"); + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1, + 0, "visible-1:0:0:0", + -1); + signal_monitor_assert_is_empty (monitor); + + check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1); + + gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1, + 0, "group-2", + -1); + signal_monitor_assert_is_empty (monitor); + + /* Parent is invisible, and adding this invisible item won't change that, + * so no signal should be emitted. */ + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1, + 0, "invisible-2:0", + -1); + signal_monitor_assert_is_empty (monitor); + + /* This makes group-2 visible, so it gets inserted and tells it has + * children. + */ + signal_monitor_append_signal (monitor, ROW_INSERTED, "2"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2"); + gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1, + 0, "visible-2:1", + -1); + signal_monitor_assert_is_empty (monitor); + + /* group-2 is already visible, so this time it is a normal insertion */ + signal_monitor_append_signal (monitor, ROW_INSERTED, "2:1"); + gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1, + 0, "visible-2:2", + -1); + signal_monitor_assert_is_empty (monitor); + + + gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1, + 0, "group-3", + -1); + signal_monitor_assert_is_empty (monitor); + + /* Parent is invisible, and adding this invisible item won't change that, + * so no signal should be emitted. */ + group_iter = item_iter; + gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1, + 0, "invisible-3:0", + -1); + signal_monitor_assert_is_empty (monitor); + + gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1, + 0, "invisible-3:1", + -1); + signal_monitor_assert_is_empty (monitor); + + /* This will make group 3 visible. */ + signal_monitor_append_signal (monitor, ROW_INSERTED, "3"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3"); + signal_monitor_append_signal (monitor, ROW_INSERTED, "3:0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "3"); + gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1); + signal_monitor_assert_is_empty (monitor); + + /* Make sure all groups are expanded, so the filter has the tree cached */ + gtk_tree_view_expand_all (GTK_TREE_VIEW (view)); + while (gtk_events_pending ()) + gtk_main_iteration (); + + /* Should only yield a row-changed */ + signal_monitor_append_signal (monitor, ROW_CHANGED, "3:0"); + gtk_tree_store_set (store, &item_iter, 0, "visible-3:1", -1); + signal_monitor_assert_is_empty (monitor); + + /* Now remove/hide some items. If a group loses its last item, the group + * should be deleted instead of the item. + */ + + signal_monitor_append_signal (monitor, ROW_DELETED, "2:1"); + gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:2"); + gtk_tree_store_remove (store, &item_iter); + signal_monitor_assert_is_empty (monitor); + + signal_monitor_append_signal (monitor, ROW_DELETED, "2:0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2"); + signal_monitor_append_signal (monitor, ROW_DELETED, "2"); + gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "2:1"); + gtk_tree_store_set (store, &item_iter, 0, "invisible-2:1", -1); + signal_monitor_assert_is_empty (monitor); + + signal_monitor_append_signal (monitor, ROW_DELETED, "1:0:0:0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1:0:0"); + signal_monitor_append_signal (monitor, ROW_DELETED, "1:0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1"); + gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, "1:0:0:0"); + gtk_tree_store_remove (store, &item_iter); + signal_monitor_assert_is_empty (monitor); + + /* Hide a group using row-changed instead of row-deleted */ + /* Caution: group 2 is gone, so offsets of the signals have moved. */ + signal_monitor_append_signal (monitor, ROW_DELETED, "2:0"); + signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2"); + signal_monitor_append_signal (monitor, ROW_DELETED, "2"); + gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &item_iter, + "3:1"); + gtk_tree_store_set (store, &item_iter, 0, "invisible-3:1", -1); + signal_monitor_assert_is_empty (monitor); + +#if 0 + { + GtkWidget *window; + GtkTreeViewColumn *col; + + gtk_tree_view_expand_all (GTK_TREE_VIEW (view)); + + col = gtk_tree_view_column_new_with_attributes ("foo", + gtk_cell_renderer_text_new (), + "text", 0, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (view), col); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_widget_destroy), NULL); + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + gtk_container_add (GTK_CONTAINER (window), view); + + gtk_widget_show (view); + gtk_widget_show (window); + + gtk_main (); + } +#endif + + /* Cleanup */ + signal_monitor_free (monitor); + g_object_unref (view); + g_object_unref (store); + g_object_unref (filter); +} + /* main */ void @@ -3437,4 +3694,6 @@ register_filter_model_tests (void) specific_bug_540201); g_test_add_func ("/TreeModelFilter/specific/bug-549287", specific_bug_549287); + g_test_add_func ("/TreeModelFilter/specific/bug-621076", + specific_bug_621076); }