summaryrefslogtreecommitdiff
path: root/gtk/tests
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/tests')
-rw-r--r--gtk/tests/Makefile.am25
-rw-r--r--gtk/tests/action.c1
-rw-r--r--gtk/tests/filtermodel.c3424
-rw-r--r--gtk/tests/gtktreemodelrefcount.c286
-rw-r--r--gtk/tests/gtktreemodelrefcount.h134
-rw-r--r--gtk/tests/liststore.c85
-rw-r--r--gtk/tests/modelrefcount.c978
-rw-r--r--gtk/tests/sortmodel.c1151
-rw-r--r--gtk/tests/treemodel.c347
-rw-r--r--gtk/tests/treemodel.h60
-rw-r--r--gtk/tests/treestore.c117
11 files changed, 6025 insertions, 583 deletions
diff --git a/gtk/tests/Makefile.am b/gtk/tests/Makefile.am
index ff5720d68e..4b2d3440ef 100644
--- a/gtk/tests/Makefile.am
+++ b/gtk/tests/Makefile.am
@@ -27,13 +27,18 @@ TEST_PROGS += testing
testing_SOURCES = testing.c
testing_LDADD = $(progs_ldadd)
-TEST_PROGS += liststore
-liststore_SOURCES = liststore.c
-liststore_LDADD = $(progs_ldadd)
-
-TEST_PROGS += treestore
-treestore_SOURCES = treestore.c
-treestore_LDADD = $(progs_ldadd)
+TEST_PROGS += treemodel
+treemodel_SOURCES = \
+ treemodel.h \
+ treemodel.c \
+ liststore.c \
+ treestore.c \
+ filtermodel.c \
+ sortmodel.c \
+ modelrefcount.c \
+ gtktreemodelrefcount.h \
+ gtktreemodelrefcount.c
+treemodel_LDADD = $(progs_ldadd)
TEST_PROGS += treeview
treeview_SOURCES = treeview.c
@@ -41,7 +46,7 @@ treeview_LDADD = $(progs_ldadd)
TEST_PROGS += treeview-scrolling
treeview_scrolling_SOURCES = treeview-scrolling.c
-treeview_scrolling_LDADD = $(progs_ldadd)
+treeview_scrolling_LDADD = $(progs_ldadd) -lm
TEST_PROGS += recentmanager
recentmanager_SOURCES = recentmanager.c
@@ -86,10 +91,6 @@ TEST_PROGS += textiter
textiter_SOURCES = textiter.c
textiter_LDADD = $(progs_ldadd)
-TEST_PROGS += filtermodel
-filtermodel_SOURCES = filtermodel.c
-filtermodel_LDADD = $(progs_ldadd)
-
TEST_PROGS += expander
expander_SOURCES = expander.c
expander_LDADD = $(progs_ldadd)
diff --git a/gtk/tests/action.c b/gtk/tests/action.c
index dffb5b18fe..6617d9521a 100644
--- a/gtk/tests/action.c
+++ b/gtk/tests/action.c
@@ -57,6 +57,7 @@ menu_item_label_notify_count (ActionTest *fixture,
GtkWidget *item = gtk_menu_item_new ();
unsigned int emmisions = 0;
+ g_object_ref_sink (item);
g_signal_connect (item, "notify::label",
G_CALLBACK (notify_count_emmisions), &emmisions);
diff --git a/gtk/tests/filtermodel.c b/gtk/tests/filtermodel.c
index 91daaf9f12..a0c11a8994 100644
--- a/gtk/tests/filtermodel.c
+++ b/gtk/tests/filtermodel.c
@@ -1,5 +1,5 @@
/* Extensive GtkTreeModelFilter tests.
- * Copyright (C) 2009 Kristian Rietveld <kris@gtk.org>
+ * Copyright (C) 2009,2011 Kristian Rietveld <kris@gtk.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,15 +19,23 @@
#include <gtk/gtk.h>
+#include "treemodel.h"
+#include "gtktreemodelrefcount.h"
/* Left to do:
* - Proper coverage checking to see if the unit tests cover
* all possible cases.
- * - Verify if the ref counting is done properly for both the
- * normal ref_count and the zero_ref_count. One way to test
- * this area is by collapsing/expanding branches on the view
- * that is connected to the filter model.
* - Check if the iterator stamp is incremented at the correct times.
+ *
+ * For more thorough testing:
+ * - Test with randomized models.
+ * - Extensively test a filter model wrapping a sort model,
+ * or a sort model wrapping a filter model by:
+ * # Checking structure.
+ * # Checking for correct signals emissions.
+ * # Checking correct reference counting.
+ * # Tests should be done with the sort and filter model
+ * in various filtering and sorting states.
*/
@@ -91,271 +99,6 @@ create_tree_store (int depth,
}
/*
- * Signal monitor
- */
-
-typedef enum
-{
- ROW_INSERTED,
- ROW_DELETED,
- ROW_CHANGED,
- ROW_HAS_CHILD_TOGGLED,
- ROWS_REORDERED,
- LAST_SIGNAL
-}
-SignalName;
-
-static const char *
-signal_name_to_string (SignalName signal)
-{
- switch (signal)
- {
- case ROW_INSERTED:
- return "row-inserted";
-
- case ROW_DELETED:
- return "row-deleted";
-
- case ROW_CHANGED:
- return "row-changed";
-
- case ROW_HAS_CHILD_TOGGLED:
- return "row-has-child-toggled";
-
- case ROWS_REORDERED:
- return "rows-reordered";
-
- default:
- /* Fall through */
- break;
- }
-
- return "(unknown)";
-}
-
-typedef struct
-{
- SignalName signal;
- GtkTreePath *path;
-}
-Signal;
-
-
-static Signal *
-signal_new (SignalName signal, GtkTreePath *path)
-{
- Signal *s;
-
- s = g_new0 (Signal, 1);
- s->signal = signal;
- s->path = gtk_tree_path_copy (path);
-
- return s;
-}
-
-static void
-signal_free (Signal *s)
-{
- if (s->path)
- gtk_tree_path_free (s->path);
-
- g_free (s);
-}
-
-
-typedef struct
-{
- GQueue *queue;
- GtkTreeModel *client;
- gulong signal_ids[LAST_SIGNAL];
-}
-SignalMonitor;
-
-
-static void
-signal_monitor_generic_handler (SignalMonitor *m,
- SignalName signal,
- GtkTreeModel *model,
- GtkTreePath *path)
-{
- Signal *s;
-
- if (g_queue_is_empty (m->queue))
- {
- g_error ("Signal queue empty\n");
- g_assert_not_reached ();
- }
-
- if (m->client != model)
- {
- g_error ("Model mismatch; expected %p, got %p\n",
- m->client, model);
- g_assert_not_reached ();
- }
-
- s = g_queue_peek_tail (m->queue);
-
-#if 0
- /* For debugging: output signals that are coming in. Leaks memory. */
- g_print ("signal=%d path=%s\n", signal, gtk_tree_path_to_string (path));
-#endif
-
- if (s->signal != signal
- || gtk_tree_path_compare (s->path, path) != 0)
- {
- gchar *path_str, *s_path_str;
-
- s_path_str = gtk_tree_path_to_string (s->path);
- path_str = gtk_tree_path_to_string (path);
-
- g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
- signal_name_to_string (s->signal), s_path_str,
- signal_name_to_string (signal), path_str);
-
- g_free (s_path_str);
- g_free (path_str);
-
- g_assert_not_reached ();
- }
-
- s = g_queue_pop_tail (m->queue);
-
- signal_free (s);
-}
-
-static void
-signal_monitor_row_inserted (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- signal_monitor_generic_handler (data, ROW_INSERTED,
- model, path);
-}
-
-static void
-signal_monitor_row_deleted (GtkTreeModel *model,
- GtkTreePath *path,
- gpointer data)
-{
- signal_monitor_generic_handler (data, ROW_DELETED,
- model, path);
-}
-
-static void
-signal_monitor_row_changed (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- signal_monitor_generic_handler (data, ROW_CHANGED,
- model, path);
-}
-
-static void
-signal_monitor_row_has_child_toggled (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
-{
- signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
- model, path);
-}
-
-static void
-signal_monitor_rows_reordered (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gint *new_order,
- gpointer data)
-{
- signal_monitor_generic_handler (data, ROWS_REORDERED,
- model, path);
-}
-
-static SignalMonitor *
-signal_monitor_new (GtkTreeModel *client)
-{
- SignalMonitor *m;
-
- m = g_new0 (SignalMonitor, 1);
- m->client = g_object_ref (client);
- m->queue = g_queue_new ();
-
- m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
- "row-inserted",
- G_CALLBACK (signal_monitor_row_inserted),
- m);
- m->signal_ids[ROW_DELETED] = g_signal_connect (client,
- "row-deleted",
- G_CALLBACK (signal_monitor_row_deleted),
- m);
- m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
- "row-changed",
- G_CALLBACK (signal_monitor_row_changed),
- m);
- m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
- "row-has-child-toggled",
- G_CALLBACK (signal_monitor_row_has_child_toggled),
- m);
- m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
- "rows-reordered",
- G_CALLBACK (signal_monitor_rows_reordered),
- m);
-
- return m;
-}
-
-static void
-signal_monitor_free (SignalMonitor *m)
-{
- int i;
-
- for (i = 0; i < LAST_SIGNAL; i++)
- g_signal_handler_disconnect (m->client, m->signal_ids[i]);
-
- g_object_unref (m->client);
-
- if (m->queue)
- g_queue_free (m->queue);
-
- g_free (m);
-}
-
-static void
-signal_monitor_assert_is_empty (SignalMonitor *m)
-{
- g_assert (g_queue_is_empty (m->queue));
-}
-
-static void
-signal_monitor_append_signal_path (SignalMonitor *m,
- SignalName signal,
- GtkTreePath *path)
-{
- Signal *s;
-
- s = signal_new (signal, path);
- g_queue_push_head (m->queue, s);
-}
-
-static void
-signal_monitor_append_signal (SignalMonitor *m,
- SignalName signal,
- const gchar *path_string)
-{
- Signal *s;
- GtkTreePath *path;
-
- path = gtk_tree_path_new_from_string (path_string);
-
- s = signal_new (signal, path);
- g_queue_push_head (m->queue, s);
-
- gtk_tree_path_free (path);
-}
-
-/*
* Fixture
*/
@@ -412,6 +155,23 @@ filter_test_setup_generic (FilterTest *fixture,
}
static void
+filter_test_setup_expand_root (FilterTest *fixture)
+{
+ int i;
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view),
+ path, FALSE);
+ gtk_tree_path_next (path);
+ }
+ gtk_tree_path_free (path);
+}
+
+static void
filter_test_setup (FilterTest *fixture,
gconstpointer test_data)
{
@@ -433,12 +193,28 @@ filter_test_setup_unfiltered (FilterTest *fixture,
}
static void
+filter_test_setup_unfiltered_root_expanded (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_unfiltered (fixture, test_data);
+ filter_test_setup_expand_root (fixture);
+}
+
+static void
filter_test_setup_empty_unfiltered (FilterTest *fixture,
gconstpointer test_data)
{
filter_test_setup_generic (fixture, test_data, 3, TRUE, TRUE);
}
+static void
+filter_test_setup_empty_unfiltered_root_expanded (FilterTest *fixture,
+ gconstpointer test_data)
+{
+ filter_test_setup_empty_unfiltered (fixture, test_data);
+ filter_test_setup_expand_root (fixture);
+}
+
static GtkTreePath *
strip_virtual_root (GtkTreePath *path,
GtkTreePath *root_path)
@@ -463,6 +239,32 @@ strip_virtual_root (GtkTreePath *path,
return real_path;
}
+static int
+count_visible (FilterTest *fixture,
+ GtkTreePath *store_path)
+{
+ int i;
+ int n_visible = 0;
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, store_path);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
+ {
+ gboolean visible;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (fixture->store), &iter,
+ 1, &visible,
+ -1);
+
+ if (visible)
+ n_visible++;
+ }
+
+ return n_visible;
+}
+
static void
filter_test_append_refilter_signals_recurse (FilterTest *fixture,
GtkTreePath *store_path,
@@ -530,26 +332,48 @@ filter_test_append_refilter_signals_recurse (FilterTest *fixture,
/* This row will be inserted */
signal_monitor_append_signal_path (fixture->monitor, ROW_CHANGED,
real_path);
- signal_monitor_append_signal_path (fixture->monitor,
- ROW_HAS_CHILD_TOGGLED,
- real_path);
- if (depth > 1
- && gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
- &iter))
+ if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (fixture->store),
+ &iter))
{
- GtkTreePath *store_copy;
- GtkTreePath *filter_copy;
-
- store_copy = gtk_tree_path_copy (store_path);
- filter_copy = gtk_tree_path_copy (filter_path);
- filter_test_append_refilter_signals_recurse (fixture,
- store_copy,
- filter_copy,
- depth - 1,
- root_path);
- gtk_tree_path_free (store_copy);
- gtk_tree_path_free (filter_copy);
+ signal_monitor_append_signal_path (fixture->monitor,
+ ROW_HAS_CHILD_TOGGLED,
+ real_path);
+
+ if (depth > 1)
+ {
+ GtkTreePath *store_copy;
+ GtkTreePath *filter_copy;
+
+ store_copy = gtk_tree_path_copy (store_path);
+ filter_copy = gtk_tree_path_copy (filter_path);
+ filter_test_append_refilter_signals_recurse (fixture,
+ store_copy,
+ filter_copy,
+ depth - 1,
+ root_path);
+ gtk_tree_path_free (store_copy);
+ gtk_tree_path_free (filter_copy);
+ }
+ else if (depth == 1)
+ {
+ GtkTreePath *tmp_path;
+
+ /* If all child rows are invisible, then the last row to
+ * become invisible will emit row-has-child-toggled on the
+ * parent.
+ */
+
+ tmp_path = gtk_tree_path_copy (store_path);
+ gtk_tree_path_append_index (tmp_path, 0);
+
+ if (count_visible (fixture, tmp_path) == 0)
+ signal_monitor_append_signal_path (fixture->monitor,
+ ROW_HAS_CHILD_TOGGLED,
+ real_path);
+
+ gtk_tree_path_free (tmp_path);
+ }
}
gtk_tree_path_next (filter_path);
@@ -660,6 +484,8 @@ filter_test_teardown (FilterTest *fixture,
{
signal_monitor_free (fixture->monitor);
+ gtk_widget_destroy (fixture->tree_view);
+
g_object_unref (fixture->filter);
g_object_unref (fixture->store);
}
@@ -733,6 +559,9 @@ check_filter_model_recurse (FilterTest *fixture,
gtk_tree_path_copy (store_parent_path),
tmp);
}
+ else
+ /* Only when we do not recurse we need to free tmp */
+ gtk_tree_path_free (tmp);
gtk_tree_path_next (filter_parent_path);
filter_has_next = gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->filter), &filter_iter);
@@ -780,24 +609,26 @@ check_filter_model_with_root (FilterTest *fixture,
static void
check_level_length (GtkTreeModelFilter *filter,
const gchar *level,
- const int length)
+ const int expected_length)
{
if (!level)
{
- int l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
- g_return_if_fail (l == length);
+ int model_length;
+
+ model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), NULL);
+ g_assert_cmpint (model_length, ==, expected_length);
}
else
{
- int l;
+ int model_length;
gboolean retrieved_iter = FALSE;
GtkTreeIter iter;
retrieved_iter = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (filter),
&iter, level);
g_return_if_fail (retrieved_iter);
- l = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
- g_return_if_fail (l == length);
+ model_length = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (filter), &iter);
+ g_assert_cmpint (model_length, ==, expected_length);
}
}
@@ -908,6 +739,59 @@ static void
filled_hide_child_levels (FilterTest *fixture,
gconstpointer user_data)
{
+ set_path_visibility (fixture, "0:2", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
+
+ set_path_visibility (fixture, "0:4", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "0:4:3", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "0:4:0", FALSE);
+ set_path_visibility (fixture, "0:4:1", FALSE);
+ set_path_visibility (fixture, "0:4:2", FALSE);
+ set_path_visibility (fixture, "0:4:4", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+ set_path_visibility (fixture, "0:4", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, "0:3", 0);
+
+ set_path_visibility (fixture, "0:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:4", 0);
+
+ /* Once 0:4:0 got inserted, 0:4 became a parent. Because 0:4 is
+ * not visible, not signals are emitted.
+ */
+ set_path_visibility (fixture, "0:4:2", TRUE);
+ set_path_visibility (fixture, "0:4:4", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, "0:4", 2);
+}
+
+static void
+filled_hide_child_levels_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
set_path_visibility (fixture, "0:2", FALSE);
check_filter_model (fixture);
@@ -935,10 +819,6 @@ filled_hide_child_levels (FilterTest *fixture,
/* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
- /* FIXME: Actually, the filter model should not be emitted the
- * row-has-child-toggled signal here. *However* an extraneous emission
- * of this signal does not hurt and is allowed.
- */
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
set_path_visibility (fixture, "0:4", TRUE);
check_filter_model (fixture);
@@ -952,13 +832,8 @@ filled_hide_child_levels (FilterTest *fixture,
check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
check_level_length (fixture->filter, "0:4", 0);
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
- /* Once 0:4:0 got inserted, 0:4 became a parent */
+ /* has-child-toggled for 0:4 is required. */
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:0");
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4:1");
-
set_path_visibility (fixture, "0:4:2", TRUE);
set_path_visibility (fixture, "0:4:4", TRUE);
signal_monitor_assert_is_empty (fixture->monitor);
@@ -1101,6 +976,60 @@ filled_vroot_hide_child_levels (FilterTest *fixture,
{
GtkTreePath *path = (GtkTreePath *)user_data;
+ set_path_visibility (fixture, "2:0:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
+
+ set_path_visibility (fixture, "2:0:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "2:0:4:3", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ set_path_visibility (fixture, "2:0:4:0", FALSE);
+ set_path_visibility (fixture, "2:0:4:1", FALSE);
+ set_path_visibility (fixture, "2:0:4:2", FALSE);
+ set_path_visibility (fixture, "2:0:4:4", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 2);
+
+ /* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
+ set_path_visibility (fixture, "2:0:4", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, "0:3", 0);
+
+ set_path_visibility (fixture, "2:0:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, "0:2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0:4", 0);
+
+ /* Once 0:4:0 got inserted, 0:4 became a parent. However, 0:4 is not
+ * visible, so no signal should be emitted.
+ */
+ set_path_visibility (fixture, "2:0:4:2", TRUE);
+ set_path_visibility (fixture, "2:0:4:4", TRUE);
+ check_level_length (fixture->filter, "0:4", 2);
+ signal_monitor_assert_is_empty (fixture->monitor);
+}
+
+static void
+filled_vroot_hide_child_levels_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+ GtkTreePath *tmp_path;
+
+ tmp_path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), tmp_path, FALSE);
+ gtk_tree_path_free (tmp_path);
+
signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:2");
set_path_visibility (fixture, "2:0:2", FALSE);
check_filter_model_with_root (fixture, path);
@@ -1128,10 +1057,6 @@ filled_vroot_hide_child_levels (FilterTest *fixture,
/* Since "0:2" is hidden, "0:4" must be "0:3" in the filter model */
signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
- /* FIXME: Actually, the filter model should not be emitted the
- * row-has-child-toggled signal here. *However* an extraneous emission
- * of this signal does not hurt and is allowed.
- */
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:3");
set_path_visibility (fixture, "2:0:4", TRUE);
check_filter_model_with_root (fixture, path);
@@ -1145,19 +1070,14 @@ filled_vroot_hide_child_levels (FilterTest *fixture,
check_level_length (fixture->filter, "0:3", LEVEL_LENGTH);
check_level_length (fixture->filter, "0:4", 0);
- /* FIXME: Inconsistency! For the non-vroot case we also receive two
- * row-has-child-toggled signals here.
- */
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:0");
/* Once 0:4:0 got inserted, 0:4 became a parent */
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:4:1");
set_path_visibility (fixture, "2:0:4:2", TRUE);
set_path_visibility (fixture, "2:0:4:4", TRUE);
check_level_length (fixture->filter, "0:4", 2);
+ signal_monitor_assert_is_empty (fixture->monitor);
}
-
static void
empty_show_nodes (FilterTest *fixture,
gconstpointer user_data)
@@ -1177,9 +1097,7 @@ empty_show_nodes (FilterTest *fixture,
check_level_length (fixture->filter, NULL, 1);
check_level_length (fixture->filter, "0", 0);
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
set_path_visibility (fixture, "3:2", TRUE);
check_filter_model (fixture);
check_level_length (fixture->filter, NULL, 1);
@@ -1217,8 +1135,6 @@ empty_show_multiple_nodes (FilterTest *fixture,
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "1");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
- signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "1");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
/* We simulate a change in visible func condition with this. The
* visibility state of multiple nodes changes at once, we emit row-changed
@@ -1233,6 +1149,7 @@ empty_show_multiple_nodes (FilterTest *fixture,
gtk_tree_path_append_index (changed_path, 2);
gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
&iter, changed_path);
+ /* Invisible node - so no signals expected */
gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
changed_path, &iter);
@@ -1257,9 +1174,7 @@ empty_show_multiple_nodes (FilterTest *fixture,
check_level_length (fixture->filter, NULL, 2);
check_level_length (fixture->filter, "0", 0);
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:0");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:0");
set_path_visibility (fixture, "3:2", TRUE);
check_filter_model (fixture);
check_level_length (fixture->filter, NULL, 2);
@@ -1451,9 +1366,28 @@ unfiltered_hide_single (FilterTest *fixture,
signal_monitor_assert_is_empty (fixture->monitor);
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
+ /* The view only shows the root level, so we only expect signals
+ * for the root level.
*/
+ filter_test_append_refilter_signals (fixture, 1);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_hide_single_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ set_path_visibility (fixture, "2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+
filter_test_append_refilter_signals (fixture, 2);
filter_test_enable_filter (fixture);
@@ -1466,6 +1400,29 @@ unfiltered_hide_single_child (FilterTest *fixture,
gconstpointer user_data)
{
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so we only expect signals
+ * for the root level.
+ */
+ filter_test_append_refilter_signals (fixture, 0);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_hide_single_child_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2", FALSE);
@@ -1474,9 +1431,6 @@ unfiltered_hide_single_child (FilterTest *fixture,
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
filter_test_append_refilter_signals (fixture, 2);
filter_test_enable_filter (fixture);
@@ -1493,6 +1447,40 @@ unfiltered_hide_single_multi_level (FilterTest *fixture,
/* This row is not shown, so its signal is not propagated */
set_path_visibility (fixture, "2:2:2", FALSE);
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so we only expect signals
+ * for the root level.
+ */
+ filter_test_append_refilter_signals (fixture, 1);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_hide_single_multi_level_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2", FALSE);
@@ -1502,9 +1490,6 @@ unfiltered_hide_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
filter_test_append_refilter_signals (fixture, 2);
filter_test_enable_filter (fixture);
@@ -1523,6 +1508,7 @@ unfiltered_hide_single_multi_level (FilterTest *fixture,
}
+
static void
unfiltered_vroot_hide_single (FilterTest *fixture,
gconstpointer user_data)
@@ -1537,11 +1523,11 @@ unfiltered_vroot_hide_single (FilterTest *fixture,
signal_monitor_assert_is_empty (fixture->monitor);
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached. (We add an additional level to
+ /* The view only shows the root level, so we only expect signals
+ * for the root level. (Though for the depth argument, we have to
* take the virtual root into account).
*/
- filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
filter_test_enable_filter (fixture);
check_filter_model_with_root (fixture, path);
@@ -1555,6 +1541,32 @@ unfiltered_vroot_hide_single_child (FilterTest *fixture,
{
GtkTreePath *path = (GtkTreePath *)user_data;
+ /* Not visible, so no signal will be received. */
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* The view only shows the root level, so we only expect signals
+ * for the root level. (Though for the depth argument, we have to
+ * take the virtual root into account).
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_vroot_hide_single_child_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2:2", FALSE);
@@ -1563,10 +1575,6 @@ unfiltered_vroot_hide_single_child (FilterTest *fixture,
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached. (We add an additional level to take
- * the virtual root into account).
- */
filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
filter_test_enable_filter (fixture);
@@ -1585,6 +1593,43 @@ unfiltered_vroot_hide_single_multi_level (FilterTest *fixture,
/* This row is not shown, so its signal is not propagated */
set_path_visibility (fixture, "2:2:2:2", FALSE);
+ /* Not shown, so no signal */
+ set_path_visibility (fixture, "2:2:2", FALSE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* We only expect signals for the root level. The depth is 2
+ * because we have to take the virtual root into account.
+ */
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+
+ /* Not shown, so no signal */
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_vroot_hide_single_multi_level_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ /* This row is not shown, so its signal is not propagated */
+ set_path_visibility (fixture, "2:2:2:2", FALSE);
+
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2:2", FALSE);
@@ -1594,9 +1639,6 @@ unfiltered_vroot_hide_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
filter_test_enable_filter (fixture);
@@ -1614,8 +1656,6 @@ unfiltered_vroot_hide_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
}
-
-
static void
unfiltered_show_single (FilterTest *fixture,
gconstpointer user_data)
@@ -1628,10 +1668,8 @@ unfiltered_show_single (FilterTest *fixture,
signal_monitor_assert_is_empty (fixture->monitor);
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
- filter_test_append_refilter_signals (fixture, 2);
+ /* We only expect signals for the root level */
+ filter_test_append_refilter_signals (fixture, 1);
filter_test_enable_filter (fixture);
check_filter_model (fixture);
@@ -1643,6 +1681,35 @@ unfiltered_show_single_child (FilterTest *fixture,
gconstpointer user_data)
{
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ /* We only expect signals for the root level */
+ filter_test_append_refilter_signals (fixture, 1);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+}
+
+static void
+unfiltered_show_single_child_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2", TRUE);
@@ -1651,10 +1718,7 @@ unfiltered_show_single_child (FilterTest *fixture,
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
- filter_test_append_refilter_signals (fixture, 3);
+ filter_test_append_refilter_signals (fixture, 2);
filter_test_enable_filter (fixture);
check_filter_model (fixture);
@@ -1676,6 +1740,41 @@ unfiltered_show_single_multi_level (FilterTest *fixture,
gconstpointer user_data)
{
+ /* The view is not showing these rows (collapsed state), so it is not
+ * referenced. The signal should not go through.
+ */
+ set_path_visibility (fixture, "2:2:2", TRUE);
+ set_path_visibility (fixture, "2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* We only expect signals for the first level */
+ filter_test_append_refilter_signals (fixture, 1);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+}
+
+static void
+unfiltered_show_single_multi_level_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
/* The view is not showing this row (collapsed state), so it is not
* referenced. The signal should not go through.
*/
@@ -1690,10 +1789,7 @@ unfiltered_show_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
- filter_test_append_refilter_signals (fixture, 3);
+ filter_test_append_refilter_signals (fixture, 2);
filter_test_enable_filter (fixture);
check_filter_model (fixture);
@@ -1711,7 +1807,6 @@ unfiltered_show_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "0:0", 1);
}
-
static void
unfiltered_vroot_show_single (FilterTest *fixture,
gconstpointer user_data)
@@ -1729,7 +1824,7 @@ unfiltered_vroot_show_single (FilterTest *fixture,
/* The view only shows the root level, so the filter model only has
* the first two levels cached.
*/
- filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
filter_test_enable_filter (fixture);
check_filter_model_with_root (fixture, path);
@@ -1743,8 +1838,6 @@ unfiltered_vroot_show_single_child (FilterTest *fixture,
{
GtkTreePath *path = (GtkTreePath *)user_data;
- signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2:2", TRUE);
signal_monitor_assert_is_empty (fixture->monitor);
@@ -1772,6 +1865,39 @@ unfiltered_vroot_show_single_child (FilterTest *fixture,
}
static void
+unfiltered_vroot_show_single_child_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2", TRUE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+}
+
+
+static void
unfiltered_vroot_show_single_multi_level (FilterTest *fixture,
gconstpointer user_data)
@@ -1783,6 +1909,44 @@ unfiltered_vroot_show_single_multi_level (FilterTest *fixture,
*/
set_path_visibility (fixture, "2:2:2:2", TRUE);
+ set_path_visibility (fixture, "2:2:2", TRUE);
+
+ signal_monitor_assert_is_empty (fixture->monitor);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
+
+ /* We only expect signals for the root level */
+ filter_test_append_refilter_signals_with_vroot (fixture, 2, path);
+ filter_test_enable_filter (fixture);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* From here we are filtered, "2" in the real model is "0" in the filter
+ * model.
+ */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+}
+
+static void
+unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
+
+{
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ /* The view is not showing this row (collapsed state), so it is not
+ * referenced. The signal should not go through.
+ */
+ set_path_visibility (fixture, "2:2:2:2", TRUE);
+
signal_monitor_append_signal (fixture->monitor, ROW_CHANGED, "2:2");
signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "2:2");
set_path_visibility (fixture, "2:2:2", TRUE);
@@ -1792,10 +1956,7 @@ unfiltered_vroot_show_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "2", LEVEL_LENGTH);
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH);
- /* The view only shows the root level, so the filter model only has
- * the first two levels cached.
- */
- filter_test_append_refilter_signals_with_vroot (fixture, 4, path);
+ filter_test_append_refilter_signals_with_vroot (fixture, 3, path);
filter_test_enable_filter (fixture);
check_filter_model_with_root (fixture, path);
@@ -1813,6 +1974,1332 @@ unfiltered_vroot_show_single_multi_level (FilterTest *fixture,
check_level_length (fixture->filter, "0:0", 1);
}
+static void
+unfiltered_rows_reordered_root_level (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 4, 0 };
+ int order1[] = { 0, 2, 1, 3, 4 };
+ int order2[] = { 4, 0, 1, 2, 3 };
+ GtkTreeIter iter0, iter1, iter2, iter3, iter4;
+ GtkTreePath *path;
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter0, "0");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter2, "2");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "4");
+
+ path = gtk_tree_path_new ();
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 5);
+ gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 5);
+ gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 5);
+ gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+unfiltered_rows_reordered_child_level (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 4, 0 };
+ int order1[] = { 0, 2, 1, 3, 4 };
+ int order2[] = { 4, 0, 1, 2, 3 };
+ GtkTreeIter iter0, iter1, iter2, iter3, iter4;
+ GtkTreePath *path;
+
+ /* Expand row 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter0, "0:0");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "0:1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter2, "0:2");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "0:3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "0:4");
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 5);
+ gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 5);
+ gtk_tree_store_move_after (fixture->store, &iter2, &iter3);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 5);
+ gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_root_level_first_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 0 };
+ int order1[] = { 0, 2, 1, 3 };
+ int order2[] = { 3, 0, 1, 2 };
+ GtkTreeIter iter1, iter2, iter3, iter4;
+ GtkTreePath *path;
+
+ /* Hide middle path */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0");
+ set_path_visibility (fixture, "0", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter2, "2");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "4");
+
+ path = gtk_tree_path_new ();
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 4);
+ gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 4);
+ gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 4);
+ gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_root_level_middle_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 0 };
+ int order1[] = { 0, 2, 1, 3 };
+ int order2[] = { 3, 0, 1, 2 };
+ GtkTreeIter iter0, iter1, iter3, iter4;
+ GtkTreePath *path;
+
+ /* Hide middle path */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "2");
+ set_path_visibility (fixture, "2", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter0, "0");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "4");
+
+ path = gtk_tree_path_new ();
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 4);
+ gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 4);
+ gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 4);
+ gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_first_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 0 };
+ int order1[] = { 0, 2, 1, 3 };
+ int order2[] = { 3, 0, 1, 2 };
+ GtkTreeIter iter1, iter2, iter3, iter4;
+ GtkTreePath *path;
+
+ /* Expand row 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, TRUE);
+
+ /* Hide middle path */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:0");
+ set_path_visibility (fixture, "0:0", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "0:1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter2, "0:2");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "0:3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "0:4");
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 4);
+ gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 4);
+ gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 4);
+ gtk_tree_store_move_before (fixture->store, &iter1, &iter2);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_middle_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 1, 2, 3, 0 };
+ int order1[] = { 0, 2, 1, 3 };
+ int order2[] = { 3, 0, 1, 2 };
+ GtkTreeIter iter0, iter1, iter3, iter4;
+ GtkTreePath *path;
+
+ /* Expand row 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+
+ /* Hide middle path */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:2");
+ set_path_visibility (fixture, "0:2", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter0, "0:0");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "0:1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter3, "0:3");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "0:4");
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 4);
+ gtk_tree_store_move_after (fixture->store, &iter0, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order1, 4);
+ gtk_tree_store_move_after (fixture->store, &iter3, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order2, 4);
+ gtk_tree_store_move_before (fixture->store, &iter0, &iter1);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_4_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ int order0[] = { 0 };
+ GtkTreeIter iter1, iter4;
+ GtkTreePath *path;
+
+ /* Expand row 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+
+ /* Hide last 4 paths */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:4");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:3");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:2");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:0");
+ set_path_visibility (fixture, "0:4", FALSE);
+ set_path_visibility (fixture, "0:3", FALSE);
+ set_path_visibility (fixture, "0:2", FALSE);
+ set_path_visibility (fixture, "0:0", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "0:1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "0:4");
+
+ signal_monitor_append_signal_reordered (fixture->monitor,
+ ROWS_REORDERED,
+ path, order0, 1);
+ gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+filtered_rows_reordered_child_level_all_hidden (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter1, iter4;
+ GtkTreePath *path;
+
+ /* Expand row 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (fixture->tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
+ /* Hide last 4 paths */
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:4");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:3");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:2");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:1");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_DELETED, "0:0");
+ signal_monitor_append_signal (fixture->monitor,
+ ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "0:4", FALSE);
+ set_path_visibility (fixture, "0:3", FALSE);
+ set_path_visibility (fixture, "0:2", FALSE);
+ set_path_visibility (fixture, "0:1", FALSE);
+ set_path_visibility (fixture, "0:0", FALSE);
+ signal_monitor_assert_is_empty (fixture->monitor);
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter1, "0:1");
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture->store),
+ &iter4, "0:4");
+
+ gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
+}
+
+static void
+insert_before (void)
+{
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreeIter iter;
+ GtkTreeIter last_iter;
+ GtkTreePath *path;
+
+ /* This tests two aspects of the row-inserted handling:
+ * 1) If the newly inserted node was already handled by building
+ * the root level, don't handle it a second time.
+ * 2) Offsets of existing nodes must be updated when a new
+ * node is inserted.
+ */
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
+ 1);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+ monitor = signal_monitor_new (filter);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 0);
+
+ /* Insert 0 */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_insert_with_values (store, &iter, NULL, 0,
+ 0, "Foo", 1, TRUE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+
+ /* Insert 1 */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+ 0, "Foo", 1, TRUE, -1);
+ last_iter = iter;
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+
+ /* Insert on 1 again -- invisible */
+ gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+ 0, "Foo", 1, FALSE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+
+ /* Insert on 1 again -- visible */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ signal_monitor_append_signal_path (monitor, ROW_INSERTED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_insert_with_values (store, &iter, NULL, 1,
+ 0, "Foo", 1, TRUE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+
+ /* Modify the iter that should be at the last position and check the
+ * signal we get.
+ */
+ path = gtk_tree_path_new_from_indices (2, -1);
+ signal_monitor_append_signal_path (monitor, ROW_CHANGED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_set (store, &last_iter, 0, "Foo changed", -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 3);
+}
+
+static void
+insert_child (void)
+{
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreeIter parent, iter;
+ GtkTreePath *path;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+ gtk_tree_store_insert_with_values (store, &parent, NULL, 0,
+ 0, "Parent", 1, TRUE, -1);
+
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter),
+ 1);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+ monitor = signal_monitor_new (filter);
+
+ /* Insert child -- invisible */
+ path = gtk_tree_path_new_from_indices (0, -1);
+ signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
+ /* The signal is received twice, once a pass through from GtkTreeStore
+ * and one generated by GtkTreeModelFilter. Not accurate, but cannot
+ * hurt.
+ */
+ signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
+ 0, "Child", 1, FALSE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+
+ /* Insert child */
+ path = gtk_tree_path_new_from_indices (0, 0, -1);
+ gtk_tree_path_up (path); /* 0 */
+ signal_monitor_append_signal_path (monitor, ROW_HAS_CHILD_TOGGLED, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_insert_with_values (store, &iter, &parent, 0,
+ 0, "Child", 1, TRUE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+
+ /* Insert child -- invisible */
+ gtk_tree_store_insert_with_values (store, &iter, &parent, 1,
+ 0, "Child", 1, FALSE, -1);
+
+ signal_monitor_assert_is_empty (monitor);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+}
+
+
+
+static void
+remove_node (void)
+{
+ GtkTreeIter iter, iter1, iter2, iter3;
+ GtkListStore *list;
+ GtkTreeModel *filter;
+ GtkWidget *view G_GNUC_UNUSED;
+
+ list = gtk_list_store_new (1, G_TYPE_INT);
+ gtk_list_store_insert_with_values (list, &iter1, 0, 0, 1, -1);
+ gtk_list_store_insert_with_values (list, &iter, 1, 0, 2, -1);
+ gtk_list_store_insert_with_values (list, &iter, 2, 0, 3, -1);
+ gtk_list_store_insert_with_values (list, &iter, 3, 0, 4, -1);
+ gtk_list_store_insert_with_values (list, &iter, 4, 0, 5, -1);
+ gtk_list_store_insert_with_values (list, &iter, 5, 0, 6, -1);
+ gtk_list_store_insert_with_values (list, &iter2, 6, 0, 7, -1);
+ gtk_list_store_insert_with_values (list, &iter3, 7, 0, 8, -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (list), NULL);
+ view = gtk_tree_view_new_with_model (filter);
+
+ gtk_list_store_remove (list, &iter1);
+ gtk_list_store_remove (list, &iter3);
+ gtk_list_store_remove (list, &iter2);
+
+ gtk_widget_destroy (view);
+ g_object_unref (filter);
+ g_object_unref (list);
+}
+
+static void
+remove_node_vroot (void)
+{
+ GtkTreeIter parent, root;
+ GtkTreeIter iter, iter1, iter2, iter3;
+ GtkTreeStore *tree;
+ GtkTreeModel *filter;
+ GtkTreePath *path;
+ GtkWidget *view G_GNUC_UNUSED;
+
+ tree = gtk_tree_store_new (1, G_TYPE_INT);
+ gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
+ gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+
+ gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
+ gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
+ gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+
+ path = gtk_tree_path_new_from_indices (0, 0, -1);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
+ gtk_tree_path_free (path);
+
+ view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_store_remove (tree, &iter1);
+ gtk_tree_store_remove (tree, &iter3);
+ gtk_tree_store_remove (tree, &iter2);
+
+ gtk_widget_destroy (view);
+ g_object_unref (filter);
+ g_object_unref (tree);
+}
+
+static void
+remove_vroot_ancestor (void)
+{
+ GtkTreeIter parent, root;
+ GtkTreeIter iter, iter1, iter2, iter3;
+ GtkTreeStore *tree;
+ GtkTreeModel *filter;
+ GtkTreePath *path;
+ GtkWidget *view G_GNUC_UNUSED;
+
+ tree = gtk_tree_store_new (1, G_TYPE_INT);
+ gtk_tree_store_insert_with_values (tree, &parent, NULL, 0, 0, 0, -1);
+ gtk_tree_store_insert_with_values (tree, &root, &parent, 0, 0, 0, -1);
+
+ gtk_tree_store_insert_with_values (tree, &iter1, &root, 0, 0, 1, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 1, 0, 2, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 2, 0, 3, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 3, 0, 4, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 4, 0, 5, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, &root, 5, 0, 6, -1);
+ gtk_tree_store_insert_with_values (tree, &iter2, &root, 6, 0, 7, -1);
+ gtk_tree_store_insert_with_values (tree, &iter3, &root, 7, 0, 8, -1);
+
+ path = gtk_tree_path_new_from_indices (0, 0, -1);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
+ gtk_tree_path_free (path);
+
+ view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_store_remove (tree, &parent);
+
+ gtk_widget_destroy (view);
+ g_object_unref (filter);
+ g_object_unref (tree);
+}
+
+static void
+ref_count_single_level (void)
+{
+ GtkTreeIter iter[5];
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter[0], NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter[1], NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter[2], NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter[3], NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter[4], NULL);
+
+ assert_root_level_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &iter[0], 2);
+ assert_node_ref_count (ref_model, &iter[1], 1);
+ assert_node_ref_count (ref_model, &iter[2], 1);
+ assert_node_ref_count (ref_model, &iter[3], 1);
+ assert_node_ref_count (ref_model, &iter[4], 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_node_ref_count (ref_model, &iter[0], 1);
+ assert_node_ref_count (ref_model, &iter[1], 0);
+ assert_node_ref_count (ref_model, &iter[2], 0);
+ assert_node_ref_count (ref_model, &iter[3], 0);
+ assert_node_ref_count (ref_model, &iter[4], 0);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &iter[0], 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_two_levels (void)
+{
+ GtkTreeIter parent1, parent2, iter, iter_first;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_first, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ /* This is quite confusing:
+ * - node 0 has a ref count of 2 because it is referenced as the
+ * first node in a level and by the tree view.
+ * - node 1 has a ref count of 2 because it is referenced by its
+ * child level and by the tree view.
+ */
+ assert_root_level_referenced (ref_model, 2);
+ assert_node_ref_count (ref_model, &iter_first, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_first, 2);
+ assert_node_ref_count (ref_model, &iter, 1);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ /* The child level is not destroyed because its parent is visible */
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_first, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_first, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &iter_first, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ /* Only the reference on the first node of the root level is kept. */
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_first, 0);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_three_levels (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2_first
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ /* This is quite confusing:
+ * - node 0 has a ref count of 2 because it is referenced as the
+ * first node in a level and by the tree view.
+ * - node 1 has a ref count of 2 because it is referenced by its
+ * child level and by the tree view.
+ */
+ assert_root_level_referenced (ref_model, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 2);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_path_append_index (path, 1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_path_up (path);
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ /* Only the reference on the first node of the root level is kept. */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_delete_row (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2_first
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_root_level_referenced (ref_model, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 2);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 2);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent2, 3);
+ assert_level_referenced (ref_model, 2, &parent2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_cleanup (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2_first
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 2);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 2);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ /* Only the reference on the first node of the root level is kept. */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_row_ref (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2, iter_parent2_first;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GtkTreePath *path;
+ GtkTreeRowReference *row_ref;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2_first, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+ row_ref = gtk_tree_row_reference_new (filter_model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+ row_ref = gtk_tree_row_reference_new (filter_model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2_first, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ /* Only the reference on the first node of the root level is kept. */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &parent1, 0);
+
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_insert (void)
+{
+ GtkTreeIter grandparent1, grandparent2, grandparent3;
+ GtkTreeIter new_node;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + grandparent3
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+ assert_node_ref_count (ref_model, &new_node, 2);
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_reordered (void)
+{
+ GtkTreeIter grandparent1, grandparent2, grandparent3;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + grandparent3
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, NULL);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &grandparent1, &grandparent3);
+
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_insert (void)
+{
+ GtkTreeIter grandparent1;
+ GtkTreeIter parent1, parent2, parent3;
+ GtkTreeIter new_node;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + parent1
+ * + parent2
+ * + parent3
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &grandparent1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &new_node, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_reordered (void)
+{
+ GtkTreeIter grandparent1;
+ GtkTreeIter parent1, parent2, parent3;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + parent1
+ * + parent2
+ * + parent3
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent3, &grandparent1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &parent1, &parent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+ assert_node_ref_count (ref_model, &parent1, 0);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
static gboolean
specific_path_dependent_filter_func (GtkTreeModel *model,
@@ -1866,6 +3353,10 @@ specific_path_dependent_filter (void)
NULL, 2))
gtk_list_store_remove (list, &iter);
}
+
+ g_object_unref (filter);
+ g_object_unref (sort);
+ g_object_unref (list);
}
@@ -2078,6 +3569,8 @@ specific_sort_filter_remove_root (void)
sort = gtk_tree_model_sort_new_with_model (model);
filter = gtk_tree_model_filter_new (sort, path);
+ gtk_tree_path_free (path);
+
gtk_tree_store_remove (GTK_TREE_STORE (model), &root);
g_object_unref (filter);
@@ -2138,13 +3631,15 @@ specific_has_child_filter (void)
{
GtkTreeModel *filter;
GtkTreeIter iter, root;
- /* A bit nasty, apologies */
- FilterTest fixture;
+ FilterTest fixture; /* This is not how it should be done */
+ GtkWidget *tree_view;
fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
fixture.filter = GTK_TREE_MODEL_FILTER (filter);
- fixture.monitor = NULL;
+ fixture.monitor = signal_monitor_new (filter);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
/* We will filter on parent state using a filter function. We will
* manually keep the boolean column in sync, so that we can use
@@ -2158,11 +3653,20 @@ specific_has_child_filter (void)
specific_has_child_filter_filter_func,
NULL, NULL);
+ /* The first node will be initially invisible: no signals */
gtk_tree_store_append (fixture.store, &root, NULL);
create_tree_store_set_values (fixture.store, &root, FALSE);
/* check_filter_model (&fixture); */
check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert a child node. This will cause the parent to become visible
+ * since there is a child now.
+ */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
gtk_tree_store_append (fixture.store, &iter, &root);
create_tree_store_set_values (fixture.store, &iter, TRUE);
@@ -2173,12 +3677,27 @@ specific_has_child_filter (void)
*/
check_level_length (fixture.filter, NULL, 1);
check_level_length (fixture.filter, "0", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* This should propagate row-changed */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
set_path_visibility (&fixture, "0", TRUE);
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+ /* New root node, no child, so no signal */
gtk_tree_store_append (fixture.store, &root, NULL);
check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* When the child comes in, this node will become visible */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
gtk_tree_store_append (fixture.store, &iter, &root);
check_level_length (fixture.filter, NULL, 2);
@@ -2188,14 +3707,19 @@ specific_has_child_filter (void)
create_tree_store_set_values (fixture.store, &iter, TRUE);
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+ /* Add another child for 1 */
gtk_tree_store_append (fixture.store, &iter, &root);
create_tree_store_set_values (fixture.store, &iter, TRUE);
check_level_length (fixture.filter, NULL, 2);
check_level_length (fixture.filter, "0", 0);
check_level_length (fixture.filter, "1", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
/* Now remove one of the remaining child rows */
+ signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
+
gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
&iter, "0:0");
gtk_tree_store_remove (fixture.store, &iter);
@@ -2205,6 +3729,7 @@ specific_has_child_filter (void)
set_path_visibility (&fixture, "0", FALSE);
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
}
@@ -2231,17 +3756,21 @@ specific_root_has_child_filter (void)
{
GtkTreeModel *filter;
GtkTreeIter iter, root;
- /* A bit nasty, apologies */
- FilterTest fixture;
+ FilterTest fixture; /* This is not how it should be done ... */
+ GtkWidget *tree_view;
- /* This is a variation on the above test case wherein the has-child
- * check for visibility only applies to root level nodes.
+ /* This is a variation on the above test case, specific has-child-filter,
+ * herein the has-child check for visibility only applies to root level
+ * nodes. In this test, children are always visible because we
+ * only filter based on the "has child" criterion.
*/
fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
fixture.filter = GTK_TREE_MODEL_FILTER (filter);
- fixture.monitor = NULL;
+ fixture.monitor = signal_monitor_new (filter);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
/* We will filter on parent state using a filter function. We will
* manually keep the boolean column in sync, so that we can use
@@ -2255,14 +3784,34 @@ specific_root_has_child_filter (void)
specific_root_has_child_filter_filter_func,
NULL, NULL);
+ /* Add a first node, this will be invisible initially, so no signal
+ * should be emitted.
+ */
gtk_tree_store_append (fixture.store, &root, NULL);
create_tree_store_set_values (fixture.store, &root, FALSE);
+ signal_monitor_assert_is_empty (fixture.monitor);
/* check_filter_model (&fixture); */
check_level_length (fixture.filter, NULL, 0);
+ /* Add a child node. This will cause the parent to become visible,
+ * so we expect row-inserted signals for both.
+ */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
gtk_tree_store_append (fixture.store, &iter, &root);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 1);
+
+ /* Modify the content of iter, no signals because the parent is not
+ * expanded.
+ */
create_tree_store_set_values (fixture.store, &iter, TRUE);
+ signal_monitor_assert_is_empty (fixture.monitor);
/* Parent must now be visible. Do the level length check first,
* to avoid modifying the child model triggering a row-changed to
@@ -2271,37 +3820,375 @@ specific_root_has_child_filter (void)
check_level_length (fixture.filter, NULL, 1);
check_level_length (fixture.filter, "0", 1);
+ /* Modify path 0 */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
set_path_visibility (&fixture, "0", TRUE);
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert another node in the root level. Initially invisible, so
+ * not expecting any signal.
+ */
gtk_tree_store_append (fixture.store, &root, NULL);
check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Adding a child node which also makes parent at path 1 visible. */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
gtk_tree_store_append (fixture.store, &iter, &root);
check_level_length (fixture.filter, NULL, 2);
check_level_length (fixture.filter, "1", 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Check if row-changed is propagated */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
create_tree_store_set_values (fixture.store, &root, TRUE);
create_tree_store_set_values (fixture.store, &iter, TRUE);
-
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+ /* Insert another child under node 1 */
gtk_tree_store_append (fixture.store, &iter, &root);
create_tree_store_set_values (fixture.store, &iter, TRUE);
check_level_length (fixture.filter, NULL, 2);
check_level_length (fixture.filter, "0", 1);
check_level_length (fixture.filter, "1", 2);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Set a child node to invisible. This should not yield any
+ * change, because filtering is only done on whether the root
+ * node has a child, which it still has.
+ */
+ set_path_visibility (&fixture, "0:0", FALSE);
+ signal_monitor_assert_is_empty (fixture.monitor);
/* Now remove one of the remaining child rows */
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
+
gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
&iter, "0:0");
gtk_tree_store_remove (fixture.store, &iter);
check_level_length (fixture.filter, NULL, 1);
check_level_length (fixture.filter, "0", 2);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Set visibility of 0 to FALSE, no-op for filter model since
+ * the child 0:0 is already gone
+ */
+ set_path_visibility (&fixture, "0", FALSE);
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+}
+
+static void
+specific_has_child_filter_on_sort_model (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeModel *sort_model;
+ GtkTreeIter iter, root;
+ FilterTest fixture; /* This is not how it should be done */
+ GtkWidget *tree_view;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
+ filter = gtk_tree_model_filter_new (sort_model, NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = signal_monitor_new (filter);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+
+ /* We will filter on parent state using a filter function. We will
+ * manually keep the boolean column in sync, so that we can use
+ * check_filter_model() to check the consistency of the model.
+ */
+ /* FIXME: We need a check_filter_model() that is not tied to LEVEL_LENGTH
+ * to be able to check the structure here. We keep the calls to
+ * check_filter_model() commented out until then.
+ */
+ gtk_tree_model_filter_set_visible_func (fixture.filter,
+ specific_has_child_filter_filter_func,
+ NULL, NULL);
+
+ /* The first node will be initially invisible: no signals */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ create_tree_store_set_values (fixture.store, &root, FALSE);
+
+ /* check_filter_model (&fixture); */
+ check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert a child node. This will cause the parent to become visible
+ * since there is a child now.
+ */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* Parent must now be visible. Do the level length check first,
+ * to avoid modifying the child model triggering a row-changed to
+ * the filter model.
+ */
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* This should propagate row-changed */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ set_path_visibility (&fixture, "0", TRUE);
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* New root node, no child, so no signal */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* When the child comes in, this node will become visible */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "1", 0);
+
+ create_tree_store_set_values (fixture.store, &root, TRUE);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Add another child for 1 */
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "0", 0);
+ check_level_length (fixture.filter, "1", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Now remove one of the remaining child rows */
+ signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
+ &iter, "0:0");
+ gtk_tree_store_remove (fixture.store, &iter);
+
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
set_path_visibility (&fixture, "0", FALSE);
/* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+}
+
+static gboolean
+specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ return gtk_tree_model_iter_n_children (model, iter) >= 2;
+}
+
+static void
+specific_at_least_2_children_filter (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeIter iter, root;
+ FilterTest fixture; /* This is not how it should be done */
+ GtkWidget *tree_view;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = signal_monitor_new (filter);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_model_filter_set_visible_func (fixture.filter,
+ specific_at_least_2_children_filter_filter_func,
+ NULL, NULL);
+
+ /* The first node will be initially invisible: no signals */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ create_tree_store_set_values (fixture.store, &root, FALSE);
+
+ /* check_filter_model (&fixture); */
+ check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert a child node. Nothing should happen.
+ */
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert a second child node. This will cause the parent to become
+ * visible.
+ */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* Parent must now be visible. Do the level length check first,
+ * to avoid modifying the child model triggering a row-changed to
+ * the filter model.
+ */
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* This should propagate row-changed */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ set_path_visibility (&fixture, "0", TRUE);
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* New root node, no child, so no signal */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* First child, no signal, no change */
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* When the second child comes in, this node will become visible */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "1");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "1", 0);
+
+ create_tree_store_set_values (fixture.store, &root, TRUE);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Add another child for 1 */
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ check_level_length (fixture.filter, NULL, 2);
+ check_level_length (fixture.filter, "0", 0);
+ check_level_length (fixture.filter, "1", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Now remove one of the remaining child rows */
+ signal_monitor_append_signal (fixture.monitor, ROW_DELETED, "0");
+
+ gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (fixture.store),
+ &iter, "0:0");
+ gtk_tree_store_remove (fixture.store, &iter);
+
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+
+ set_path_visibility (&fixture, "0", FALSE);
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+}
+
+static void
+specific_at_least_2_children_filter_on_sort_model (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeModel *sort_model;
+ GtkTreeIter iter, root;
+ FilterTest fixture; /* This is not how it should be done */
+ GtkWidget *tree_view;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (fixture.store));
+ filter = gtk_tree_model_filter_new (sort_model, NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = signal_monitor_new (filter);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_model_filter_set_visible_func (fixture.filter,
+ specific_at_least_2_children_filter_filter_func,
+ NULL, NULL);
+
+ /* The first node will be initially invisible: no signals */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ create_tree_store_set_values (fixture.store, &root, FALSE);
+
+ /* check_filter_model (&fixture); */
+ check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* Insert a child node. Nothing should happen.
+ */
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ check_level_length (fixture.filter, NULL, 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ {
+ GtkTreePath *path = gtk_tree_path_new_from_indices (0, 0, -1);
+ GtkTreeRowReference *ref;
+
+ ref = gtk_tree_row_reference_new (sort_model, path);
+ gtk_tree_path_free (path);
+ }
+
+ /* Insert a second child node. This will cause the parent to become
+ * visible.
+ */
+ signal_monitor_append_signal (fixture.monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ gtk_tree_store_append (fixture.store, &iter, &root);
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+
+ /* Parent must now be visible. Do the level length check first,
+ * to avoid modifying the child model triggering a row-changed to
+ * the filter model.
+ */
+ check_level_length (fixture.filter, NULL, 1);
+ check_level_length (fixture.filter, "0", 0);
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* This should propagate row-changed */
+ signal_monitor_append_signal (fixture.monitor, ROW_CHANGED, "0");
+ signal_monitor_append_signal (fixture.monitor, ROW_HAS_CHILD_TOGGLED, "0");
+
+ set_path_visibility (&fixture, "0", TRUE);
+ /* check_filter_model (&fixture); */
+ signal_monitor_assert_is_empty (fixture.monitor);
+
+ /* New root node, no child, so no signal */
+ gtk_tree_store_append (fixture.store, &root, NULL);
+ check_level_length (fixture.filter, NULL, 1);
+ signal_monitor_assert_is_empty (fixture.monitor);
}
@@ -2365,43 +4252,150 @@ specific_list_store_clear (void)
}
static void
-specific_bug_300089 (void)
+specific_sort_ref_leaf_and_remove_ancestor (void)
{
- /* Test case for GNOME Bugzilla bug 300089. Written by
- * Matthias Clasen.
- */
- GtkTreeModel *sort_model, *child_model;
+ GtkTreeIter iter, child, child2, child3;
+ GtkTreeStore *tree;
+ GtkTreeModel *sort;
GtkTreePath *path;
- GtkTreeIter iter, iter2, sort_iter;
+ GtkTreeRowReference *rowref;
+ GtkWidget *view G_GNUC_UNUSED;
- child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
+ tree = gtk_tree_store_new (1, G_TYPE_INT);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
- gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
- gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
+ gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
+ gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
+ gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
- gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
- gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (tree));
+ view = gtk_tree_view_new_with_model (sort);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
- gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
+ path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
+ rowref = gtk_tree_row_reference_new (sort, path);
+ gtk_tree_path_free (path);
+ path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
+ rowref = gtk_tree_row_reference_new (sort, path);
+ gtk_tree_path_free (path);
- sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
- 0, GTK_SORT_ASCENDING);
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ rowref = gtk_tree_row_reference_new (sort, path);
+ gtk_tree_path_free (path);
- path = gtk_tree_path_new_from_indices (1, 1, -1);
+ path = gtk_tree_path_new_from_indices (3, -1);
+ rowref = gtk_tree_row_reference_new (sort, path);
+ gtk_tree_path_free (path);
- /* make sure a level is constructed */
- gtk_tree_model_get_iter (sort_model, &sort_iter, path);
+ /* Deleting a parent */
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
+ gtk_tree_store_remove (tree, &iter);
+ gtk_tree_path_free (path);
- /* change the "E" row in a way that causes it to change position */
- gtk_tree_model_get_iter (child_model, &iter, path);
- gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
+ gtk_tree_row_reference_free (rowref);
+}
+
+static void
+specific_ref_leaf_and_remove_ancestor (void)
+{
+ GtkTreeIter iter, child, child2, child3;
+ GtkTreeStore *tree;
+ GtkTreeModel *filter;
+ GtkTreePath *path;
+ GtkTreeRowReference *rowref;
+ GtkWidget *view G_GNUC_UNUSED;
+
+ tree = gtk_tree_store_new (1, G_TYPE_INT);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
+
+ gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
+ gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
+ gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), NULL);
+ view = gtk_tree_view_new_with_model (filter);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+
+ path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (3, 0, 0, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (3, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ /* Deleting a parent */
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
+ gtk_tree_store_remove (tree, &iter);
+ gtk_tree_path_free (path);
+
+ gtk_tree_row_reference_free (rowref);
+}
+
+static void
+specific_virtual_ref_leaf_and_remove_ancestor (void)
+{
+ GtkTreeIter iter, child, child2, child3;
+ GtkTreeStore *tree;
+ GtkTreeModel *filter;
+ GtkTreePath *path;
+ GtkTreeRowReference *rowref;
+ GtkWidget *view G_GNUC_UNUSED;
+
+ tree = gtk_tree_store_new (1, G_TYPE_INT);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 0, 0, 1, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 1, 0, 2, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 2, 0, 3, -1);
+ gtk_tree_store_insert_with_values (tree, &iter, NULL, 3, 0, 4, -1);
+
+ gtk_tree_store_insert_with_values (tree, &child, &iter, 0, 0, 50, -1);
+ gtk_tree_store_insert_with_values (tree, &child2, &child, 0, 0, 6, -1);
+ gtk_tree_store_insert_with_values (tree, &child3, &child2, 0, 0, 7, -1);
+
+ /* Set a virtual root of 3:0 */
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (tree), path);
+ gtk_tree_path_free (path);
+
+ view = gtk_tree_view_new_with_model (filter);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (view));
+
+ path = gtk_tree_path_new_from_indices (0, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (0, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
+
+ /* Deleting the virtual root */
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (tree), &iter, path);
+ gtk_tree_store_remove (tree, &iter);
+ gtk_tree_path_free (path);
+
+ gtk_tree_row_reference_free (rowref);
}
@@ -2433,6 +4427,8 @@ specific_bug_301558 (void)
int i;
gboolean add;
+ g_test_bug ("301558");
+
tree = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_BOOLEAN);
gtk_tree_store_append (tree, &iter, NULL);
gtk_tree_store_set (tree, &iter, 0, 123, 1, TRUE, -1);
@@ -2505,6 +4501,9 @@ specific_bug_311955 (void)
GtkWidget *tree_view;
int i;
int n;
+ GtkTreePath *path;
+
+ g_test_bug ("311955");
store = gtk_tree_store_new (1, G_TYPE_INT);
@@ -2533,6 +4532,9 @@ specific_bug_311955 (void)
while (gtk_events_pending ())
gtk_main_iteration ();
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 2);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
+
/* Fill model */
for (i = 0; i < 4; i++)
{
@@ -2553,6 +4555,9 @@ specific_bug_311955 (void)
while (gtk_events_pending ())
gtk_main_iteration ();
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 1);
+
/* Remove bottommost child from the tree. */
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
n = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (store), &root);
@@ -2564,6 +4569,86 @@ specific_bug_311955 (void)
}
else
g_assert_not_reached ();
+
+ path = gtk_tree_path_new_from_indices (0, 2, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
+}
+
+static void
+specific_bug_311955_clean (void)
+{
+ /* Cleaned up version of the test case for GNOME Bugzilla bug 311955,
+ * which is easier to understand.
+ */
+ GtkTreeIter iter, child, grandchild;
+ GtkTreeStore *store;
+ GtkTreeModel *sort;
+ GtkTreeModel *filter;
+
+ GtkWidget *tree_view;
+ GtkTreePath *path;
+
+ store = gtk_tree_store_new (1, G_TYPE_INT);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, 1, -1);
+
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 1, -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ filter = gtk_tree_model_filter_new (sort, NULL);
+
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_311955_filter_func,
+ NULL, NULL);
+
+ tree_view = gtk_tree_view_new_with_model (filter);
+ g_object_unref (store);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
+
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 0, -1);
+
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 1, -1);
+
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 1, -1);
+
+ gtk_tree_store_append (store, &grandchild, &child);
+ gtk_tree_store_set (store, &grandchild, 0, 1, -1);
+
+ gtk_tree_store_append (store, &child, &iter);
+ /* Don't set a value: assume 0 */
+
+ /* Remove leaf node, check trigger row-has-child-toggled */
+ path = gtk_tree_path_new_from_indices (0, 3, 0, -1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
+ gtk_tree_path_free (path);
+ gtk_tree_store_remove (store, &iter);
+
+ path = gtk_tree_path_new_from_indices (0, 2, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 3);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0:2", 0);
+
+ gtk_widget_destroy (tree_view);
}
static void
@@ -2587,6 +4672,8 @@ specific_bug_346800 (void)
store = gtk_tree_store_newv (2, columns);
model = GTK_TREE_MODEL (store);
+ g_test_bug ("346800");
+
filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
gtk_tree_model_filter_set_visible_column (filter, 1);
@@ -2622,45 +4709,6 @@ specific_bug_346800 (void)
}
}
-
-static void
-specific_bug_364946 (void)
-{
- /* This is a test case for GNOME Bugzilla bug 364946. It was written
- * by Andreas Koehler.
- */
- GtkTreeStore *store;
- GtkTreeIter a, aa, aaa, aab, iter;
- GtkTreeModel *s_model;
-
- store = gtk_tree_store_new (1, G_TYPE_STRING);
-
- gtk_tree_store_append (store, &a, NULL);
- gtk_tree_store_set (store, &a, 0, "0", -1);
-
- gtk_tree_store_append (store, &aa, &a);
- gtk_tree_store_set (store, &aa, 0, "0:0", -1);
-
- gtk_tree_store_append (store, &aaa, &aa);
- gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
-
- gtk_tree_store_append (store, &aab, &aa);
- gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
-
- s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
- GTK_SORT_ASCENDING);
-
- gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
-
- gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
- gtk_tree_store_remove (store, &aaa);
- gtk_tree_store_remove (store, &aab);
-
- gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
-}
-
-
static gboolean
specific_bug_464173_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
@@ -2683,6 +4731,8 @@ specific_bug_464173 (void)
GtkWidget *view G_GNUC_UNUSED;
gboolean visible = TRUE;
+ g_test_bug ("464173");
+
model = gtk_tree_store_new (1, G_TYPE_STRING);
gtk_tree_store_append (model, &iter1, NULL);
gtk_tree_store_set (model, &iter1, 0, "Foo", -1);
@@ -2725,6 +4775,8 @@ specific_bug_540201 (void)
GtkWidget *tree_view G_GNUC_UNUSED;
+ g_test_bug ("540201");
+
store = gtk_tree_store_new (1, G_TYPE_INT);
gtk_tree_store_append (store, &root, NULL);
@@ -2776,6 +4828,8 @@ specific_bug_549287 (void)
GtkTreeIter iter;
GtkTreeIter *swap, *parent, *child;
+ g_test_bug ("529287");
+
store = gtk_tree_store_new (1, G_TYPE_STRING);
filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filtered),
@@ -2821,180 +4875,582 @@ specific_bug_549287 (void)
}
}
-/* main */
+static gboolean
+specific_bug_621076_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean visible = FALSE;
+ gchar *str = NULL;
+
+ 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))
+ {
+ if (specific_bug_621076_visible_func (model, &child_iter, data))
+ {
+ visible = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (str)
+ g_free (str);
-int
-main (int argc,
- char **argv)
+ return visible;
+}
+
+static void
+specific_bug_621076 (void)
{
- gtk_test_init (&argc, &argv, NULL);
+ /* 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 */
+ 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_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);
+}
- g_test_add ("/FilterModel/self/verify-test-suite",
+/* main */
+
+void
+register_filter_model_tests (void)
+{
+ g_test_add ("/TreeModelFilter/self/verify-test-suite",
FilterTest, NULL,
filter_test_setup,
verify_test_suite,
filter_test_teardown);
- g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-1",
+ g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-1",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup,
verify_test_suite_vroot,
filter_test_teardown);
- g_test_add ("/FilterModel/self/verify-test-suite/vroot/depth-2",
+ g_test_add ("/TreeModelFilter/self/verify-test-suite/vroot/depth-2",
FilterTest, gtk_tree_path_new_from_indices (2, 3, -1),
filter_test_setup,
verify_test_suite_vroot,
filter_test_teardown);
- g_test_add ("/FilterModel/filled/hide-root-level",
+ g_test_add ("/TreeModelFilter/filled/hide-root-level",
FilterTest, NULL,
filter_test_setup,
filled_hide_root_level,
filter_test_teardown);
- g_test_add ("/FilterModel/filled/hide-child-levels",
+ g_test_add ("/TreeModelFilter/filled/hide-child-levels",
FilterTest, NULL,
filter_test_setup,
filled_hide_child_levels,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filled/hide-child-levels/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup,
+ filled_hide_child_levels_root_expanded,
+ filter_test_teardown);
- g_test_add ("/FilterModel/filled/hide-root-level/vroot",
+ g_test_add ("/TreeModelFilter/filled/hide-root-level/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup,
filled_vroot_hide_root_level,
filter_test_teardown);
- g_test_add ("/FilterModel/filled/hide-child-levels/vroot",
+ g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup,
filled_vroot_hide_child_levels,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filled/hide-child-levels/vroot-root-expanded",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup,
+ filled_vroot_hide_child_levels_root_expanded,
+ filter_test_teardown);
- g_test_add ("/FilterModel/empty/show-nodes",
+ g_test_add ("/TreeModelFilter/empty/show-nodes",
FilterTest, NULL,
filter_test_setup_empty,
empty_show_nodes,
filter_test_teardown);
- g_test_add ("/FilterModel/empty/show-multiple-nodes",
+ g_test_add ("/TreeModelFilter/empty/show-multiple-nodes",
FilterTest, NULL,
filter_test_setup_empty,
empty_show_multiple_nodes,
filter_test_teardown);
- g_test_add ("/FilterModel/empty/show-nodes/vroot",
+ g_test_add ("/TreeModelFilter/empty/show-nodes/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_empty,
empty_vroot_show_nodes,
filter_test_teardown);
- g_test_add ("/FilterModel/empty/show-multiple-nodes/vroot",
+ g_test_add ("/TreeModelFilter/empty/show-multiple-nodes/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_empty,
empty_vroot_show_multiple_nodes,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single",
FilterTest, NULL,
filter_test_setup_unfiltered,
unfiltered_hide_single,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single-child",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered_root_expanded,
+ unfiltered_hide_single_root_expanded,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-child",
FilterTest, NULL,
filter_test_setup_unfiltered,
unfiltered_hide_single_child,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single-multi-level",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered_root_expanded,
+ unfiltered_hide_single_child_root_expanded,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level",
FilterTest, NULL,
filter_test_setup_unfiltered,
unfiltered_hide_single_multi_level,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered_root_expanded,
+ unfiltered_hide_single_multi_level_root_expanded,
+ filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_unfiltered,
unfiltered_vroot_hide_single,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single-child/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_unfiltered,
unfiltered_vroot_hide_single_child,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/hide-single-multi-level/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-child/vroot/root-expanded",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_unfiltered_root_expanded,
+ unfiltered_vroot_hide_single_child_root_expanded,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_unfiltered,
unfiltered_vroot_hide_single_multi_level,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/hide-single-multi-level/vroot/root-expanded",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_unfiltered_root_expanded,
+ unfiltered_vroot_hide_single_multi_level_root_expanded,
+ filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single",
FilterTest, NULL,
filter_test_setup_empty_unfiltered,
unfiltered_show_single,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single-child",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-child",
FilterTest, NULL,
filter_test_setup_empty_unfiltered,
unfiltered_show_single_child,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single-multi-level",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-child/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup_empty_unfiltered_root_expanded,
+ unfiltered_show_single_child_root_expanded,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level",
FilterTest, NULL,
filter_test_setup_empty_unfiltered,
unfiltered_show_single_multi_level,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/root-expanded",
+ FilterTest, NULL,
+ filter_test_setup_empty_unfiltered_root_expanded,
+ unfiltered_show_single_multi_level_root_expanded,
+ filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_empty_unfiltered,
unfiltered_vroot_show_single,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single-child/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_empty_unfiltered,
unfiltered_vroot_show_single_child,
filter_test_teardown);
- g_test_add ("/FilterModel/unfiltered/show-single-multi-level/vroot",
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-child/vroot/root-expanded",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty_unfiltered_root_expanded,
+ unfiltered_vroot_show_single_child_root_expanded,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot",
FilterTest, gtk_tree_path_new_from_indices (2, -1),
filter_test_setup_empty_unfiltered,
unfiltered_vroot_show_single_multi_level,
filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/show-single-multi-level/vroot/root-expanded",
+ FilterTest, gtk_tree_path_new_from_indices (2, -1),
+ filter_test_setup_empty_unfiltered_root_expanded,
+ unfiltered_vroot_show_single_multi_level_root_expanded,
+ filter_test_teardown);
- g_test_add_func ("/FilterModel/specific/path-dependent-filter",
+ g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/root-level",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered,
+ unfiltered_rows_reordered_root_level,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/unfiltered/rows-reordered/child-level",
+ FilterTest, NULL,
+ filter_test_setup_unfiltered,
+ unfiltered_rows_reordered_child_level,
+ filter_test_teardown);
+
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/first-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_root_level_first_hidden,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/root-level/middle-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_root_level_middle_hidden,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/first-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_child_level_first_hidden,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/middle-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_child_level_middle_hidden,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/4-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_child_level_4_hidden,
+ filter_test_teardown);
+ g_test_add ("/TreeModelFilter/filtered/rows-reordered/child-level/all-hidden",
+ FilterTest, NULL,
+ filter_test_setup,
+ filtered_rows_reordered_child_level_all_hidden,
+ filter_test_teardown);
+
+ /* Inserts in child models after creation of filter model */
+ g_test_add_func ("/TreeModelFilter/insert/before",
+ insert_before);
+ g_test_add_func ("/TreeModelFilter/insert/child",
+ insert_child);
+
+ /* Removals from child model after creating of filter model */
+ g_test_add_func ("/TreeModelFilter/remove/node",
+ remove_node);
+ g_test_add_func ("/TreeModelFilter/remove/node-vroot",
+ remove_node_vroot);
+ g_test_add_func ("/TreeModelFilter/remove/vroot-ancestor",
+ remove_vroot_ancestor);
+
+ /* Reference counting */
+ g_test_add_func ("/TreeModelFilter/ref-count/single-level",
+ ref_count_single_level);
+ g_test_add_func ("/TreeModelFilter/ref-count/two-levels",
+ ref_count_two_levels);
+ g_test_add_func ("/TreeModelFilter/ref-count/three-levels",
+ ref_count_three_levels);
+ g_test_add_func ("/TreeModelFilter/ref-count/delete-row",
+ ref_count_delete_row);
+ g_test_add_func ("/TreeModelFilter/ref-count/cleanup",
+ ref_count_cleanup);
+ g_test_add_func ("/TreeModelFilter/ref-count/row-ref",
+ ref_count_row_ref);
+
+ /* Reference counting, transfer of first reference on
+ * first node in level. This is a GtkTreeModelFilter-specific
+ * feature.
+ */
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/insert",
+ ref_count_transfer_root_level_insert);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/reordered",
+ ref_count_transfer_root_level_reordered);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/insert",
+ ref_count_transfer_child_level_insert);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
+ ref_count_transfer_child_level_reordered);
+
+ g_test_add_func ("/TreeModelFilter/specific/path-dependent-filter",
specific_path_dependent_filter);
- g_test_add_func ("/FilterModel/specific/append-after-collapse",
+ g_test_add_func ("/TreeModelFilter/specific/append-after-collapse",
specific_append_after_collapse);
- g_test_add_func ("/FilterModel/specific/sort-filter-remove-node",
+ g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-node",
specific_sort_filter_remove_node);
- g_test_add_func ("/FilterModel/specific/sort-filter-remove-root",
+ g_test_add_func ("/TreeModelFilter/specific/sort-filter-remove-root",
specific_sort_filter_remove_root);
- g_test_add_func ("/FilterModel/specific/root-mixed-visibility",
+ g_test_add_func ("/TreeModelFilter/specific/root-mixed-visibility",
specific_root_mixed_visibility);
- g_test_add_func ("/FilterModel/specific/has-child-filter",
+ g_test_add_func ("/TreeModelFilter/specific/has-child-filter",
specific_has_child_filter);
- g_test_add_func ("/FilterModel/specific/root-has-child-filter",
+ g_test_add_func ("/TreeModelFilter/specific/has-child-filter-on-sort-model",
+ specific_has_child_filter_on_sort_model);
+ g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter",
+ specific_at_least_2_children_filter);
+ g_test_add_func ("/TreeModelFilter/specific/at-least-2-children-filter-on-sort-model",
+ specific_at_least_2_children_filter_on_sort_model);
+ g_test_add_func ("/TreeModelFilter/specific/root-has-child-filter",
specific_root_has_child_filter);
- g_test_add_func ("/FilterModel/specific/filter-add-child",
+ g_test_add_func ("/TreeModelFilter/specific/filter-add-child",
specific_filter_add_child);
- g_test_add_func ("/FilterModel/specific/list-store-clear",
+ g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
specific_list_store_clear);
-
- g_test_add_func ("/FilterModel/specific/bug-300089",
- specific_bug_300089);
- g_test_add_func ("/FilterModel/specific/bug-301558",
+ g_test_add_func ("/TreeModelFilter/specific/sort-ref-leaf-and-remove-ancestor",
+ specific_sort_ref_leaf_and_remove_ancestor);
+ g_test_add_func ("/TreeModelFilter/specific/ref-leaf-and-remove-ancestor",
+ specific_ref_leaf_and_remove_ancestor);
+ g_test_add_func ("/TreeModelFilter/specific/virtual-ref-leaf-and-remove-ancestor",
+ specific_virtual_ref_leaf_and_remove_ancestor);
+
+ g_test_add_func ("/TreeModelFilter/specific/bug-301558",
specific_bug_301558);
- g_test_add_func ("/FilterModel/specific/bug-311955",
+ g_test_add_func ("/TreeModelFilter/specific/bug-311955",
specific_bug_311955);
- g_test_add_func ("/FilterModel/specific/bug-346800",
+ g_test_add_func ("/TreeModelFilter/specific/bug-311955-clean",
+ specific_bug_311955_clean);
+ g_test_add_func ("/TreeModelFilter/specific/bug-346800",
specific_bug_346800);
- g_test_add_func ("/FilterModel/specific/bug-364946",
- specific_bug_364946);
- g_test_add_func ("/FilterModel/specific/bug-464173",
+ g_test_add_func ("/TreeModelFilter/specific/bug-464173",
specific_bug_464173);
- g_test_add_func ("/FilterModel/specific/bug-540201",
+ g_test_add_func ("/TreeModelFilter/specific/bug-540201",
specific_bug_540201);
- g_test_add_func ("/FilterModel/specific/bug-549287",
+ g_test_add_func ("/TreeModelFilter/specific/bug-549287",
specific_bug_549287);
-
- return g_test_run ();
+ g_test_add_func ("/TreeModelFilter/specific/bug-621076",
+ specific_bug_621076);
}
diff --git a/gtk/tests/gtktreemodelrefcount.c b/gtk/tests/gtktreemodelrefcount.c
new file mode 100644
index 0000000000..9c91a587da
--- /dev/null
+++ b/gtk/tests/gtktreemodelrefcount.c
@@ -0,0 +1,286 @@
+/* gtktreemodelrefcount.c
+ * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include "gtktreemodelrefcount.h"
+
+
+/* The purpose of this GtkTreeModel is to keep record of the reference count
+ * of each node. The reference count does not effect the functioning of
+ * the model in any way. Because this model is a subclass of GtkTreeStore,
+ * the GtkTreeStore API should be used to add to and remove nodes from
+ * this model. We depend on the iter format of GtkTreeStore, which means
+ * that this model needs to be revised in case the iter format of
+ * GtkTreeStore is modified. Currently, we make use of the fact that
+ * the value stored in the user_data field is unique for each node.
+ */
+
+struct _GtkTreeModelRefCountPrivate
+{
+ GHashTable *node_hash;
+};
+
+typedef struct
+{
+ int ref_count;
+}
+NodeInfo;
+
+
+static void gtk_tree_model_ref_count_tree_model_init (GtkTreeModelIface *iface);
+static void gtk_tree_model_ref_count_finalize (GObject *object);
+
+static NodeInfo *node_info_new (void);
+static void node_info_free (NodeInfo *info);
+
+/* GtkTreeModel interface */
+static void gtk_tree_model_ref_count_ref_node (GtkTreeModel *model,
+ GtkTreeIter *iter);
+static void gtk_tree_model_ref_count_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter);
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkTreeModelRefCount, gtk_tree_model_ref_count, GTK_TYPE_TREE_STORE,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
+ gtk_tree_model_ref_count_tree_model_init))
+
+static void
+gtk_tree_model_ref_count_init (GtkTreeModelRefCount *ref_model)
+{
+ ref_model->priv = G_TYPE_INSTANCE_GET_PRIVATE (ref_model,
+ GTK_TYPE_TREE_MODEL_REF_COUNT,
+ GtkTreeModelRefCountPrivate);
+
+ ref_model->priv->node_hash = g_hash_table_new_full (g_direct_hash,
+ g_direct_equal,
+ NULL,
+ (GDestroyNotify)node_info_free);
+}
+
+static void
+gtk_tree_model_ref_count_class_init (GtkTreeModelRefCountClass *ref_model_class)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) ref_model_class;
+
+ object_class->finalize = gtk_tree_model_ref_count_finalize;
+
+ g_type_class_add_private (object_class, sizeof (GtkTreeModelRefCountPrivate));
+}
+
+static void
+gtk_tree_model_ref_count_tree_model_init (GtkTreeModelIface *iface)
+{
+ iface->ref_node = gtk_tree_model_ref_count_ref_node;
+ iface->unref_node = gtk_tree_model_ref_count_unref_node;
+}
+
+static void
+gtk_tree_model_ref_count_finalize (GObject *object)
+{
+ GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (object);
+
+ if (ref_model->priv->node_hash)
+ {
+ g_hash_table_destroy (ref_model->priv->node_hash);
+ ref_model->priv->node_hash = NULL;
+ }
+
+ G_OBJECT_CLASS (gtk_tree_model_ref_count_parent_class)->finalize (object);
+}
+
+
+static NodeInfo *
+node_info_new (void)
+{
+ NodeInfo *info = g_slice_new (NodeInfo);
+ info->ref_count = 0;
+
+ return info;
+}
+
+static void
+node_info_free (NodeInfo *info)
+{
+ g_slice_free (NodeInfo, info);
+}
+
+static void
+gtk_tree_model_ref_count_ref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ NodeInfo *info;
+ GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data);
+ if (!info)
+ {
+ info = node_info_new ();
+
+ g_hash_table_insert (ref_model->priv->node_hash, iter->user_data, info);
+ }
+
+ info->ref_count++;
+}
+
+static void
+gtk_tree_model_ref_count_unref_node (GtkTreeModel *model,
+ GtkTreeIter *iter)
+{
+ NodeInfo *info;
+ GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data);
+ g_assert (info != NULL);
+ g_assert (info->ref_count > 0);
+
+ info->ref_count--;
+}
+
+
+GtkTreeModel *
+gtk_tree_model_ref_count_new (void)
+{
+ GtkTreeModel *retval;
+
+ retval = g_object_new (gtk_tree_model_ref_count_get_type (), NULL);
+
+ return retval;
+}
+
+static void
+dump_iter (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter)
+{
+ gchar *path_str;
+ NodeInfo *info;
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (ref_model), iter);
+ path_str = gtk_tree_path_to_string (path);
+ gtk_tree_path_free (path);
+
+ info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data);
+ if (!info)
+ g_print ("%-16s ref_count=0\n", path_str);
+ else
+ g_print ("%-16s ref_count=%d\n", path_str, info->ref_count);
+
+ g_free (path_str);
+}
+
+static void
+gtk_tree_model_ref_count_dump_recurse (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter)
+{
+ do
+ {
+ GtkTreeIter child;
+
+ dump_iter (ref_model, iter);
+
+ if (gtk_tree_model_iter_children (GTK_TREE_MODEL (ref_model),
+ &child, iter))
+ gtk_tree_model_ref_count_dump_recurse (ref_model, &child);
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ref_model), iter));
+}
+
+void
+gtk_tree_model_ref_count_dump (GtkTreeModelRefCount *ref_model)
+{
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ref_model), &iter))
+ return;
+
+ gtk_tree_model_ref_count_dump_recurse (ref_model, &iter);
+}
+
+static gboolean
+check_iter (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter,
+ gint expected_ref_count,
+ gboolean may_assert)
+{
+ NodeInfo *info;
+
+ if (may_assert)
+ g_assert (gtk_tree_store_iter_is_valid (GTK_TREE_STORE (ref_model), iter));
+
+ info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data);
+ if (!info)
+ {
+ if (expected_ref_count == 0)
+ return TRUE;
+ else
+ {
+ if (may_assert)
+ g_error ("Expected ref count %d, but node has never been referenced.\n", expected_ref_count);
+ return FALSE;
+ }
+ }
+
+ if (may_assert)
+ g_assert_cmpint (expected_ref_count, ==, info->ref_count);
+
+ return expected_ref_count == info->ref_count;
+}
+
+gboolean
+gtk_tree_model_ref_count_check_level (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *parent,
+ gint expected_ref_count,
+ gboolean recurse,
+ gboolean may_assert)
+{
+ GtkTreeIter iter;
+
+ if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (ref_model),
+ &iter, parent))
+ return TRUE;
+
+ do
+ {
+ if (!check_iter (ref_model, &iter, expected_ref_count, may_assert))
+ return FALSE;
+
+ if (recurse &&
+ gtk_tree_model_iter_has_child (GTK_TREE_MODEL (ref_model), &iter))
+ {
+ if (!gtk_tree_model_ref_count_check_level (ref_model, &iter,
+ expected_ref_count,
+ recurse, may_assert))
+ return FALSE;
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ref_model), &iter));
+
+ return TRUE;
+}
+
+gboolean
+gtk_tree_model_ref_count_check_node (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter,
+ gint expected_ref_count,
+ gboolean may_assert)
+{
+ return check_iter (ref_model, iter, expected_ref_count, may_assert);
+}
diff --git a/gtk/tests/gtktreemodelrefcount.h b/gtk/tests/gtktreemodelrefcount.h
new file mode 100644
index 0000000000..f32c8bd2b8
--- /dev/null
+++ b/gtk/tests/gtktreemodelrefcount.h
@@ -0,0 +1,134 @@
+/* gtktreemodelrefcount.h
+ * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_TREE_MODEL_REF_COUNT_H__
+#define __GTK_TREE_MODEL_REF_COUNT_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_TREE_MODEL_REF_COUNT (gtk_tree_model_ref_count_get_type ())
+#define GTK_TREE_MODEL_REF_COUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCount))
+#define GTK_TREE_MODEL_REF_COUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCountClass))
+#define GTK_IS_TREE_MODEL_REF_COUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT))
+#define GTK_IS_TREE_MODEL_REF_COUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_TREE_MODEL_REF_COUNT))
+#define GTK_TREE_MODEL_REF_COUNT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCountClass))
+
+
+typedef struct _GtkTreeModelRefCount GtkTreeModelRefCount;
+typedef struct _GtkTreeModelRefCountClass GtkTreeModelRefCountClass;
+typedef struct _GtkTreeModelRefCountPrivate GtkTreeModelRefCountPrivate;
+
+struct _GtkTreeModelRefCount
+{
+ GtkTreeStore parent;
+
+ /* < private > */
+ GtkTreeModelRefCountPrivate *priv;
+};
+
+struct _GtkTreeModelRefCountClass
+{
+ GtkTreeStoreClass parent_class;
+};
+
+
+GType gtk_tree_model_ref_count_get_type (void) G_GNUC_CONST;
+GtkTreeModel *gtk_tree_model_ref_count_new (void);
+
+void gtk_tree_model_ref_count_dump (GtkTreeModelRefCount *ref_model);
+gboolean gtk_tree_model_ref_count_check_level (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *parent,
+ gint expected_ref_count,
+ gboolean recurse,
+ gboolean may_assert);
+gboolean gtk_tree_model_ref_count_check_node (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter,
+ gint expected_ref_count,
+ gboolean may_assert);
+
+/* A couple of helpers for the tests. Since this model will never be used
+ * outside of unit tests anyway, it is probably fine to have these here
+ * without namespacing.
+ */
+
+static inline void
+assert_entire_model_unreferenced (GtkTreeModelRefCount *ref_model)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, NULL, 0, TRUE, TRUE);
+}
+
+static inline void
+assert_root_level_unreferenced (GtkTreeModelRefCount *ref_model)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, NULL, 0, FALSE, TRUE);
+}
+
+static inline void
+assert_level_unreferenced (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, iter, 0, FALSE, TRUE);
+}
+
+static inline void
+assert_entire_model_referenced (GtkTreeModelRefCount *ref_model,
+ gint ref_count)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, NULL, ref_count, TRUE, TRUE);
+}
+
+static inline void
+assert_not_entire_model_referenced (GtkTreeModelRefCount *ref_model,
+ gint ref_count)
+{
+ g_assert_cmpint (gtk_tree_model_ref_count_check_level (ref_model, NULL,
+ ref_count,
+ TRUE, FALSE),
+ ==, FALSE);
+}
+
+static inline void
+assert_root_level_referenced (GtkTreeModelRefCount *ref_model,
+ gint ref_count)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, NULL, ref_count,
+ FALSE, TRUE);
+}
+
+static inline void
+assert_level_referenced (GtkTreeModelRefCount *ref_model,
+ gint ref_count,
+ GtkTreeIter *iter)
+{
+ gtk_tree_model_ref_count_check_level (ref_model, iter, ref_count,
+ FALSE, TRUE);
+}
+
+static inline void
+assert_node_ref_count (GtkTreeModelRefCount *ref_model,
+ GtkTreeIter *iter,
+ gint ref_count)
+{
+ gtk_tree_model_ref_count_check_node (ref_model, iter, ref_count, TRUE);
+}
+
+
+#endif /* __GTK_TREE_MODEL_REF_COUNT_H__ */
diff --git a/gtk/tests/liststore.c b/gtk/tests/liststore.c
index e710d9bad2..4efc2879d5 100644
--- a/gtk/tests/liststore.c
+++ b/gtk/tests/liststore.c
@@ -27,6 +27,8 @@
#include <gtk/gtk.h>
+#include "treemodel.h"
+
static inline gboolean
iters_equal (GtkTreeIter *a,
GtkTreeIter *b)
@@ -998,128 +1000,123 @@ list_store_test_iter_parent_invalid (ListStore *fixture,
/* main */
-int
-main (int argc,
- char **argv)
+void
+register_list_store_tests (void)
{
- gtk_test_init (&argc, &argv, NULL);
-
/* insertion */
- g_test_add_func ("/list-store/insert-high-values",
+ g_test_add_func ("/ListStore/insert-high-values",
list_store_test_insert_high_values);
- g_test_add_func ("/list-store/append",
+ g_test_add_func ("/ListStore/append",
list_store_test_append);
- g_test_add_func ("/list-store/prepend",
+ g_test_add_func ("/ListStore/prepend",
list_store_test_prepend);
- g_test_add_func ("/list-store/insert-after",
+ g_test_add_func ("/ListStore/insert-after",
list_store_test_insert_after);
- g_test_add_func ("/list-store/insert-after-NULL",
+ g_test_add_func ("/ListStore/insert-after-NULL",
list_store_test_insert_after_NULL);
- g_test_add_func ("/list-store/insert-before",
+ g_test_add_func ("/ListStore/insert-before",
list_store_test_insert_before);
- g_test_add_func ("/list-store/insert-before-NULL",
+ g_test_add_func ("/ListStore/insert-before-NULL",
list_store_test_insert_before_NULL);
/* setting values (FIXME) */
/* removal */
- g_test_add ("/list-store/remove-begin", ListStore, NULL,
+ g_test_add ("/ListStore/remove-begin", ListStore, NULL,
list_store_setup, list_store_test_remove_begin,
list_store_teardown);
- g_test_add ("/list-store/remove-middle", ListStore, NULL,
+ g_test_add ("/ListStore/remove-middle", ListStore, NULL,
list_store_setup, list_store_test_remove_middle,
list_store_teardown);
- g_test_add ("/list-store/remove-end", ListStore, NULL,
+ g_test_add ("/ListStore/remove-end", ListStore, NULL,
list_store_setup, list_store_test_remove_end,
list_store_teardown);
- g_test_add ("/list-store/clear", ListStore, NULL,
+ g_test_add ("/ListStore/clear", ListStore, NULL,
list_store_setup, list_store_test_clear,
list_store_teardown);
/* reordering */
- g_test_add ("/list-store/reorder", ListStore, NULL,
+ g_test_add ("/ListStore/reorder", ListStore, NULL,
list_store_setup, list_store_test_reorder,
list_store_teardown);
/* swapping */
- g_test_add ("/list-store/swap-begin", ListStore, NULL,
+ g_test_add ("/ListStore/swap-begin", ListStore, NULL,
list_store_setup, list_store_test_swap_begin,
list_store_teardown);
- g_test_add ("/list-store/swap-middle-next", ListStore, NULL,
+ g_test_add ("/ListStore/swap-middle-next", ListStore, NULL,
list_store_setup, list_store_test_swap_middle_next,
list_store_teardown);
- g_test_add ("/list-store/swap-middle-apart", ListStore, NULL,
+ g_test_add ("/ListStore/swap-middle-apart", ListStore, NULL,
list_store_setup, list_store_test_swap_middle_apart,
list_store_teardown);
- g_test_add ("/list-store/swap-end", ListStore, NULL,
+ g_test_add ("/ListStore/swap-end", ListStore, NULL,
list_store_setup, list_store_test_swap_end,
list_store_teardown);
- g_test_add_func ("/list-store/swap-single",
+ g_test_add_func ("/ListStore/swap-single",
list_store_test_swap_single);
/* moving */
- g_test_add ("/list-store/move-after-from-start", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-from-start", ListStore, NULL,
list_store_setup, list_store_test_move_after_from_start,
list_store_teardown);
- g_test_add ("/list-store/move-after-next", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-next", ListStore, NULL,
list_store_setup, list_store_test_move_after_next,
list_store_teardown);
- g_test_add ("/list-store/move-after-apart", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-apart", ListStore, NULL,
list_store_setup, list_store_test_move_after_apart,
list_store_teardown);
- g_test_add ("/list-store/move-after-end", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-end", ListStore, NULL,
list_store_setup, list_store_test_move_after_end,
list_store_teardown);
- g_test_add ("/list-store/move-after-from-end", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-from-end", ListStore, NULL,
list_store_setup, list_store_test_move_after_from_end,
list_store_teardown);
- g_test_add ("/list-store/move-after-change-ends", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-change-ends", ListStore, NULL,
list_store_setup, list_store_test_move_after_change_ends,
list_store_teardown);
- g_test_add ("/list-store/move-after-NULL", ListStore, NULL,
+ g_test_add ("/ListStore/move-after-NULL", ListStore, NULL,
list_store_setup, list_store_test_move_after_NULL,
list_store_teardown);
- g_test_add_func ("/list-store/move-after-single",
+ g_test_add_func ("/ListStore/move-after-single",
list_store_test_move_after_single);
- g_test_add ("/list-store/move-before-next", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-next", ListStore, NULL,
list_store_setup, list_store_test_move_before_next,
list_store_teardown);
- g_test_add ("/list-store/move-before-apart", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-apart", ListStore, NULL,
list_store_setup, list_store_test_move_before_apart,
list_store_teardown);
- g_test_add ("/list-store/move-before-to-start", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-to-start", ListStore, NULL,
list_store_setup, list_store_test_move_before_to_start,
list_store_teardown);
- g_test_add ("/list-store/move-before-from-end", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-from-end", ListStore, NULL,
list_store_setup, list_store_test_move_before_from_end,
list_store_teardown);
- g_test_add ("/list-store/move-before-change-ends", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-change-ends", ListStore, NULL,
list_store_setup, list_store_test_move_before_change_ends,
list_store_teardown);
- g_test_add ("/list-store/move-before-NULL", ListStore, NULL,
+ g_test_add ("/ListStore/move-before-NULL", ListStore, NULL,
list_store_setup, list_store_test_move_before_NULL,
list_store_teardown);
- g_test_add_func ("/list-store/move-before-single",
+ g_test_add_func ("/ListStore/move-before-single",
list_store_test_move_before_single);
/* iter invalidation */
- g_test_add ("/list-store/iter-prev-invalid", ListStore, NULL,
+ g_test_add ("/ListStore/iter-prev-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_previous_invalid,
list_store_teardown);
- g_test_add ("/list-store/iter-next-invalid", ListStore, NULL,
+ g_test_add ("/ListStore/iter-next-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_next_invalid,
list_store_teardown);
- g_test_add ("/list-store/iter-children-invalid", ListStore, NULL,
+ g_test_add ("/ListStore/iter-children-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_children_invalid,
list_store_teardown);
- g_test_add ("/list-store/iter-nth-child-invalid", ListStore, NULL,
+ g_test_add ("/ListStore/iter-nth-child-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_nth_child_invalid,
list_store_teardown);
- g_test_add ("/list-store/iter-parent-invalid", ListStore, NULL,
+ g_test_add ("/ListStore/iter-parent-invalid", ListStore, NULL,
list_store_setup, list_store_test_iter_parent_invalid,
list_store_teardown);
-
- return g_test_run ();
}
diff --git a/gtk/tests/modelrefcount.c b/gtk/tests/modelrefcount.c
new file mode 100644
index 0000000000..c701287927
--- /dev/null
+++ b/gtk/tests/modelrefcount.c
@@ -0,0 +1,978 @@
+/* GtkTreeModel ref counting tests
+ * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtktreemodelrefcount.h"
+#include "treemodel.h"
+
+/* And the tests themselves */
+
+static void
+test_list_no_reference (void)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ assert_root_level_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_list_reference_during_creation (void)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_root_level_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_list_reference_after_creation (void)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ assert_root_level_unreferenced (ref_model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_root_level_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_list_reference_reordered (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ assert_root_level_unreferenced (ref_model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter3, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter4, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter5, NULL);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &iter1, &iter5);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &iter3, &iter4);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_root_level_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+
+static void
+test_tree_no_reference (void)
+{
+ GtkTreeIter iter, child;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_during_creation (void)
+{
+ GtkTreeIter iter, child;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_not_entire_model_referenced (ref_model, 1);
+ assert_level_unreferenced (ref_model, &child);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_after_creation (void)
+{
+ GtkTreeIter iter, child;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_not_entire_model_referenced (ref_model, 1);
+ assert_level_unreferenced (ref_model, &child);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_reordered (void)
+{
+ GtkTreeIter parent;
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ assert_root_level_unreferenced (ref_model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, &parent);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, &parent);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter3, &parent);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter4, &parent);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter5, &parent);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &iter1, &iter5);
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_tree_store_move_after (GTK_TREE_STORE (model),
+ &iter3, &iter4);
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_expand_all (void)
+{
+ GtkTreeIter iter, child;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_not_entire_model_referenced (ref_model, 1);
+ assert_level_unreferenced (ref_model, &child);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_not_entire_model_referenced (ref_model, 1);
+ assert_level_unreferenced (ref_model, &child);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_collapse_all (void)
+{
+ GtkTreeIter iter, child;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &iter);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ tree_view = gtk_tree_view_new_with_model (model);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_not_entire_model_referenced (ref_model, 1);
+ assert_level_unreferenced (ref_model, &child);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_tree_reference_expand_collapse (void)
+{
+ GtkTreeIter parent1, parent2, child;
+ GtkTreePath *path1, *path2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child, &parent2);
+
+ path1 = gtk_tree_model_get_path (model, &parent1);
+ path2 = gtk_tree_model_get_path (model, &parent2);
+
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path1, FALSE);
+
+ assert_level_referenced (ref_model, 1, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path1);
+
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path2, FALSE);
+
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_referenced (ref_model, 1, &parent2);
+
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path2);
+
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path2, FALSE);
+
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_referenced (ref_model, 1, &parent2);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path1, FALSE);
+
+ assert_level_referenced (ref_model, 1, &parent1);
+ assert_level_referenced (ref_model, 1, &parent2);
+
+ gtk_tree_path_free (path1);
+ gtk_tree_path_free (path2);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_list (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+
+ assert_root_level_unreferenced (ref_model);
+
+ /* create and remove a row ref and check reference counts */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &iter2, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_root_level_unreferenced (ref_model);
+
+ /* the same, but then also with a tree view monitoring the model */
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ row_ref = gtk_tree_row_reference_new (model, path);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &iter2, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &iter2, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_root_level_unreferenced (ref_model);
+
+ gtk_tree_path_free (path);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_list_remove (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+
+ assert_root_level_unreferenced (ref_model);
+
+ /* test creating the row reference and then removing the node */
+ path = gtk_tree_path_new_from_indices (1, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &iter2, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter1);
+
+ assert_root_level_unreferenced (ref_model);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_root_level_unreferenced (ref_model);
+
+ /* test creating a row ref, removing another node and then removing
+ * the row ref node.
+ */
+ row_ref = gtk_tree_row_reference_new (model, path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &iter2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter0);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter2);
+
+ g_assert (!gtk_tree_model_get_iter_first (model, &iter0));
+
+ gtk_tree_row_reference_free (row_ref);
+
+ gtk_tree_path_free (path);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_tree (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreeIter child0, child1, child2;
+ GtkTreeIter grandchild0, grandchild1, grandchild2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref, *row_ref1;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child0, &iter0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild0, &child0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child1, &iter1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild1, &child1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child2, &iter2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild2, &child2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ /* create and remove a row ref and check reference counts */
+ path = gtk_tree_path_new_from_indices (1, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 1);
+ assert_node_ref_count (ref_model, &iter2, 0);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ /* again, with path 1:1 */
+ path = gtk_tree_path_new_from_indices (1, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 0);
+ assert_node_ref_count (ref_model, &iter2, 0);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ /* both row refs existent at once and also with a tree view monitoring
+ * the model
+ */
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ path = gtk_tree_path_new_from_indices (1, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 1);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ path = gtk_tree_path_new_from_indices (1, 0, -1);
+ row_ref1 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 3);
+ assert_node_ref_count (ref_model, &child1, 2);
+ assert_node_ref_count (ref_model, &grandchild1, 1);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 0);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 0);
+ assert_node_ref_count (ref_model, &iter2, 0);
+ assert_node_ref_count (ref_model, &child2, 0);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_row_reference_free (row_ref1);
+
+ assert_root_level_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_tree_remove (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreeIter child0, child1, child2;
+ GtkTreeIter grandchild0, grandchild1, grandchild2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref, *row_ref1, *row_ref2;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child0, &iter0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild0, &child0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child1, &iter1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild1, &child1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child2, &iter2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild2, &child2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ path = gtk_tree_path_new_from_indices (1, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (2, 0, -1);
+ row_ref1 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (2, -1);
+ row_ref2 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 1);
+ assert_node_ref_count (ref_model, &iter2, 2);
+ assert_node_ref_count (ref_model, &child2, 1);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandchild1);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 0);
+ assert_node_ref_count (ref_model, &child1, 0);
+ assert_node_ref_count (ref_model, &iter2, 2);
+ assert_node_ref_count (ref_model, &child2, 1);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &child2);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 0);
+ assert_node_ref_count (ref_model, &child1, 0);
+ assert_node_ref_count (ref_model, &iter2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ gtk_tree_row_reference_free (row_ref);
+ gtk_tree_row_reference_free (row_ref1);
+ gtk_tree_row_reference_free (row_ref2);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_tree_remove_ancestor (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreeIter child0, child1, child2;
+ GtkTreeIter grandchild0, grandchild1, grandchild2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref, *row_ref1;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child0, &iter0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild0, &child0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child1, &iter1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild1, &child1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child2, &iter2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild2, &child2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ path = gtk_tree_path_new_from_indices (1, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (2, 0, -1);
+ row_ref1 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &grandchild1, 1);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &child2, 1);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &child1);
+
+ assert_node_ref_count (ref_model, &iter0, 0);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 0);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &child2, 1);
+ assert_node_ref_count (ref_model, &grandchild2, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ gtk_tree_row_reference_free (row_ref);
+ gtk_tree_row_reference_free (row_ref1);
+
+ g_object_unref (ref_model);
+}
+
+static void
+test_row_reference_tree_expand (void)
+{
+ GtkTreeIter iter0, iter1, iter2;
+ GtkTreeIter child0, child1, child2;
+ GtkTreeIter grandchild0, grandchild1, grandchild2;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeRowReference *row_ref, *row_ref1, *row_ref2;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+ tree_view = gtk_tree_view_new_with_model (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter0, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child0, &iter0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild0, &child0);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child1, &iter1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild1, &child1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &child2, &iter2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandchild2, &child2);
+
+ assert_root_level_referenced (ref_model, 1);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ path = gtk_tree_path_new_from_indices (1, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (2, 0, -1);
+ row_ref1 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ path = gtk_tree_path_new_from_indices (2, -1);
+ row_ref2 = gtk_tree_row_reference_new (model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 1);
+ assert_node_ref_count (ref_model, &grandchild0, 1);
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &child1, 2);
+ assert_node_ref_count (ref_model, &grandchild1, 2);
+ assert_node_ref_count (ref_model, &iter2, 3);
+ assert_node_ref_count (ref_model, &child2, 2);
+ assert_node_ref_count (ref_model, &grandchild2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandchild1);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 1);
+ assert_node_ref_count (ref_model, &grandchild0, 1);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &iter2, 3);
+ assert_node_ref_count (ref_model, &child2, 2);
+ assert_node_ref_count (ref_model, &grandchild2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &child2);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 1);
+ assert_node_ref_count (ref_model, &grandchild0, 1);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 1);
+ assert_node_ref_count (ref_model, &iter2, 2);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 0);
+ assert_node_ref_count (ref_model, &iter2, 2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter2);
+
+ assert_node_ref_count (ref_model, &iter0, 1);
+ assert_node_ref_count (ref_model, &child0, 0);
+ assert_node_ref_count (ref_model, &grandchild0, 0);
+ assert_node_ref_count (ref_model, &iter1, 1);
+ assert_node_ref_count (ref_model, &child1, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+ gtk_tree_row_reference_free (row_ref1);
+ gtk_tree_row_reference_free (row_ref2);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (ref_model);
+}
+
+void
+register_model_ref_count_tests (void)
+{
+ /* lists (though based on GtkTreeStore) */
+ g_test_add_func ("/TreeModel/ref-count/list/no-reference",
+ test_list_no_reference);
+ g_test_add_func ("/TreeModel/ref-count/list/reference-during-creation",
+ test_list_reference_during_creation);
+ g_test_add_func ("/TreeModel/ref-count/list/reference-after-creation",
+ test_list_reference_after_creation);
+ g_test_add_func ("/TreeModel/ref-count/list/reference-reordered",
+ test_list_reference_reordered);
+
+ /* trees */
+ g_test_add_func ("/TreeModel/ref-count/tree/no-reference",
+ test_tree_no_reference);
+ g_test_add_func ("/TreeModel/ref-count/tree/reference-during-creation",
+ test_tree_reference_during_creation);
+ g_test_add_func ("/TreeModel/ref-count/tree/reference-after-creation",
+ test_tree_reference_after_creation);
+ g_test_add_func ("/TreeModel/ref-count/tree/expand-all",
+ test_tree_reference_expand_all);
+ g_test_add_func ("/TreeModel/ref-count/tree/collapse-all",
+ test_tree_reference_collapse_all);
+ g_test_add_func ("/TreeModel/ref-count/tree/expand-collapse",
+ test_tree_reference_expand_collapse);
+ g_test_add_func ("/TreeModel/ref-count/tree/reference-reordered",
+ test_tree_reference_reordered);
+
+ /* row references */
+ g_test_add_func ("/TreeModel/ref-count/row-reference/list",
+ test_row_reference_list);
+ g_test_add_func ("/TreeModel/ref-count/row-reference/list-remove",
+ test_row_reference_list_remove);
+ g_test_add_func ("/TreeModel/ref-count/row-reference/tree",
+ test_row_reference_tree);
+ g_test_add_func ("/TreeModel/ref-count/row-reference/tree-remove",
+ test_row_reference_tree_remove);
+ g_test_add_func ("/TreeModel/ref-count/row-reference/tree-remove-ancestor",
+ test_row_reference_tree_remove_ancestor);
+ g_test_add_func ("/TreeModel/ref-count/row-reference/tree-expand",
+ test_row_reference_tree_expand);
+}
diff --git a/gtk/tests/sortmodel.c b/gtk/tests/sortmodel.c
new file mode 100644
index 0000000000..a58359d6d1
--- /dev/null
+++ b/gtk/tests/sortmodel.c
@@ -0,0 +1,1151 @@
+/* Extensive GtkTreeModelSort tests.
+ * Copyright (C) 2009,2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include "treemodel.h"
+#include "gtktreemodelrefcount.h"
+
+
+static void
+ref_count_single_level (void)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+
+ assert_root_level_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (sort_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_two_levels (void)
+{
+ GtkTreeIter parent1, parent2, iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter, 1);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &iter, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (sort_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_three_levels (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_path_append_index (path, 1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_path_up (path);
+ gtk_tree_view_collapse_row (GTK_TREE_VIEW (tree_view), path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (sort_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_delete_row (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ assert_root_level_referenced (ref_model, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_level_unreferenced (ref_model, &parent1);
+ assert_level_unreferenced (ref_model, &parent2);
+
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 1);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &iter_parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 2);
+ assert_level_referenced (ref_model, 1, &parent1);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_level_referenced (ref_model, 1, &parent2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_level_referenced (ref_model, 1, &parent2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+
+ gtk_widget_destroy (tree_view);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (sort_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_cleanup (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ gtk_widget_destroy (tree_view);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (sort_model));
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (sort_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_row_ref (void)
+{
+ GtkTreeIter grandparent1, grandparent2, parent1, parent2;
+ GtkTreeIter iter_parent1, iter_parent2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ GtkTreePath *path;
+ GtkTreeRowReference *row_ref;
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ /* + grandparent1
+ * + grandparent2
+ * + parent1
+ * + iter_parent1
+ * + parent2
+ * + iter_parent2
+ * + iter_parent2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent1, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent1, &parent1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_parent2, &parent2);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+ row_ref = gtk_tree_row_reference_new (sort_model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ /* Referenced because the node is visible, its child level is built
+ * and referenced by the row ref.
+ */
+ assert_node_ref_count (ref_model, &grandparent2, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ /* Referenced by the row ref and because its child level is built. */
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 0);
+
+ path = gtk_tree_path_new_from_indices (1, 1, 1, -1);
+ row_ref = gtk_tree_row_reference_new (sort_model, path);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ /* Referenced because the node is visible, its child level is built
+ * and referenced by the row ref.
+ */
+ assert_node_ref_count (ref_model, &grandparent2, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ /* Referenced by the row ref and because its child level is built. */
+ assert_node_ref_count (ref_model, &parent2, 2);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent2, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+ gtk_tree_row_reference_free (row_ref);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &iter_parent1, 0);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_reorder_single (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeIter siter1, siter2, siter3, siter4, siter5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_INT };
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
+
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter1, NULL, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter2, NULL, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter3, NULL, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter4, NULL, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter5, NULL, 4,
+ 0, 60, -1);
+
+ assert_root_level_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter1, &iter1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter2, &iter2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter3, &iter3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter4, &iter4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter5, &iter5);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter1);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter1);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter5);
+
+ assert_node_ref_count (ref_model, &iter1, 3);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 4);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 2);
+
+ /* Sort */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+
+ assert_node_ref_count (ref_model, &iter1, 3);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 4);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 2);
+
+ /* Re-translate the iters after sorting */
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter1, &iter1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter2, &iter2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter3, &iter3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter4, &iter4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter5, &iter5);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter1);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter1);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter5);
+
+ assert_entire_model_referenced (ref_model, 1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_reorder_two (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeIter citer1, citer2, citer3, citer4, citer5;
+ GtkTreeIter siter1, siter2, siter3, siter4, siter5;
+ GtkTreeIter sciter1, sciter2, sciter3, sciter4, sciter5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_INT };
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
+
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter1, NULL, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter2, NULL, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter3, NULL, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter4, NULL, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter5, NULL, 4,
+ 0, 60, -1);
+
+ /* Child level */
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer1, &iter1, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer2, &iter1, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer3, &iter1, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer4, &iter1, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer5, &iter1, 4,
+ 0, 60, -1);
+
+ assert_root_level_unreferenced (ref_model);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 1);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 1);
+
+ assert_level_referenced (ref_model, 1, &iter1);
+
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter1, &iter1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter2, &iter2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter3, &iter3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter4, &iter4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter5, &iter5);
+
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter1, &citer1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter2, &citer2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter3, &citer3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter4, &citer4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter5, &citer5);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter1);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter1);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter3);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &siter5);
+
+ assert_node_ref_count (ref_model, &iter1, 4);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 4);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 2);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter3);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter3);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+
+ gtk_tree_model_ref_node (GTK_TREE_MODEL (sort_model), &sciter1);
+
+ assert_node_ref_count (ref_model, &citer1, 2);
+ assert_node_ref_count (ref_model, &citer2, 1);
+ assert_node_ref_count (ref_model, &citer3, 3);
+ assert_node_ref_count (ref_model, &citer4, 1);
+ assert_node_ref_count (ref_model, &citer5, 4);
+
+ /* Sort */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+
+ assert_node_ref_count (ref_model, &iter1, 4);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 4);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 2);
+
+ assert_node_ref_count (ref_model, &citer1, 2);
+ assert_node_ref_count (ref_model, &citer2, 1);
+ assert_node_ref_count (ref_model, &citer3, 3);
+ assert_node_ref_count (ref_model, &citer4, 1);
+ assert_node_ref_count (ref_model, &citer5, 4);
+
+ /* Re-translate the iters after sorting */
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter1, &iter1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter2, &iter2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter3, &iter3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter4, &iter4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &siter5, &iter5);
+
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter1, &citer1);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter2, &citer2);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter3, &citer3);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter4, &citer4);
+ gtk_tree_model_sort_convert_child_iter_to_iter (GTK_TREE_MODEL_SORT (sort_model), &sciter5, &citer5);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter1);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter1);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter3);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &siter5);
+
+ assert_node_ref_count (ref_model, &iter1, 2);
+ assert_node_ref_count (ref_model, &iter2, 1);
+ assert_node_ref_count (ref_model, &iter3, 1);
+ assert_node_ref_count (ref_model, &iter4, 1);
+ assert_node_ref_count (ref_model, &iter5, 1);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter3);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter3);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter5);
+
+ gtk_tree_model_unref_node (GTK_TREE_MODEL (sort_model), &sciter1);
+
+ assert_level_referenced (ref_model, 1, &iter1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+check_sort_order (GtkTreeModel *sort_model,
+ GtkSortType sort_order,
+ const char *parent_path)
+{
+ int prev_value;
+ GtkTreeIter siter;
+
+ if (!parent_path)
+ gtk_tree_model_get_iter_first (sort_model, &siter);
+ else
+ {
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_string (parent_path);
+ gtk_tree_path_append_index (path, 0);
+
+ gtk_tree_model_get_iter (sort_model, &siter, path);
+
+ gtk_tree_path_free (path);
+ }
+
+ if (sort_order == GTK_SORT_ASCENDING)
+ prev_value = -1;
+ else
+ prev_value = INT_MAX;
+
+ do
+ {
+ int value;
+
+ gtk_tree_model_get (sort_model, &siter, 0, &value, -1);
+ if (sort_order == GTK_SORT_ASCENDING)
+ g_assert (prev_value <= value);
+ else
+ g_assert (prev_value >= value);
+
+ prev_value = value;
+ }
+ while (gtk_tree_model_iter_next (sort_model, &siter));
+}
+
+static void
+rows_reordered_single_level (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreePath *path;
+ GType column_types[] = { G_TYPE_INT };
+ int order[][5] =
+ {
+ { 2, 3, 0, 1, 4 },
+ { 4, 3, 2, 1, 0 },
+ { 2, 1, 4, 3, 0 }
+ };
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
+
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter1, NULL, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter2, NULL, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter3, NULL, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter4, NULL, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter5, NULL, 4,
+ 0, 60, -1);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ monitor = signal_monitor_new (sort_model);
+
+ /* Sort */
+ path = gtk_tree_path_new ();
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[0], 5);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+ signal_monitor_assert_is_empty (monitor);
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, NULL);
+
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[1], 5);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_DESCENDING);
+ signal_monitor_assert_is_empty (monitor);
+ check_sort_order (sort_model, GTK_SORT_DESCENDING, NULL);
+
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[2], 5);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+ signal_monitor_assert_is_empty (monitor);
+
+ gtk_tree_path_free (path);
+ signal_monitor_free (monitor);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+rows_reordered_two_levels (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5;
+ GtkTreeIter citer1, citer2, citer3, citer4, citer5;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreePath *path, *child_path;
+ GType column_types[] = { G_TYPE_INT };
+ int order[][5] =
+ {
+ { 2, 3, 0, 1, 4 },
+ { 4, 3, 2, 1, 0 },
+ { 2, 1, 4, 3, 0 }
+ };
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
+
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter1, NULL, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter2, NULL, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter3, NULL, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter4, NULL, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter5, NULL, 4,
+ 0, 60, -1);
+
+ /* Child level */
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer1, &iter1, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer2, &iter1, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer3, &iter1, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer4, &iter1, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &citer5, &iter1, 4,
+ 0, 60, -1);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ monitor = signal_monitor_new (sort_model);
+
+ /* Sort */
+ path = gtk_tree_path_new ();
+ child_path = gtk_tree_path_new_from_indices (2, -1);
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[0], 5);
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ child_path, order[0], 5);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+ signal_monitor_assert_is_empty (monitor);
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, NULL);
+ /* The parent node of the child level moved due to sorting */
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, "2");
+
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[1], 5);
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ child_path, order[1], 5);
+ gtk_tree_path_free (child_path);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_DESCENDING);
+ signal_monitor_assert_is_empty (monitor);
+ check_sort_order (sort_model, GTK_SORT_DESCENDING, NULL);
+ /* The parent node of the child level moved due to sorting */
+ check_sort_order (sort_model, GTK_SORT_DESCENDING, "2");
+
+ child_path = gtk_tree_path_new_from_indices (0, -1);
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order[2], 5);
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ child_path, order[2], 5);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
+ GTK_SORT_ASCENDING);
+ signal_monitor_assert_is_empty (monitor);
+
+ gtk_tree_path_free (path);
+ gtk_tree_path_free (child_path);
+ signal_monitor_free (monitor);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ g_object_unref (ref_model);
+}
+
+static void
+sorted_insert (void)
+{
+ GtkTreeIter iter1, iter2, iter3, iter4, iter5, new_iter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *sort_model;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreePath *path;
+ GType column_types[] = { G_TYPE_INT };
+ int order0[] = { 1, 2, 3, 0, 4, 5, 6 };
+
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
+
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
+
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter1, NULL, 0,
+ 0, 30, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter2, NULL, 1,
+ 0, 40, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter3, NULL, 2,
+ 0, 10, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter4, NULL, 3,
+ 0, 20, -1);
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &iter5, NULL, 4,
+ 0, 60, -1);
+
+ sort_model = gtk_tree_model_sort_new_with_model (model);
+ tree_view = gtk_tree_view_new_with_model (sort_model);
+
+ /* Sort */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, NULL);
+
+ monitor = signal_monitor_new (sort_model);
+
+ /* Insert a new item */
+ signal_monitor_append_signal (monitor, ROW_INSERTED, "4");
+ gtk_tree_store_insert_with_values (GTK_TREE_STORE (model), &new_iter, NULL,
+ 5, 0, 50, -1);
+ signal_monitor_assert_is_empty (monitor);
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, NULL);
+
+ /* Sort the tree sort and append a new item */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
+ 0, GTK_SORT_ASCENDING);
+ check_sort_order (model, GTK_SORT_ASCENDING, NULL);
+
+ path = gtk_tree_path_new ();
+ signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal_reordered (monitor,
+ ROWS_REORDERED,
+ path, order0, 7);
+ signal_monitor_append_signal (monitor, ROW_CHANGED, "3");
+ gtk_tree_store_append (GTK_TREE_STORE (model), &new_iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &new_iter, 0, 35, -1);
+ check_sort_order (model, GTK_SORT_ASCENDING, NULL);
+ check_sort_order (sort_model, GTK_SORT_ASCENDING, NULL);
+
+ gtk_tree_path_free (path);
+ signal_monitor_free (monitor);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (sort_model);
+
+ g_object_unref (ref_model);
+}
+
+
+static void
+specific_bug_300089 (void)
+{
+ /* Test case for GNOME Bugzilla bug 300089. Written by
+ * Matthias Clasen.
+ */
+ GtkTreeModel *sort_model, *child_model;
+ GtkTreePath *path;
+ GtkTreeIter iter, iter2, sort_iter;
+
+ g_test_bug ("300089");
+
+ child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "B", -1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "D", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter2, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter2, 0, "E", -1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (child_model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "C", -1);
+
+
+ sort_model = GTK_TREE_MODEL (gtk_tree_model_sort_new_with_model (child_model));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
+
+ path = gtk_tree_path_new_from_indices (1, 1, -1);
+
+ /* make sure a level is constructed */
+ gtk_tree_model_get_iter (sort_model, &sort_iter, path);
+
+ /* change the "E" row in a way that causes it to change position */
+ gtk_tree_model_get_iter (child_model, &iter, path);
+ gtk_tree_store_set (GTK_TREE_STORE (child_model), &iter, 0, "A", -1);
+
+ gtk_tree_path_free (path);
+}
+
+static void
+specific_bug_364946 (void)
+{
+ /* This is a test case for GNOME Bugzilla bug 364946. It was written
+ * by Andreas Koehler.
+ */
+ GtkTreeStore *store;
+ GtkTreeIter a, aa, aaa, aab, iter;
+ GtkTreeModel *s_model;
+
+ g_test_bug ("364946");
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+ gtk_tree_store_append (store, &a, NULL);
+ gtk_tree_store_set (store, &a, 0, "0", -1);
+
+ gtk_tree_store_append (store, &aa, &a);
+ gtk_tree_store_set (store, &aa, 0, "0:0", -1);
+
+ gtk_tree_store_append (store, &aaa, &aa);
+ gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
+
+ gtk_tree_store_append (store, &aab, &aa);
+ gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
+
+ s_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (s_model), 0,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
+
+ gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
+ gtk_tree_store_remove (store, &aaa);
+ gtk_tree_store_remove (store, &aab);
+
+ gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
+}
+
+/* main */
+
+void
+register_sort_model_tests (void)
+{
+ g_test_add_func ("/TreeModelSort/ref-count/single-level",
+ ref_count_single_level);
+ g_test_add_func ("/TreeModelSort/ref-count/two-levels",
+ ref_count_two_levels);
+ g_test_add_func ("/TreeModelSort/ref-count/three-levels",
+ ref_count_three_levels);
+ g_test_add_func ("/TreeModelSort/ref-count/delete-row",
+ ref_count_delete_row);
+ g_test_add_func ("/TreeModelSort/ref-count/cleanup",
+ ref_count_cleanup);
+ g_test_add_func ("/TreeModelSort/ref-count/row-ref",
+ ref_count_row_ref);
+ g_test_add_func ("/TreeModelSort/ref-count/reorder/single-level",
+ ref_count_reorder_single);
+ g_test_add_func ("/TreeModelSort/ref-count/reorder/two-levels",
+ ref_count_reorder_two);
+
+ g_test_add_func ("/TreeModelSort/rows-reordered/single-level",
+ rows_reordered_single_level);
+ g_test_add_func ("/TreeModelSort/rows-reordered/two-levels",
+ rows_reordered_two_levels);
+ g_test_add_func ("/TreeModelSort/sorted-insert",
+ sorted_insert);
+
+ g_test_add_func ("/TreeModelSort/specific/bug-300089",
+ specific_bug_300089);
+ g_test_add_func ("/TreeModelSort/specific/bug-364946",
+ specific_bug_364946);
+}
diff --git a/gtk/tests/treemodel.c b/gtk/tests/treemodel.c
new file mode 100644
index 0000000000..97bbc14b27
--- /dev/null
+++ b/gtk/tests/treemodel.c
@@ -0,0 +1,347 @@
+/* Main wrapper for TreeModel test suite.
+ * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include "treemodel.h"
+
+int
+main (int argc,
+ char **argv)
+{
+ gtk_test_init (&argc, &argv, NULL);
+
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ register_list_store_tests ();
+ register_tree_store_tests ();
+ register_model_ref_count_tests ();
+ register_sort_model_tests ();
+ register_filter_model_tests ();
+
+ return g_test_run ();
+}
+
+/*
+ * Signal monitor
+ */
+
+static const char *
+signal_name_to_string (SignalName signal)
+{
+ switch (signal)
+ {
+ case ROW_INSERTED:
+ return "row-inserted";
+
+ case ROW_DELETED:
+ return "row-deleted";
+
+ case ROW_CHANGED:
+ return "row-changed";
+
+ case ROW_HAS_CHILD_TOGGLED:
+ return "row-has-child-toggled";
+
+ case ROWS_REORDERED:
+ return "rows-reordered";
+
+ default:
+ /* Fall through */
+ break;
+ }
+
+ return "(unknown)";
+}
+
+typedef struct
+{
+ SignalName signal;
+ GtkTreePath *path;
+
+ /* For rows-reordered */
+ int *new_order;
+ int len;
+}
+Signal;
+
+
+static Signal *
+signal_new (SignalName signal, GtkTreePath *path)
+{
+ Signal *s;
+
+ s = g_new0 (Signal, 1);
+ s->signal = signal;
+ s->path = gtk_tree_path_copy (path);
+ s->new_order = NULL;
+
+ return s;
+}
+
+static Signal *
+signal_new_with_order (SignalName signal, GtkTreePath *path,
+ int *new_order, int len)
+{
+ Signal *s = signal_new (signal, path);
+
+ s->new_order = new_order;
+ s->len = len;
+
+ return s;
+}
+
+static void
+signal_free (Signal *s)
+{
+ if (s->path)
+ gtk_tree_path_free (s->path);
+
+ g_free (s);
+}
+
+
+struct _SignalMonitor
+{
+ GQueue *queue;
+ GtkTreeModel *client;
+ gulong signal_ids[LAST_SIGNAL];
+};
+
+
+static void
+signal_monitor_generic_handler (SignalMonitor *m,
+ SignalName signal,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ GtkTreePath *path,
+ int *new_order)
+{
+ Signal *s;
+
+ if (g_queue_is_empty (m->queue))
+ {
+ gchar *path_str;
+
+ path_str = gtk_tree_path_to_string (path);
+ g_error ("Signal queue empty, got signal %s path %s\n",
+ signal_name_to_string (signal), path_str);
+ g_free (path_str);
+
+ g_assert_not_reached ();
+ }
+
+ if (m->client != model)
+ {
+ g_error ("Model mismatch; expected %p, got %p\n",
+ m->client, model);
+ g_assert_not_reached ();
+ }
+
+ s = g_queue_peek_tail (m->queue);
+
+#if 0
+ /* For debugging: output signals that are coming in. Leaks memory. */
+ g_print ("signal=%s path=%s\n", signal_name_to_string (signal),
+ gtk_tree_path_to_string (path));
+#endif
+
+ if (s->signal != signal ||
+ (gtk_tree_path_get_depth (s->path) == 0 &&
+ gtk_tree_path_get_depth (path) != 0) ||
+ (gtk_tree_path_get_depth (s->path) != 0 &&
+ gtk_tree_path_compare (s->path, path) != 0))
+ {
+ gchar *path_str, *s_path_str;
+
+ s_path_str = gtk_tree_path_to_string (s->path);
+ path_str = gtk_tree_path_to_string (path);
+
+ g_error ("Signals don't match; expected signal %s path %s, got signal %s path %s\n",
+ signal_name_to_string (s->signal), s_path_str,
+ signal_name_to_string (signal), path_str);
+
+ g_free (s_path_str);
+ g_free (path_str);
+
+ g_assert_not_reached ();
+ }
+
+ if (signal == ROWS_REORDERED && s->new_order != NULL)
+ {
+ int i, len;
+
+ g_assert (new_order != NULL);
+
+ len = gtk_tree_model_iter_n_children (model, iter);
+ g_assert (s->len == len);
+
+ for (i = 0; i < len; i++)
+ g_assert (s->new_order[i] == new_order[i]);
+ }
+
+ s = g_queue_pop_tail (m->queue);
+
+ signal_free (s);
+}
+
+static void
+signal_monitor_row_inserted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_INSERTED,
+ model, iter, path, NULL);
+}
+
+static void
+signal_monitor_row_deleted (GtkTreeModel *model,
+ GtkTreePath *path,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_DELETED,
+ model, NULL, path, NULL);
+}
+
+static void
+signal_monitor_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_CHANGED,
+ model, iter, path, NULL);
+}
+
+static void
+signal_monitor_row_has_child_toggled (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROW_HAS_CHILD_TOGGLED,
+ model, iter, path, NULL);
+}
+
+static void
+signal_monitor_rows_reordered (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gint *new_order,
+ gpointer data)
+{
+ signal_monitor_generic_handler (data, ROWS_REORDERED,
+ model, iter, path, new_order);
+}
+
+SignalMonitor *
+signal_monitor_new (GtkTreeModel *client)
+{
+ SignalMonitor *m;
+
+ m = g_new0 (SignalMonitor, 1);
+ m->client = g_object_ref (client);
+ m->queue = g_queue_new ();
+
+ m->signal_ids[ROW_INSERTED] = g_signal_connect (client,
+ "row-inserted",
+ G_CALLBACK (signal_monitor_row_inserted),
+ m);
+ m->signal_ids[ROW_DELETED] = g_signal_connect (client,
+ "row-deleted",
+ G_CALLBACK (signal_monitor_row_deleted),
+ m);
+ m->signal_ids[ROW_CHANGED] = g_signal_connect (client,
+ "row-changed",
+ G_CALLBACK (signal_monitor_row_changed),
+ m);
+ m->signal_ids[ROW_HAS_CHILD_TOGGLED] = g_signal_connect (client,
+ "row-has-child-toggled",
+ G_CALLBACK (signal_monitor_row_has_child_toggled),
+ m);
+ m->signal_ids[ROWS_REORDERED] = g_signal_connect (client,
+ "rows-reordered",
+ G_CALLBACK (signal_monitor_rows_reordered),
+ m);
+
+ return m;
+}
+
+void
+signal_monitor_free (SignalMonitor *m)
+{
+ int i;
+
+ for (i = 0; i < LAST_SIGNAL; i++)
+ g_signal_handler_disconnect (m->client, m->signal_ids[i]);
+
+ g_object_unref (m->client);
+
+ if (m->queue)
+ g_queue_free (m->queue);
+
+ g_free (m);
+}
+
+void
+signal_monitor_assert_is_empty (SignalMonitor *m)
+{
+ g_assert (g_queue_is_empty (m->queue));
+}
+
+void
+signal_monitor_append_signal_path (SignalMonitor *m,
+ SignalName signal,
+ GtkTreePath *path)
+{
+ Signal *s;
+
+ s = signal_new (signal, path);
+ g_queue_push_head (m->queue, s);
+}
+
+void
+signal_monitor_append_signal_reordered (SignalMonitor *m,
+ SignalName signal,
+ GtkTreePath *path,
+ int *new_order,
+ int len)
+{
+ Signal *s;
+
+ s = signal_new_with_order (signal, path, new_order, len);
+ g_queue_push_head (m->queue, s);
+}
+
+void
+signal_monitor_append_signal (SignalMonitor *m,
+ SignalName signal,
+ const gchar *path_string)
+{
+ Signal *s;
+ GtkTreePath *path;
+
+ path = gtk_tree_path_new_from_string (path_string);
+
+ s = signal_new (signal, path);
+ g_queue_push_head (m->queue, s);
+
+ gtk_tree_path_free (path);
+}
diff --git a/gtk/tests/treemodel.h b/gtk/tests/treemodel.h
new file mode 100644
index 0000000000..1478f470b5
--- /dev/null
+++ b/gtk/tests/treemodel.h
@@ -0,0 +1,60 @@
+/* Main wrapper for TreeModel test suite.
+ * Copyright (C) 2011 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+void register_list_store_tests ();
+void register_tree_store_tests ();
+void register_sort_model_tests ();
+void register_filter_model_tests ();
+void register_model_ref_count_tests ();
+
+/*
+ * Signal monitor
+ */
+typedef struct _SignalMonitor SignalMonitor;
+typedef enum _SignalName SignalName;
+
+enum _SignalName
+{
+ ROW_INSERTED,
+ ROW_DELETED,
+ ROW_CHANGED,
+ ROW_HAS_CHILD_TOGGLED,
+ ROWS_REORDERED,
+ LAST_SIGNAL
+};
+
+
+SignalMonitor *signal_monitor_new (GtkTreeModel *client);
+void signal_monitor_free (SignalMonitor *m);
+
+void signal_monitor_assert_is_empty (SignalMonitor *m);
+
+void signal_monitor_append_signal_reordered (SignalMonitor *m,
+ SignalName signal,
+ GtkTreePath *path,
+ int *new_order,
+ int len);
+void signal_monitor_append_signal_path (SignalMonitor *m,
+ SignalName signal,
+ GtkTreePath *path);
+void signal_monitor_append_signal (SignalMonitor *m,
+ SignalName signal,
+ const gchar *path_string);
diff --git a/gtk/tests/treestore.c b/gtk/tests/treestore.c
index 663eaaf580..9d0c4c3d4e 100644
--- a/gtk/tests/treestore.c
+++ b/gtk/tests/treestore.c
@@ -998,131 +998,162 @@ tree_store_test_iter_parent_invalid (TreeStore *fixture,
g_assert (iter.stamp == 0);
}
+/* specific bugs */
+static void
+specific_bug_77977 (void)
+{
+ GtkTreeStore *tree_store;
+ GtkTreeIter iter1, iter2, iter3;
+ GtkTreePath *path;
+ GtkTreeRowReference *row_ref;
+
+ /* Stripped down version of test case for bug 77977 by Damon Chaplin */
+
+ g_test_bug ("77977");
+
+ tree_store = gtk_tree_store_new (1, G_TYPE_STRING);
+
+ gtk_tree_store_append (tree_store, &iter1, NULL);
+ gtk_tree_store_set (tree_store, &iter1, 0, "Window1", -1);
+
+ gtk_tree_store_append (tree_store, &iter2, &iter1);
+ gtk_tree_store_set (tree_store, &iter2, 0, "Table1", -1);
+
+ gtk_tree_store_append (tree_store, &iter3, &iter2);
+ gtk_tree_store_set (tree_store, &iter3, 0, "Button1", -1);
+
+ path = gtk_tree_path_new_from_indices (0, 0, 0, -1);
+ row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (tree_store), path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_store_remove (tree_store, &iter1);
+
+ gtk_tree_row_reference_free (row_ref);
+ g_object_unref (tree_store);
+}
/* main */
-int
-main (int argc,
- char **argv)
+void
+register_tree_store_tests (void)
{
- gtk_test_init (&argc, &argv, NULL);
-
/* insertion */
- g_test_add_func ("/tree-store/insert-high-values",
+ g_test_add_func ("/TreeStore/insert-high-values",
tree_store_test_insert_high_values);
- g_test_add_func ("/tree-store/append",
+ g_test_add_func ("/TreeStore/append",
tree_store_test_append);
- g_test_add_func ("/tree-store/prepend",
+ g_test_add_func ("/TreeStore/prepend",
tree_store_test_prepend);
- g_test_add_func ("/tree-store/insert-after",
+ g_test_add_func ("/TreeStore/insert-after",
tree_store_test_insert_after);
- g_test_add_func ("/tree-store/insert-after-NULL",
+ g_test_add_func ("/TreeStore/insert-after-NULL",
tree_store_test_insert_after_NULL);
- g_test_add_func ("/tree-store/insert-before",
+ g_test_add_func ("/TreeStore/insert-before",
tree_store_test_insert_before);
- g_test_add_func ("/tree-store/insert-before-NULL",
+ g_test_add_func ("/TreeStore/insert-before-NULL",
tree_store_test_insert_before_NULL);
/* setting values (FIXME) */
/* removal */
- g_test_add ("/tree-store/remove-begin", TreeStore, NULL,
+ g_test_add ("/TreeStore/remove-begin", TreeStore, NULL,
tree_store_setup, tree_store_test_remove_begin,
tree_store_teardown);
- g_test_add ("/tree-store/remove-middle", TreeStore, NULL,
+ g_test_add ("/TreeStore/remove-middle", TreeStore, NULL,
tree_store_setup, tree_store_test_remove_middle,
tree_store_teardown);
- g_test_add ("/tree-store/remove-end", TreeStore, NULL,
+ g_test_add ("/TreeStore/remove-end", TreeStore, NULL,
tree_store_setup, tree_store_test_remove_end,
tree_store_teardown);
- g_test_add ("/tree-store/clear", TreeStore, NULL,
+ g_test_add ("/TreeStore/clear", TreeStore, NULL,
tree_store_setup, tree_store_test_clear,
tree_store_teardown);
/* reordering */
- g_test_add ("/tree-store/reorder", TreeStore, NULL,
+ g_test_add ("/TreeStore/reorder", TreeStore, NULL,
tree_store_setup, tree_store_test_reorder,
tree_store_teardown);
/* swapping */
- g_test_add ("/tree-store/swap-begin", TreeStore, NULL,
+ g_test_add ("/TreeStore/swap-begin", TreeStore, NULL,
tree_store_setup, tree_store_test_swap_begin,
tree_store_teardown);
- g_test_add ("/tree-store/swap-middle-next", TreeStore, NULL,
+ g_test_add ("/TreeStore/swap-middle-next", TreeStore, NULL,
tree_store_setup, tree_store_test_swap_middle_next,
tree_store_teardown);
- g_test_add ("/tree-store/swap-middle-apart", TreeStore, NULL,
+ g_test_add ("/TreeStore/swap-middle-apart", TreeStore, NULL,
tree_store_setup, tree_store_test_swap_middle_apart,
tree_store_teardown);
- g_test_add ("/tree-store/swap-end", TreeStore, NULL,
+ g_test_add ("/TreeStore/swap-end", TreeStore, NULL,
tree_store_setup, tree_store_test_swap_end,
tree_store_teardown);
- g_test_add_func ("/tree-store/swap-single",
+ g_test_add_func ("/TreeStore/swap-single",
tree_store_test_swap_single);
/* moving */
- g_test_add ("/tree-store/move-after-from-start", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-from-start", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_from_start,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-next", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-next", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_next,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-apart", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-apart", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_apart,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-end", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-end", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_end,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-from-end", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-from-end", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_from_end,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-change-ends", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-change-ends", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_change_ends,
tree_store_teardown);
- g_test_add ("/tree-store/move-after-NULL", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-after-NULL", TreeStore, NULL,
tree_store_setup, tree_store_test_move_after_NULL,
tree_store_teardown);
- g_test_add_func ("/tree-store/move-after-single",
+ g_test_add_func ("/TreeStore/move-after-single",
tree_store_test_move_after_single);
- g_test_add ("/tree-store/move-before-next", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-next", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_next,
tree_store_teardown);
- g_test_add ("/tree-store/move-before-apart", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-apart", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_apart,
tree_store_teardown);
- g_test_add ("/tree-store/move-before-to-start", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-to-start", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_to_start,
tree_store_teardown);
- g_test_add ("/tree-store/move-before-from-end", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-from-end", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_from_end,
tree_store_teardown);
- g_test_add ("/tree-store/move-before-change-ends", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-change-ends", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_change_ends,
tree_store_teardown);
- g_test_add ("/tree-store/move-before-NULL", TreeStore, NULL,
+ g_test_add ("/TreeStore/move-before-NULL", TreeStore, NULL,
tree_store_setup, tree_store_test_move_before_NULL,
tree_store_teardown);
- g_test_add_func ("/tree-store/move-before-single",
+ g_test_add_func ("/TreeStore/move-before-single",
tree_store_test_move_before_single);
/* iter invalidation */
- g_test_add ("/tree-store/iter-prev-invalid", TreeStore, NULL,
+ g_test_add ("/TreeStore/iter-prev-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_previous_invalid,
tree_store_teardown);
- g_test_add ("/tree-store/iter-next-invalid", TreeStore, NULL,
+ g_test_add ("/TreeStore/iter-next-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_next_invalid,
tree_store_teardown);
- g_test_add ("/tree-store/iter-children-invalid", TreeStore, NULL,
+ g_test_add ("/TreeStore/iter-children-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_children_invalid,
tree_store_teardown);
- g_test_add ("/tree-store/iter-nth-child-invalid", TreeStore, NULL,
+ g_test_add ("/TreeStore/iter-nth-child-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_nth_child_invalid,
tree_store_teardown);
- g_test_add ("/tree-store/iter-parent-invalid", TreeStore, NULL,
+ g_test_add ("/TreeStore/iter-parent-invalid", TreeStore, NULL,
tree_store_setup, tree_store_test_iter_parent_invalid,
tree_store_teardown);
- return g_test_run ();
+ /* specific bugs */
+ g_test_add_func ("/TreeStore/bug-77977", specific_bug_77977);
}