/* 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
* 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.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <gtk/gtk.h>
+#include <string.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.
*/
gboolean visible)
{
GtkTreePath *path;
+ gchar *path_string;
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), iter);
+ path_string = gtk_tree_path_to_string (path);
+
gtk_tree_store_set (store, iter,
- 0, gtk_tree_path_to_string (path),
+ 0, path_string,
1, visible,
-1);
+
gtk_tree_path_free (path);
+ g_free (path_string);
}
static void
}
/*
- * Signal monitor
+ * Fixture
*/
-typedef enum
-{
- ROW_INSERTED,
- ROW_DELETED,
- ROW_CHANGED,
- ROW_HAS_CHILD_TOGGLED,
- ROWS_REORDERED,
- LAST_SIGNAL
-}
-SignalName;
-
-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;
- guint signal_ids[LAST_SIGNAL];
-}
-SignalMonitor;
-
-
-static void
-signal_monitor_generic_handler (SignalMonitor *m,
- SignalName signal,
- GtkTreeModel *model,
- GtkTreePath *path)
-{
- Signal *s;
-
- g_return_if_fail (m->client == model);
- g_return_if_fail (!g_queue_is_empty (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
-
- s = g_queue_peek_tail (m->queue);
-
- g_return_if_fail (s->signal == signal);
-
- s = g_queue_pop_tail (m->queue);
-
- g_return_if_fail (!gtk_tree_path_compare (path, s->path));
-
- 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);
+ GtkWidget *tree_view;
- g_free (m);
-}
+ GtkTreeStore *store;
+ GtkTreeModelFilter *filter;
-static void
-signal_monitor_assert_is_empty (SignalMonitor *m)
-{
- g_assert (g_queue_is_empty (m->queue));
-}
+ SignalMonitor *monitor;
-static void
-signal_monitor_append_signal_path (SignalMonitor *m,
- SignalName signal,
- GtkTreePath *path)
-{
- Signal *s;
+ guint block_signals : 1;
+} FilterTest;
- 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)
+filter_test_store_signal (FilterTest *fixture)
{
- 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);
+ if (fixture->block_signals)
+ g_signal_stop_emission_by_name (fixture->store, "row-changed");
}
-/*
- * Fixture
- */
-
-typedef struct
-{
- GtkWidget *tree_view;
-
- GtkTreeStore *store;
- GtkTreeModelFilter *filter;
-
- SignalMonitor *monitor;
-} FilterTest;
static void
filter_test_setup_generic (FilterTest *fixture,
fixture->store = create_tree_store (depth, !empty);
+ g_signal_connect_swapped (fixture->store, "row-changed",
+ G_CALLBACK (filter_test_store_signal), fixture);
+
/* Please forgive me for casting const away. */
filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture->store),
(GtkTreePath *)vroot);
fixture->monitor = signal_monitor_new (filter);
}
+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)
filter_test_setup_generic (fixture, test_data, 3, FALSE, TRUE);
}
+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)
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,
/* 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);
gtk_tree_model_filter_refilter (fixture->filter);
}
+static void
+filter_test_block_signals (FilterTest *fixture)
+{
+ fixture->block_signals = TRUE;
+}
+
+static void
+filter_test_unblock_signals (FilterTest *fixture)
+{
+ fixture->block_signals = FALSE;
+}
+
static void
filter_test_teardown (FilterTest *fixture,
gconstpointer test_data)
{
signal_monitor_free (fixture->monitor);
+ gtk_widget_destroy (fixture->tree_view);
+
g_object_unref (fixture->filter);
g_object_unref (fixture->store);
}
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);
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);
}
}
-1);
}
+#if 0
static void
insert_path_with_visibility (FilterTest *fixture,
const gchar *path_string,
}
gtk_tree_path_free (path);
}
+#endif
/*
* The actual tests.
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);
/* 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);
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);
{
GtkTreePath *path = (GtkTreePath *)user_data;
- 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);
check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
- signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
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);
/* 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);
check_level_length (fixture->filter, "0:3", 0);
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
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);
- /* FIXME: Inconsistency! For the non-vroot case we also receive two
- * row-has-child-toggled signals here.
+ /* Once 0:4:0 got inserted, 0:4 became a parent. However, 0:4 is not
+ * visible, so no signal should be emitted.
*/
- 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)
+filled_vroot_hide_child_levels_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
{
- check_filter_model (fixture);
- check_level_length (fixture->filter, NULL, 0);
+ GtkTreePath *path = (GtkTreePath *)user_data;
+ GtkTreePath *tmp_path;
- signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
- signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
- set_path_visibility (fixture, "3", TRUE);
- check_filter_model (fixture);
- check_level_length (fixture->filter, NULL, 1);
- check_level_length (fixture->filter, "0", 0);
+ 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);
- set_path_visibility (fixture, "3:2:2", TRUE);
- check_filter_model (fixture);
+ 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);
+ check_level_length (fixture->filter, NULL, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "0", LEVEL_LENGTH - 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0:3");
+ 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 */
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:3");
+ 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);
+ check_level_length (fixture->filter, "0:3", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0:2");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:2");
+ 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 */
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0:4");
+ 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)
+{
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+ check_level_length (fixture->filter, "0", 0);
+
+ set_path_visibility (fixture, "3:2:2", TRUE);
+ check_filter_model (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);
check_level_length (fixture->filter, "0:0:0", 0);
}
+static void
+empty_show_multiple_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter;
+ GtkTreePath *changed_path;
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 0);
+
+ 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_INSERTED, "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
+ * for these nodes (and others) after that.
+ */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "3", TRUE);
+ set_path_visibility (fixture, "4", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ 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);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 0);
+
+ set_path_visibility (fixture, "3:2:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3:2", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 1);
+ check_level_length (fixture->filter, "0:0:0", 0);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "3", FALSE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 1);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_INSERTED, "0");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ set_path_visibility (fixture, "3:2:1", TRUE);
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model (fixture);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 2);
+ check_level_length (fixture->filter, "0:0:0", 0);
+}
+
static void
empty_vroot_show_nodes (FilterTest *fixture,
gconstpointer user_data)
check_level_length (fixture->filter, "0:1", 0);
}
+static void
+empty_vroot_show_multiple_nodes (FilterTest *fixture,
+ gconstpointer user_data)
+{
+ GtkTreeIter iter;
+ GtkTreePath *changed_path;
+ GtkTreePath *path = (GtkTreePath *)user_data;
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ /* We simulate a change in visible func condition with this. The
+ * visibility state of multiple nodes changes at once, we emit row-changed
+ * for these nodes (and others) after that.
+ */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "2", TRUE);
+ set_path_visibility (fixture, "3", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (changed_path, 1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, changed_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ set_path_visibility (fixture, "2:2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 0);
+
+ 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_INSERTED, "1");
+ signal_monitor_append_signal (fixture->monitor, ROW_HAS_CHILD_TOGGLED, "1");
+
+ /* Again, we simulate a call to refilter */
+ filter_test_block_signals (fixture);
+ set_path_visibility (fixture, "2:2", TRUE);
+ set_path_visibility (fixture, "2:3", TRUE);
+ filter_test_unblock_signals (fixture);
+
+ changed_path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (changed_path, 2);
+ gtk_tree_path_append_index (changed_path, 1);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store),
+ &iter, changed_path);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_next (changed_path);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), &iter);
+ gtk_tree_model_row_changed (GTK_TREE_MODEL (fixture->store),
+ changed_path, &iter);
+
+ gtk_tree_path_free (changed_path);
+
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 1);
+ check_level_length (fixture->filter, "0:0", 0);
+
+ set_path_visibility (fixture, "3", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+
+ signal_monitor_append_signal (fixture->monitor, ROW_DELETED, "0");
+ set_path_visibility (fixture, "2:2", FALSE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 1);
+
+ 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:1", TRUE);
+ set_path_visibility (fixture, "2:2", TRUE);
+ check_filter_model_with_root (fixture, path);
+ check_level_length (fixture->filter, NULL, 2);
+ check_level_length (fixture->filter, "0", 2);
+ check_level_length (fixture->filter, "0:1", 0);
+}
+
static void
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);
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");
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);
unfiltered_hide_single_multi_level (FilterTest *fixture,
gconstpointer user_data)
+{
+ /* 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);
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);
}
+
static void
unfiltered_vroot_hide_single (FilterTest *fixture,
gconstpointer user_data)
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);
{
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");
+ /* 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 the filter model only has
- * the first two levels cached. (We add an additional level to take
- * the virtual root into account).
+ /* 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);
}
static void
-unfiltered_vroot_hide_single_multi_level (FilterTest *fixture,
- gconstpointer user_data)
+unfiltered_vroot_hide_single_child_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
{
GtkTreePath *path = (GtkTreePath *)user_data;
- /* This row is not shown, so its signal is not propagated */
+ 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);
+
+ 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, LEVEL_LENGTH);
+ check_level_length (fixture->filter, "2", LEVEL_LENGTH - 1);
+}
+
+static void
+unfiltered_vroot_hide_single_multi_level (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);
+
+ /* 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");
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);
check_level_length (fixture->filter, "2:2", LEVEL_LENGTH - 1);
}
-
-
static void
unfiltered_show_single (FilterTest *fixture,
gconstpointer user_data)
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);
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");
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);
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.
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);
check_level_length (fixture->filter, "0:0", 1);
}
-
static void
unfiltered_vroot_show_single (FilterTest *fixture,
gconstpointer user_data)
/* 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);
{
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, "0", 1);
}
+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)
*/
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);
signal_monitor_assert_is_empty (fixture->monitor);
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);
+ /* 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, "0:0", 1);
}
+static void
+unfiltered_vroot_show_single_multi_level_root_expanded (FilterTest *fixture,
+ gconstpointer user_data)
-static gboolean
-specific_path_dependent_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
{
- GtkTreePath *path;
+ GtkTreePath *path = (GtkTreePath *)user_data;
- path = gtk_tree_model_get_path (model, iter);
- if (gtk_tree_path_get_indices (path)[0] < 4)
- return FALSE;
+ /* 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);
- return 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);
+
+ 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);
+
+ 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);
+ 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
-specific_path_dependent_filter (void)
+unfiltered_rows_reordered_root_level (FilterTest *fixture,
+ gconstpointer user_data)
{
- int i;
- GtkTreeIter iter;
- GtkListStore *list;
- GtkTreeModel *sort;
- GtkTreeModel *filter;
+ 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;
- list = gtk_list_store_new (1, G_TYPE_INT);
- gtk_list_store_insert_with_values (list, &iter, 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, &iter, 6, 0, 7, -1);
- gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
+ 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");
- sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
- filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
- specific_path_dependent_filter_func,
- NULL, NULL);
+ 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);
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
- GTK_SORT_DESCENDING);
+ 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);
- for (i = 0; i < 4; i++)
- {
- if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
- NULL, 1))
- gtk_list_store_remove (list, &iter);
+ 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);
- if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
- NULL, 2))
- gtk_list_store_remove (list, &iter);
- }
+ 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;
-static gboolean
-specific_append_after_collapse_visible_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- gint number;
- gboolean hide_negative_numbers;
+ /* 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 (model, iter, 1, &number, -1);
- hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
+ 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");
- return (number >= 0 || !hide_negative_numbers);
+ 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
-specific_append_after_collapse (void)
+filtered_rows_reordered_root_level_first_hidden (FilterTest *fixture,
+ gconstpointer user_data)
{
- /* This test is based on one of the test cases I found in my
- * old test cases directory. I unfortunately do not have a record
- * from who this test case originated. -Kris.
- *
- * General idea:
- * - Construct tree.
- * - Show tree, expand, collapse.
- * - Add a row.
- */
-
- GtkTreeIter iter;
- GtkTreeIter child_iter;
- GtkTreeIter child_iter2;
- GtkTreePath *append_path;
- GtkTreeStore *store;
- GtkTreeModel *filter;
- GtkTreeModel *sort;
-
- GtkWidget *window;
- GtkWidget *tree_view;
+ 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;
- store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+ /* 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);
- filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
- g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
- GINT_TO_POINTER (FALSE));
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
- specific_append_after_collapse_visible_func,
- filter, NULL);
+ 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");
- sort = gtk_tree_model_sort_new_with_model (filter);
+ 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);
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- tree_view = gtk_tree_view_new_with_model (sort);
- gtk_container_add (GTK_CONTAINER (window), tree_view);
- gtk_widget_realize (tree_view);
+ 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);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ 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_store_prepend (store, &iter, NULL);
- gtk_tree_store_set (store, &iter,
- 0, "hallo", 1, 1, -1);
+ gtk_tree_path_free (path);
+}
- gtk_tree_store_append (store, &child_iter, &iter);
- gtk_tree_store_set (store, &child_iter,
- 0, "toemaar", 1, 1, -1);
+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;
- gtk_tree_store_append (store, &child_iter2, &child_iter);
- gtk_tree_store_set (store, &child_iter2,
- 0, "very deep", 1, 1, -1);
+ /* 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);
- append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
+ 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");
- gtk_tree_store_append (store, &child_iter, &iter);
- gtk_tree_store_set (store, &child_iter,
- 0, "sja", 1, 1, -1);
+ 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);
- gtk_tree_store_append (store, &child_iter, &iter);
- gtk_tree_store_set (store, &child_iter,
- 0, "some word", 1, -1, -1);
+ 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);
- /* Expand and collapse the tree */
- gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ 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_view_collapse_all (GTK_TREE_VIEW (tree_view));
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ gtk_tree_path_free (path);
+}
- /* Add another it */
- g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
- GINT_TO_POINTER (TRUE));
+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;
- if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
- {
- gtk_tree_store_append (store, &child_iter, &iter);
- gtk_tree_store_set (store, &child_iter,
- 0, "new new new !!", 1, 1, -1);
- }
- gtk_tree_path_free (append_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);
- /* Expand */
- gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
- while (gtk_events_pending ())
- gtk_main_iteration ();
-}
+ /* 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");
-static gint
-specific_sort_filter_remove_node_compare_func (GtkTreeModel *model,
- GtkTreeIter *iter1,
- GtkTreeIter *iter2,
- gpointer data)
-{
- return -1;
-}
+ 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);
-static gboolean
-specific_sort_filter_remove_node_visible_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- char *item = NULL;
+ 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);
- /* Do reference the model */
- gtk_tree_model_get (model, iter, 0, &item, -1);
- g_free (item);
+ 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);
- return FALSE;
+ gtk_tree_path_free (path);
}
static void
-specific_sort_filter_remove_node (void)
+filtered_rows_reordered_child_level_middle_hidden (FilterTest *fixture,
+ gconstpointer user_data)
{
- /* This test is based on one of the test cases I found in my
- * old test cases directory. I unfortunately do not have a record
- * from who this test case originated. -Kris.
- *
- * General idea:
- * - Create tree store, sort, filter models. The sort model has
- * a default sort func that is enabled, filter model a visible func
- * that defaults to returning FALSE.
- * - Remove a node from the tree store.
- */
+ 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;
- GtkTreeIter iter;
- GtkTreeStore *store;
- GtkTreeModel *filter;
- GtkTreeModel *sort;
+ /* 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);
- GtkWidget *window;
- GtkWidget *tree_view;
+ /* 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);
- store = gtk_tree_store_new (1, G_TYPE_STRING);
- gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
+ 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");
- gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
+ 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);
- sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
- gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
- specific_sort_filter_remove_node_compare_func, NULL, NULL);
+ 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);
- filter = gtk_tree_model_filter_new (sort, NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
- specific_sort_filter_remove_node_visible_func,
- filter, NULL);
+ 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;
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- tree_view = gtk_tree_view_new_with_model (filter);
- gtk_container_add (GTK_CONTAINER (window), tree_view);
- gtk_widget_realize (tree_view);
+ /* 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);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ 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");
- /* Remove a node */
- gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
- gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
- gtk_tree_store_remove (store, &iter);
+ 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);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ gtk_tree_path_free (path);
}
-
static void
-specific_sort_filter_remove_root (void)
+filtered_rows_reordered_child_level_all_hidden (FilterTest *fixture,
+ gconstpointer user_data)
{
- /* This test is based on one of the test cases I found in my
- * old test cases directory. I unfortunately do not have a record
- * from who this test case originated. -Kris.
- */
-
- GtkTreeModel *model, *sort, *filter;
- GtkTreeIter root, mid, leaf;
+ GtkTreeIter iter1, iter4;
GtkTreePath *path;
- model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
- gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
- gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
- gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
-
- path = gtk_tree_model_get_path (model, &mid);
+ /* 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);
- sort = gtk_tree_model_sort_new_with_model (model);
- filter = gtk_tree_model_filter_new (sort, 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_store_remove (GTK_TREE_STORE (model), &root);
+ 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");
- g_object_unref (filter);
- g_object_unref (sort);
- g_object_unref (model);
+ gtk_tree_store_move_after (fixture->store, &iter1, &iter4);
+ signal_monitor_assert_is_empty (fixture->monitor);
}
-
static void
-specific_root_mixed_visibility (void)
+insert_before (void)
{
- int i;
+ GtkTreeStore *store;
GtkTreeModel *filter;
- /* A bit nasty, apologies */
- FilterTest fixture;
+ GtkWidget *tree_view;
+ SignalMonitor *monitor;
+ GtkTreeIter iter;
+ GtkTreeIter last_iter;
+ GtkTreePath *path;
- fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ /* 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.
+ */
- for (i = 0; i < LEVEL_LENGTH; i++)
+ 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);
+
+ g_object_unref (filter);
+ g_object_unref (store);
+ gtk_widget_destroy (tree_view);
+}
+
+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);
+
+ g_object_unref (filter);
+ g_object_unref (store);
+ gtk_widget_destroy (tree_view);
+}
+
+
+
+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));
+
+ /* The root level and first level remain cached, only the references on the
+ * first nodes of these levels are kept.
+ */
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &iter_first, 1);
+ 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));
+
+ /* The root level and first level remain cached, only the references on the
+ * first nodes of these levels are kept. Grandparent2 is the parent
+ * of the first level with parent1, so grandparent2 keeps a reference
+ * as well.
+ */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ 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);
+
+ 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_filter_row_length_1 (void)
+{
+ GtkTreeIter level1_1;
+ GtkTreeIter level2_1;
+ GtkTreeIter level3_1;
+ GtkTreeIter level4_1;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+
+ /* + level1_1
+ * + level2_1
+ * + level3_1
+ * + level4_1
+ *
+ * Node level1_1 is expanded. This makes that levels 1 and 2 are
+ * visible. Level 3 is cached because its parent is visible. Level 4
+ * is not cached.
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 3);
+ assert_node_ref_count (ref_model, &level3_1, 1);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 3);
+ assert_node_ref_count (ref_model, &level3_1, 1);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ /* level3_1 has a visible parent, so the node is kept in the cache. */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 3);
+ assert_node_ref_count (ref_model, &level3_1, 1);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ /* level2_1 has a visible parent, so is kept in the cache. However,
+ * the external reference should be released.
+ */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_1_remove_in_root_level (void)
+{
+ GtkTreeIter level1_1;
+ GtkTreeIter level2_1;
+ GtkTreeIter level3_1;
+ GtkTreeIter level4_1;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+
+ /* + level1_1
+ * + level2_1
+ * + level3_1
+ * + level4_1
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 3);
+ assert_node_ref_count (ref_model, &level3_1, 3);
+ assert_node_ref_count (ref_model, &level4_1, 2);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 0);
+ assert_node_ref_count (ref_model, &level2_1, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_1_remove_in_child_level (void)
+{
+ GtkTreeIter level1_1;
+ GtkTreeIter level2_1;
+ GtkTreeIter level3_1;
+ GtkTreeIter level4_1;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+
+ /* + level1_1
+ * + level2_1
+ * + level3_1
+ * + level4_1
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ path = gtk_tree_path_new_from_indices (0, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, TRUE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 3);
+ assert_node_ref_count (ref_model, &level3_1, 3);
+ assert_node_ref_count (ref_model, &level4_1, 2);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 3);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 0);
+ assert_node_ref_count (ref_model, &level2_1, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_gt_1 (void)
+{
+ GtkTreeIter level1_1, level1_2;
+ GtkTreeIter level2_1, level2_2;
+ GtkTreeIter level3_1, level3_2;
+ GtkTreeIter level4_1, level4_2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+
+ /* + level1_1
+ * + level1_2
+ * + level2_1
+ * + level2_2
+ * + level3_1
+ * + level3_2
+ * + level4_1
+ * + level4_2
+ *
+ * Node level1_2 is expanded. This makes that levels 1 and 2 are
+ * visible. Level 3 is cached because its parent is visible. Level 4
+ * is not cached.
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_2, &level1_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_2, &level2_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_2, &level3_2);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_2, 0, TRUE, -1);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ path = gtk_tree_path_new_from_indices (1, -1);
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (tree_view), path, FALSE);
+ gtk_tree_path_free (path);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 2);
+ assert_node_ref_count (ref_model, &level3_1, 1);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 2);
+ assert_node_ref_count (ref_model, &level3_1, 1);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 2);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 1);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 0);
+ assert_node_ref_count (ref_model, &level2_1, 0);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &level1_1, 1);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 0);
+
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_filter_row_length_gt_1_visible_children (void)
+{
+ GtkTreeIter level1_1, level1_2;
+ GtkTreeIter level2_1, level2_2;
+ GtkTreeIter level3_1, level3_2;
+ GtkTreeIter level4_1, level4_2;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+
+ /* + level1_1
+ * + level1_2
+ * + level2_1
+ * + level2_2
+ * + level3_1
+ * + level3_2
+ * + level4_1
+ * + level4_2
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level1_2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_1, &level1_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level2_2, &level1_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_1, &level2_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level3_2, &level2_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_1, &level3_2);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &level4_2, &level3_2);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level1_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level3_2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level4_2, 0, TRUE, -1);
+
+ assert_entire_model_unreferenced (ref_model);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ 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, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 2);
+ assert_node_ref_count (ref_model, &level3_1, 2);
+ assert_node_ref_count (ref_model, &level3_2, 2);
+ assert_node_ref_count (ref_model, &level4_1, 2);
+ assert_node_ref_count (ref_model, &level4_2, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &level2_2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &level1_1, 2);
+ assert_node_ref_count (ref_model, &level1_2, 2);
+ assert_node_ref_count (ref_model, &level2_1, 2);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ gtk_widget_destroy (tree_view);
+ gtk_tree_model_filter_clear_cache (GTK_TREE_MODEL_FILTER (filter_model));
+
+ assert_node_ref_count (ref_model, &level1_1, 1);
+ assert_node_ref_count (ref_model, &level1_2, 1);
+ assert_node_ref_count (ref_model, &level2_1, 1);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 0);
+
+ g_object_unref (filter_model);
+
+ assert_node_ref_count (ref_model, &level1_1, 0);
+ assert_node_ref_count (ref_model, &level1_2, 0);
+ assert_node_ref_count (ref_model, &level2_1, 0);
+ assert_node_ref_count (ref_model, &level2_2, 0);
+ assert_node_ref_count (ref_model, &level3_1, 0);
+ assert_node_ref_count (ref_model, &level3_2, 0);
+ assert_node_ref_count (ref_model, &level4_1, 0);
+ assert_node_ref_count (ref_model, &level4_2, 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));
+
+ /* The root level and first level remain cached, only the references on the
+ * first nodes of these levels are kept. Grandparent2 is the parent
+ * of the first level with parent1, so grandparent2 keeps a reference
+ * as well.
+ */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ 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);
+
+ 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));
+
+ /* The root level and first level remain cached, only the references on the
+ * first nodes of these levels are kept. Grandparent2 is the parent
+ * of the first level with parent1, so grandparent2 keeps a reference
+ * as well.
+ */
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &parent1, 1);
+
+ 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_remove (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_remove (GTK_TREE_STORE (model), &grandparent1);
+
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_remove_filtered (void)
+{
+ GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + grandparent1
+ * + grandparent2
+ * + grandparent3
+ * + grandparent4
+ */
+
+ 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);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, NULL);
+
+ /* Filter first node */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 2);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent4);
+
+ /* Check level length to get root level cached again */
+ check_level_length (GTK_TREE_MODEL_FILTER (filter_model), NULL, 0);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, NULL);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter_model), NULL, 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_root_level_reordered_filtered (void)
+{
+ GtkTreeIter grandparent1, grandparent2, grandparent3;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + 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);
+
+ /* Test with 1 node filtered */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ /* Move the invisible node grandparent1 */
+
+ /* 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, 0);
+
+ /* Move the invisible node grandparent1 */
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_before (GTK_TREE_STORE (model),
+ &grandparent1, &grandparent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ /* Now swap grandparent2 and grandparent3, first reference must transfer */
+ /* gtk_tree_store_swap() will emit rows-reordered */
+ gtk_tree_store_swap (GTK_TREE_STORE (model),
+ &grandparent2, &grandparent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+
+ /* Swap back */
+ gtk_tree_store_swap (GTK_TREE_STORE (model),
+ &grandparent2, &grandparent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+
+ /* Test with two nodes filtered */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_before (GTK_TREE_STORE (model),
+ &grandparent3, &grandparent1);
+
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_root_level_filter (void)
+{
+ GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+ GtkTreeIter new_node;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + grandparent1
+ * + grandparent2
+ * + grandparent3
+ * + grandparent4
+ */
+
+ 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);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, NULL);
+
+ /* Filter first node */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 2);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 2);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 2);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, NULL);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &new_node, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &new_node, 2);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 2);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ 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_remove (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_remove (GTK_TREE_STORE (model), &parent1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent3, 1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+static void
+ref_count_transfer_child_level_remove_filtered (void)
+{
+ GtkTreeIter grandparent1;
+ GtkTreeIter parent1, parent2, parent3, parent4;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + grandparent1
+ * + parent1
+ * + parent2
+ * + parent3
+ * + parent4
+ */
+
+ 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);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent4, &grandparent1);
+
+ /* Filter first node */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent4, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ 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, 0);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+ assert_node_ref_count (ref_model, &parent4, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent3, 1);
+ assert_node_ref_count (ref_model, &parent4, 0);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent4, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent4);
+
+ /* Check level length to get level cached again */
+ check_level_length (GTK_TREE_MODEL_FILTER (filter_model), "0", 0);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &parent2, &grandparent1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter_model), "0", 1);
+
+ 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 void
+ref_count_transfer_child_level_reordered_filtered (void)
+{
+ GtkTreeIter grandparent1;
+ GtkTreeIter parent1, parent2, parent3;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + 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);
+
+ /* Test with 1 node filtered (parent1) */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent3, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ 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, 0);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ /* Move invisible node parent 1 */
+
+ /* 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);
+
+ /* Move invisible node parent 1 */
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_before (GTK_TREE_STORE (model),
+ &parent1, &parent2);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ /* Now swap parent2 and parent2, first reference must transfer */
+ /* gtk_tree_store_swap() will emit rows-reordered */
+ gtk_tree_store_swap (GTK_TREE_STORE (model),
+ &parent2, &parent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent3, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+
+ /* Swap back */
+ gtk_tree_store_swap (GTK_TREE_STORE (model),
+ &parent2, &parent3);
+
+ assert_node_ref_count (ref_model, &grandparent1, 3);
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 1);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &parent1, 1);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &parent3, 0);
+
+ /* Test with two nodes filtered */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &parent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &parent1, 0);
+ assert_node_ref_count (ref_model, &parent2, 0);
+ assert_node_ref_count (ref_model, &parent3, 1);
+
+ /* gtk_tree_store_move() will emit rows-reordered */
+ gtk_tree_store_move_before (GTK_TREE_STORE (model),
+ &parent3, &parent1);
+
+ assert_node_ref_count (ref_model, &parent3, 1);
+ assert_node_ref_count (ref_model, &parent2, 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 void
+ref_count_transfer_child_level_filter (void)
+{
+ GtkTreeIter root;
+ GtkTreeIter grandparent1, grandparent2, grandparent3, grandparent4;
+ GtkTreeIter new_node;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ 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);
+
+ /* + root
+ * + grandparent1
+ * + grandparent2
+ * + grandparent3
+ * + grandparent4
+ */
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent1, &root);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent2, &root);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent3, &root);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &grandparent4, &root);
+
+ /* Filter first node */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &root, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 1);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent3, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &root);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 1);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent1, 0, FALSE, -1);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+ gtk_tree_store_prepend (GTK_TREE_STORE (model), &new_node, &root);
+
+ assert_node_ref_count (ref_model, &new_node, 0);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 1);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &new_node, 0, TRUE, -1);
+
+ assert_node_ref_count (ref_model, &new_node, 1);
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 0);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent2, 0, TRUE, -1);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &new_node);
+
+ assert_node_ref_count (ref_model, &grandparent1, 0);
+ assert_node_ref_count (ref_model, &grandparent2, 1);
+ assert_node_ref_count (ref_model, &grandparent3, 0);
+ assert_node_ref_count (ref_model, &grandparent4, 0);
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &grandparent4, 0, TRUE, -1);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &grandparent2);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
+
+
+static gboolean
+specific_path_dependent_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, iter);
+ if (gtk_tree_path_get_indices (path)[0] < 4)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+specific_path_dependent_filter (void)
+{
+ int i;
+ GtkTreeIter iter;
+ GtkListStore *list;
+ GtkTreeModel *sort;
+ GtkTreeModel *filter;
+
+ list = gtk_list_store_new (1, G_TYPE_INT);
+ gtk_list_store_insert_with_values (list, &iter, 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, &iter, 6, 0, 7, -1);
+ gtk_list_store_insert_with_values (list, &iter, 7, 0, 8, -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (list));
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (sort), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_path_dependent_filter_func,
+ NULL, NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort), 0,
+ GTK_SORT_DESCENDING);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
+ NULL, 1))
+ gtk_list_store_remove (list, &iter);
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (list), &iter,
+ NULL, 2))
+ gtk_list_store_remove (list, &iter);
+ }
+
+ g_object_unref (filter);
+ g_object_unref (sort);
+ g_object_unref (list);
+}
+
+
+static gboolean
+specific_append_after_collapse_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gint number;
+ gboolean hide_negative_numbers;
+
+ gtk_tree_model_get (model, iter, 1, &number, -1);
+ hide_negative_numbers = GPOINTER_TO_INT (g_object_get_data (data, "private-hide-negative-numbers"));
+
+ return (number >= 0 || !hide_negative_numbers);
+}
+
+static void
+specific_append_after_collapse (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ *
+ * General idea:
+ * - Construct tree.
+ * - Show tree, expand, collapse.
+ * - Add a row.
+ */
+
+ GtkTreeIter iter;
+ GtkTreeIter child_iter;
+ GtkTreeIter child_iter2;
+ GtkTreePath *append_path;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkTreeModel *sort;
+
+ GtkWidget *window;
+ GtkWidget *tree_view;
+
+ store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_INT);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
+ GINT_TO_POINTER (FALSE));
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_append_after_collapse_visible_func,
+ filter, NULL);
+
+ sort = gtk_tree_model_sort_new_with_model (filter);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ tree_view = gtk_tree_view_new_with_model (sort);
+ gtk_container_add (GTK_CONTAINER (window), tree_view);
+ gtk_widget_realize (tree_view);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ gtk_tree_store_prepend (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ 0, "hallo", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "toemaar", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter2, &child_iter);
+ gtk_tree_store_set (store, &child_iter2,
+ 0, "very deep", 1, 1, -1);
+
+ append_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &child_iter2);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "sja", 1, 1, -1);
+
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "some word", 1, -1, -1);
+
+ /* Expand and collapse the tree */
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Add another it */
+ g_object_set_data (G_OBJECT (filter), "private-hide-negative-numbers",
+ GINT_TO_POINTER (TRUE));
+
+ if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, append_path))
+ {
+ gtk_tree_store_append (store, &child_iter, &iter);
+ gtk_tree_store_set (store, &child_iter,
+ 0, "new new new !!", 1, 1, -1);
+ }
+ gtk_tree_path_free (append_path);
+
+ /* Expand */
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+
+static gint
+specific_sort_filter_remove_node_compare_func (GtkTreeModel *model,
+ GtkTreeIter *iter1,
+ GtkTreeIter *iter2,
+ gpointer data)
+{
+ return -1;
+}
+
+static gboolean
+specific_sort_filter_remove_node_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ char *item = NULL;
+
+ /* Do reference the model */
+ gtk_tree_model_get (model, iter, 0, &item, -1);
+ g_free (item);
+
+ return FALSE;
+}
+
+static void
+specific_sort_filter_remove_node (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ *
+ * General idea:
+ * - Create tree store, sort, filter models. The sort model has
+ * a default sort func that is enabled, filter model a visible func
+ * that defaults to returning FALSE.
+ * - Remove a node from the tree store.
+ */
+
+ GtkTreeIter iter;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkTreeModel *sort;
+
+ GtkWidget *window;
+ GtkWidget *tree_view;
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello1", -1);
+
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter, 0, "Hello2", -1);
+
+ sort = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
+ gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (sort),
+ specific_sort_filter_remove_node_compare_func, NULL, NULL);
+
+ filter = gtk_tree_model_filter_new (sort, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_sort_filter_remove_node_visible_func,
+ filter, NULL);
+
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ tree_view = gtk_tree_view_new_with_model (filter);
+ gtk_container_add (GTK_CONTAINER (window), tree_view);
+ gtk_widget_realize (tree_view);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ /* Remove a node */
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
+ gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter);
+ gtk_tree_store_remove (store, &iter);
+
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+}
+
+
+static void
+specific_sort_filter_remove_root (void)
+{
+ /* This test is based on one of the test cases I found in my
+ * old test cases directory. I unfortunately do not have a record
+ * from who this test case originated. -Kris.
+ */
+
+ GtkTreeModel *model, *sort, *filter;
+ GtkTreeIter root, mid, leaf;
+ GtkTreePath *path;
+
+ model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
+ gtk_tree_store_append (GTK_TREE_STORE (model), &root, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &mid, &root);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &leaf, &mid);
+
+ path = gtk_tree_model_get_path (model, &mid);
+
+ 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);
+ g_object_unref (sort);
+ g_object_unref (model);
+}
+
+
+static void
+specific_root_mixed_visibility (void)
+{
+ int i;
+ GtkTreeModel *filter;
+ /* A bit nasty, apologies */
+ FilterTest fixture;
+
+ fixture.store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
+
+ for (i = 0; i < LEVEL_LENGTH; i++)
{
GtkTreeIter iter;
- gtk_tree_store_insert (fixture.store, &iter, NULL, i);
- if (i % 2 == 0)
- create_tree_store_set_values (fixture.store, &iter, TRUE);
- else
- create_tree_store_set_values (fixture.store, &iter, FALSE);
- }
+ gtk_tree_store_insert (fixture.store, &iter, NULL, i);
+ if (i % 2 == 0)
+ create_tree_store_set_values (fixture.store, &iter, TRUE);
+ else
+ create_tree_store_set_values (fixture.store, &iter, FALSE);
+ }
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (fixture.store), NULL);
+ fixture.filter = GTK_TREE_MODEL_FILTER (filter);
+ fixture.monitor = NULL;
+
+ gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
+
+ /* In order to trigger the potential bug, we should not access
+ * the filter model here (so don't call the check functions).
+ */
+
+ /* Change visibility of an odd row to TRUE */
+ set_path_visibility (&fixture, "3", TRUE);
+ check_filter_model (&fixture);
+ check_level_length (fixture.filter, NULL, 4);
+}
+
+
+
+static gboolean
+specific_has_child_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ return gtk_tree_model_iter_has_child (model, iter);
+}
+
+static void
+specific_has_child_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);
+
+ /* 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");
+ 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_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);
+
+ g_object_unref (fixture.filter);
+ g_object_unref (fixture.store);
+ gtk_widget_destroy (tree_view);
+}
+
+
+static gboolean
+specific_root_has_child_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int depth;
+ GtkTreePath *path;
+
+ path = gtk_tree_model_get_path (model, iter);
+ depth = gtk_tree_path_get_depth (path);
+ gtk_tree_path_free (path);
+ if (depth > 1)
+ return TRUE;
+ /* else */
+ return gtk_tree_model_iter_has_child (model, iter);
+}
+
+static void
+specific_root_has_child_filter (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeIter iter, root;
+ FilterTest fixture; /* This is not how it should be done ... */
+ GtkWidget *tree_view;
+
+ /* 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);
- gtk_tree_model_filter_set_visible_column (fixture.filter, 1);
+ tree_view = gtk_tree_view_new_with_model (filter);
- /* In order to trigger the potential bug, we should not access
- * the filter model here (so don't call the check functions).
+ /* 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_root_has_child_filter_filter_func,
+ NULL, NULL);
- /* Change visibility of an odd row to TRUE */
- set_path_visibility (&fixture, "3", TRUE);
- check_filter_model (&fixture);
- check_level_length (fixture.filter, NULL, 4);
+ /* 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
+ * the filter model.
+ */
+ 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);
+
+ g_object_unref (fixture.filter);
+ g_object_unref (fixture.store);
+ gtk_widget_destroy (tree_view);
}
+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);
+ g_object_unref (fixture.filter);
+ g_object_unref (fixture.store);
+ gtk_widget_destroy (tree_view);
+}
static gboolean
-specific_has_child_filter_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
+specific_at_least_2_children_filter_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
{
- return gtk_tree_model_iter_has_child (model, iter);
+ return gtk_tree_model_iter_n_children (model, iter) >= 2;
}
static void
-specific_has_child_filter (void)
+specific_at_least_2_children_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
- * 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,
+ 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);
*/
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);
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);
set_path_visibility (&fixture, "0", FALSE);
/* check_filter_model (&fixture); */
-}
-
-
-static gboolean
-specific_root_has_child_filter_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- int depth;
- GtkTreePath *path;
-
- path = gtk_tree_model_get_path (model, iter);
- depth = gtk_tree_path_get_depth (path);
- gtk_tree_path_free (path);
+ signal_monitor_assert_is_empty (fixture.monitor);
- if (depth > 1)
- return TRUE;
- /* else */
- return gtk_tree_model_iter_has_child (model, iter);
+ g_object_unref (fixture.filter);
+ g_object_unref (fixture.store);
+ gtk_widget_destroy (tree_view);
}
static void
-specific_root_has_child_filter (void)
+specific_at_least_2_children_filter_on_sort_model (void)
{
+ GtkTreeRowReference *ref;
GtkTreeModel *filter;
+ GtkTreeModel *sort_model;
GtkTreeIter iter, root;
- /* A bit nasty, apologies */
- FilterTest fixture;
-
- /* This is a variation on the above test case wherein the has-child
- * check for visibility only applies to root level nodes.
- */
+ 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);
+ 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 = 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
- * 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_root_has_child_filter_filter_func,
+ 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);
+
+ 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);
* the filter model.
*/
check_level_length (fixture.filter, NULL, 1);
- check_level_length (fixture.filter, "0", 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);
- gtk_tree_store_append (fixture.store, &iter, &root);
- check_level_length (fixture.filter, NULL, 2);
- check_level_length (fixture.filter, "1", 1);
-
- create_tree_store_set_values (fixture.store, &root, TRUE);
- create_tree_store_set_values (fixture.store, &iter, TRUE);
-
- /* check_filter_model (&fixture); */
-
- 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);
-
- /* Now remove one of the remaining child rows */
- 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);
-
- set_path_visibility (&fixture, "0", FALSE);
- /* check_filter_model (&fixture); */
+ gtk_tree_row_reference_free (ref);
+ g_object_unref (fixture.filter);
+ g_object_unref (fixture.store);
+ gtk_widget_destroy (tree_view);
}
GtkTreeIter iter_first;
GtkTreeIter child;
GtkTreeStore *store;
- GtkTreeModel *filter;
+ GtkTreeModel *filter G_GNUC_UNUSED;
store = gtk_tree_store_new (1, G_TYPE_STRING);
gtk_tree_store_set (store, &child, 0, "Hello", -1);
}
+static void
+specific_list_store_clear (void)
+{
+ GtkTreeIter iter;
+ 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, &iter, 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, &iter, 6, 0, 7, -1);
+ gtk_list_store_insert_with_values (list, &iter, 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_clear (list);
+}
+
+static void
+specific_sort_ref_leaf_and_remove_ancestor (void)
+{
+ GtkTreeIter iter, child, child2, child3;
+ GtkTreeStore *tree;
+ GtkTreeModel *sort;
+ 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);
+
+ 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));
+
+ 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);
+
+ 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 (3, -1);
+ rowref = gtk_tree_row_reference_new (sort, 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_bug_300089 (void)
+specific_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 *filter;
GtkTreePath *path;
- GtkTreeIter iter, iter2, sort_iter;
+ 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));
- child_model = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_STRING));
+ 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);
- 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);
+ 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);
- 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);
+ path = gtk_tree_path_new_from_indices (3, 0, -1);
+ rowref = gtk_tree_row_reference_new (filter, path);
+ gtk_tree_path_free (path);
- 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, -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);
- 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);
+ 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);
- path = gtk_tree_path_new_from_indices (1, 1, -1);
+ 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);
- /* make sure a level is constructed */
- gtk_tree_model_get_iter (sort_model, &sort_iter, 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);
- /* 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);
}
GtkTreeModel *filter;
GtkTreeModel *sort;
GtkTreeIter root, iter, iter2;
- GtkWidget *view;
+ GtkWidget *view G_GNUC_UNUSED;
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);
GtkTreeModel *sort;
GtkTreeModel *filter;
- GtkWidget *window;
+ GtkWidget *window G_GNUC_UNUSED;
GtkWidget *tree_view;
int i;
int n;
+ GtkTreePath *path;
+
+ g_test_bug ("311955");
store = gtk_tree_store_new (1, G_TYPE_INT);
gtk_tree_store_set (store, &iter, 0, 50, -1);
gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter, 0, 22, -1);
+ gtk_tree_store_set (store, &iter, 0, 22, -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);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ 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, 2);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
+
+ /* Fill model */
+ for (i = 0; i < 4; i++)
+ {
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
+
+ gtk_tree_store_append (store, &iter, &root);
+
+ if (i < 3)
+ gtk_tree_store_set (store, &iter, 0, i, -1);
+
+ if (i % 2 == 0)
+ {
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 10, -1);
+ }
+ }
+
+ 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);
+
+ if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
+ {
+ if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
+ gtk_tree_store_remove (store, &child);
+ }
+ 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);
specific_bug_311955_filter_func,
NULL, NULL);
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
tree_view = gtk_tree_view_new_with_model (filter);
g_object_unref (store);
while (gtk_events_pending ())
gtk_main_iteration ();
- /* Fill model */
- for (i = 0; i < 4; i++)
- {
- gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &root);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), NULL, 1);
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "0", 1);
- gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter);
- if (i < 3)
- gtk_tree_store_set (store, &iter, 0, i, -1);
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 0, -1);
- if (i % 2 == 0)
- {
- gtk_tree_store_append (store, &child, &iter);
- gtk_tree_store_set (store, &child, 0, 10, -1);
- }
- }
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 1, -1);
- while (gtk_events_pending ())
- gtk_main_iteration ();
+ gtk_tree_store_append (store, &child, &iter);
+ gtk_tree_store_set (store, &child, 0, 1, -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);
+ gtk_tree_store_append (store, &grandchild, &child);
+ gtk_tree_store_set (store, &grandchild, 0, 1, -1);
- if (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store), &iter, &root, n - 2))
- {
- if (gtk_tree_model_iter_children (GTK_TREE_MODEL (store), &child, &iter))
- gtk_tree_store_remove (store, &child);
- }
- else
- g_assert_not_reached ();
+ 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
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);
(i & 1) ? TRUE : FALSE, -1);
gtk_tree_model_filter_refilter (filter);
- gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
- (i & 1) ? FALSE: TRUE, -1);
- gtk_tree_model_filter_refilter (filter);
- }
- }
-}
+ gtk_tree_store_set (GTK_TREE_STORE (model), &child_iters[i-2], 1,
+ (i & 1) ? FALSE: TRUE, -1);
+ gtk_tree_model_filter_refilter (filter);
+ }
+ }
+}
+
+static gboolean
+specific_bug_464173_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean *visible = (gboolean *)data;
+
+ return *visible;
+}
+
+static void
+specific_bug_464173 (void)
+{
+ /* Test case for GNOME Bugzilla bug 464173, test case written
+ * by Andreas Koehler.
+ */
+ GtkTreeStore *model;
+ GtkTreeModelFilter *f_model;
+ GtkTreeIter iter1, iter2;
+ 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);
+ gtk_tree_store_append (model, &iter2, &iter1);
+ gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
+
+ f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
+ gtk_tree_model_filter_set_visible_func (f_model,
+ specific_bug_464173_visible_func,
+ &visible, NULL);
+
+ view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
+
+ visible = FALSE;
+ gtk_tree_model_filter_refilter (f_model);
+}
+
+
+static gboolean
+specific_bug_540201_filter_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean has_children;
+
+ has_children = gtk_tree_model_iter_has_child (model, iter);
+
+ return has_children;
+}
+
+static void
+specific_bug_540201 (void)
+{
+ /* Test case for GNOME Bugzilla bug 540201, steps provided by
+ * Charles Day.
+ */
+ GtkTreeIter iter, root;
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+
+ 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);
+ gtk_tree_store_set (store, &root, 0, 33, -1);
+
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ tree_view = gtk_tree_view_new_with_model (filter);
+
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_540201_filter_func,
+ NULL, NULL);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 50, -1);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 22, -1);
+
+
+ gtk_tree_store_append (store, &root, NULL);
+ gtk_tree_store_set (store, &root, 0, 33, -1);
+
+ gtk_tree_store_append (store, &iter, &root);
+ gtk_tree_store_set (store, &iter, 0, 22, -1);
+}
+
+
+static gboolean
+specific_bug_549287_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean result = FALSE;
+
+ result = gtk_tree_model_iter_has_child (model, iter);
+
+ return result;
+}
+
+static void
+specific_bug_549287 (void)
+{
+ /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
+
+ int i;
+ GtkTreeStore *store;
+ GtkTreeModel *filtered;
+ GtkWidget *view G_GNUC_UNUSED;
+ 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),
+ specific_bug_549287_visible_func,
+ NULL, NULL);
+
+ view = gtk_tree_view_new_with_model (filtered);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
+ {
+ parent = gtk_tree_iter_copy (&iter);
+ child = gtk_tree_iter_copy (&iter);
+
+ while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
+ child, parent, 0))
+ {
+
+ swap = parent;
+ parent = child;
+ child = swap;
+ }
+
+ gtk_tree_store_append (store, child, parent);
+ gtk_tree_store_set (store, child,
+ 0, "Something",
+ -1);
+
+ gtk_tree_iter_free (parent);
+ gtk_tree_iter_free (child);
+ }
+ else
+ {
+ gtk_tree_store_append (store, &iter, NULL);
+ gtk_tree_store_set (store, &iter,
+ 0, "Something",
+ -1);
+ }
+
+ /* since we inserted something, we changed the visibility conditions: */
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
+ }
+}
+
+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);
+
+ return visible;
+}
+
+static void
+specific_bug_621076 (void)
+{
+ /* Test case for GNOME Bugzilla bug 621076, provided by Xavier Claessens */
+
+ /* This test case differs from has-child-filter and root-has-child-filter
+ * in that the visible function both filters on content and model
+ * structure. Also, it is recursive.
+ */
+
+ GtkTreeStore *store;
+ GtkTreeModel *filter;
+ GtkWidget *view;
+ GtkTreeIter group_iter;
+ GtkTreeIter item_iter;
+ SignalMonitor *monitor;
+
+ g_test_bug ("621076");
+
+ store = gtk_tree_store_new (1, G_TYPE_STRING);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_621076_visible_func,
+ NULL, NULL);
+
+ view = gtk_tree_view_new_with_model (filter);
+ g_object_ref_sink (view);
+
+ monitor = signal_monitor_new (filter);
+
+ signal_monitor_append_signal (monitor, ROW_INSERTED, "0");
+ gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+ 0, "visible-group-0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* visible-group-0 is not expanded, so ROW_INSERTED should not be emitted
+ * for its children. However, ROW_HAS_CHILD_TOGGLED should be emitted on
+ * visible-group-0 to tell the view that row can be expanded. */
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "0");
+ group_iter = item_iter;
+ gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+ 0, "visible-0:0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ signal_monitor_append_signal (monitor, ROW_INSERTED, "1");
+ gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+ 0, "visible-group-1",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* We are adding an hidden item inside visible-group-1, so
+ * ROW_HAS_CHILD_TOGGLED should not be emitted. It is emitted though,
+ * because the signal originating at TreeStore will be propagated,
+ * as well a generated signal because the state of the parent *could*
+ * change by a change in the model.
+ */
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ group_iter = item_iter;
+ gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+ 0, "group-1:0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* This group is invisible and its parent too. Nothing should be emitted */
+ group_iter = item_iter;
+ gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+ 0, "group-1:0:0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* Adding a visible item in this group hierarchy will make all nodes
+ * in this path visible. The first level should simply tell the view
+ * that it now has a child, and the view will load the tree if needed
+ * (depends on the expanded state).
+ */
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "1");
+ group_iter = item_iter;
+ gtk_tree_store_insert_with_values (store, &item_iter, &group_iter, -1,
+ 0, "visible-1:0:0:0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ check_level_length (GTK_TREE_MODEL_FILTER (filter), "1", 1);
+
+ gtk_tree_store_insert_with_values (store, &item_iter, NULL, -1,
+ 0, "group-2",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* Parent is invisible, and adding this invisible item won't change that,
+ * so no signal should be emitted. */
+ group_iter = item_iter;
+ gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+ 0, "invisible-2:0",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* This makes group-2 visible, so it gets inserted and tells it has
+ * children.
+ */
+ signal_monitor_append_signal (monitor, ROW_INSERTED, "2");
+ signal_monitor_append_signal (monitor, ROW_HAS_CHILD_TOGGLED, "2");
+ gtk_tree_store_insert_with_values (store, NULL, &group_iter, -1,
+ 0, "visible-2:1",
+ -1);
+ signal_monitor_assert_is_empty (monitor);
+
+ /* group-2 is already visible, so this time it is a normal insertion */
+ 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);
+}
static void
-specific_bug_364946 (void)
+specific_bug_657353_related (void)
{
- /* This is a test case for GNOME Bugzilla bug 364946. It was written
- * by Andreas Koehler.
+ GtkTreeIter node1, node2, node3, node4;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeModel *filter_model;
+ GtkWidget *tree_view;
+ GType column_types[] = { G_TYPE_BOOLEAN };
+
+ /* gtk_tree_model_filter_rows_reordered() used to have a problem to
+ * not properly transfer the first ref count when the first node in
+ * the level does not have elt->offset == 0. This test checks for
+ * that. This bug could cause the faulty condition
+ * elt->ext_ref_count > elt->ref_count
+ * to raise.
*/
- GtkTreeStore *store;
- GtkTreeIter a, aa, aaa, aab, iter;
- GtkTreeModel *s_model;
- store = gtk_tree_store_new (1, G_TYPE_STRING);
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
- gtk_tree_store_append (store, &a, NULL);
- gtk_tree_store_set (store, &a, 0, "0", -1);
+ gtk_tree_store_set_column_types (GTK_TREE_STORE (model), 1,
+ column_types);
- gtk_tree_store_append (store, &aa, &a);
- gtk_tree_store_set (store, &aa, 0, "0:0", -1);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &node1, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &node2, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &node3, NULL);
+ gtk_tree_store_append (GTK_TREE_STORE (model), &node4, NULL);
- gtk_tree_store_append (store, &aaa, &aa);
- gtk_tree_store_set (store, &aaa, 0, "0:0:0", -1);
+ /* Hide the first node */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &node1, 0, FALSE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &node2, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &node3, 0, TRUE, -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &node4, 0, TRUE, -1);
- gtk_tree_store_append (store, &aab, &aa);
- gtk_tree_store_set (store, &aab, 0, "0:0:1", -1);
+ filter_model = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), 0);
+ tree_view = gtk_tree_view_new_with_model (filter_model);
- 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);
+ assert_node_ref_count (ref_model, &node1, 0);
+ assert_node_ref_count (ref_model, &node2, 2);
+ assert_node_ref_count (ref_model, &node3, 1);
+ assert_node_ref_count (ref_model, &node4, 1);
- gtk_tree_model_get_iter_from_string (s_model, &iter, "0:0:0");
+ /* Swap nodes 2 and 3 */
- 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_store_swap() will emit rows-reordered */
+ gtk_tree_store_swap (GTK_TREE_STORE (model),
+ &node2, &node3);
- gtk_tree_model_sort_clear_cache (GTK_TREE_MODEL_SORT (s_model));
-}
+ assert_node_ref_count (ref_model, &node1, 0);
+ assert_node_ref_count (ref_model, &node3, 2);
+ assert_node_ref_count (ref_model, &node2, 1);
+ assert_node_ref_count (ref_model, &node4, 1);
+
+ /* Hide node 3 */
+ gtk_tree_store_set (GTK_TREE_STORE (model), &node3, 0, FALSE, -1);
+ assert_node_ref_count (ref_model, &node1, 0);
+ assert_node_ref_count (ref_model, &node3, 0);
+ assert_node_ref_count (ref_model, &node2, 2);
+ assert_node_ref_count (ref_model, &node4, 1);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (ref_model);
+}
static gboolean
-specific_bug_464173_visible_func (GtkTreeModel *model,
+specific_bug_657353_visible_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
- gboolean *visible = (gboolean *)data;
+ gchar *str;
+ gboolean ret = FALSE;
- return *visible;
+ gtk_tree_model_get (model, iter, 0, &str, -1);
+ ret = strstr (str, "hidden") ? FALSE : TRUE;
+ g_free (str);
+
+ return ret;
}
static void
-specific_bug_464173 (void)
+specific_bug_657353 (void)
{
- /* Test case for GNOME Bugzilla bug 464173, test case written
- * by Andreas Koehler.
+ GtkListStore *store;
+ GtkTreeModel *sort_model;
+ GtkTreeModel *filter_model;
+ GtkTreeIter iter, iter_a, iter_b, iter_c;
+ GtkWidget *tree_view;
+
+ /* This is a very carefully crafted test case that is triggering the
+ * situation described in bug 657353.
+ *
+ * GtkListStore acts like EphyCompletionModel
+ * GtkTreeModelSort acts like the sort model added in
+ * ephy_location_entry_set_completion.
+ * GtkTreeModelFilter acts like the filter model in
+ * GtkEntryCompletion.
*/
- GtkTreeStore *model;
- GtkTreeModelFilter *f_model;
- GtkTreeIter iter1, iter2;
- GtkWidget *view;
- gboolean visible = TRUE;
- 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);
- gtk_tree_store_append (model, &iter2, &iter1);
- gtk_tree_store_set (model, &iter2, 0, "Bar", -1);
+ /* Set up a model that's wrapped in a GtkTreeModelSort. The first item
+ * will be hidden.
+ */
+ store = gtk_list_store_new (1, G_TYPE_STRING);
+ gtk_list_store_insert_with_values (store, &iter_b, 0, 0, "BBB hidden", -1);
+ gtk_list_store_insert_with_values (store, &iter, 1, 0, "EEE", -1);
+ gtk_list_store_insert_with_values (store, &iter, 2, 0, "DDD", -1);
+ gtk_list_store_insert_with_values (store, &iter_c, 3, 0, "CCC", -1);
- f_model = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL(model), NULL));
- gtk_tree_model_filter_set_visible_func (f_model,
- specific_bug_464173_visible_func,
- &visible, NULL);
+ sort_model = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (store));
- view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (f_model));
+ filter_model = gtk_tree_model_filter_new (sort_model, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
+ specific_bug_657353_visible_func,
+ filter_model, NULL);
- visible = FALSE;
- gtk_tree_model_filter_refilter (f_model);
-}
+ tree_view = gtk_tree_view_new_with_model (filter_model);
+ /* This triggers emission of rows-reordered. The elt with offset == 0
+ * is hidden, which used to cause misbehavior. (The first reference should
+ * have moved to CCC, which did not happen).
+ */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sort_model),
+ 0, GTK_SORT_ASCENDING);
-static gboolean
-specific_bug_540201_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
-{
- gboolean has_children;
+ /* By inserting another item that will appear at the first position, a
+ * reference transfer is done from CCC (which failed to get this reference
+ * earlier) to AAA. At this point, the rule
+ * elt->ref_count >= elt->ext_ref_count is broken for CCC.
+ */
+ gtk_list_store_insert_with_values (store, &iter_a, 6, 0, "AAA", -1);
- has_children = gtk_tree_model_iter_has_child (model, iter);
+ /* When we hide CCC, the references cannot be correctly released, because
+ * CCC failed to get a reference during rows-reordered. The faulty condition
+ * only manifests itself here with MODEL_FILTER_DEBUG disabled (as is usual
+ * in production).
+ */
+ gtk_list_store_set (store, &iter_c, 0, "CCC hidden", -1);
- return has_children;
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter_model);
+ g_object_unref (sort_model);
+ g_object_unref (store);
}
static void
-specific_bug_540201 (void)
+specific_bug_658696 (void)
{
- /* Test case for GNOME Bugzilla bug 540201, steps provided by
- * Charles Day.
- */
- GtkTreeIter iter, root;
GtkTreeStore *store;
GtkTreeModel *filter;
+ GtkTreePath *vroot;
+ GtkTreeIter iter;
- GtkWidget *tree_view;
+ store = create_tree_store (4, TRUE);
- store = gtk_tree_store_new (1, G_TYPE_INT);
+ vroot = gtk_tree_path_new_from_indices (0, 0, -1);
+ filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), vroot);
+ gtk_tree_path_free (vroot);
- gtk_tree_store_append (store, &root, NULL);
- gtk_tree_store_set (store, &root, 0, 33, -1);
+ /* This used to cause a crash in gtk_tree_model_filter_check_ancestors() */
+ gtk_tree_store_append (store, &iter, NULL);
- filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (store), NULL);
- tree_view = gtk_tree_view_new_with_model (filter);
+ g_object_unref (store);
+ g_object_unref (filter);
+}
+
+static gboolean
+specific_bug_659022_visible_func (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ GtkTreeIter tmp;
+
+ if (!gtk_tree_model_iter_parent (model, &tmp, iter))
+ {
+ if (gtk_tree_model_iter_n_children (model, iter) >= 2)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+specific_bug_659022_row_changed_emission (void)
+{
+ GtkTreeModel *filter;
+ GtkTreeModel *model;
+ GtkTreeIter parent, child, child2;
+ GtkTreePath *path;
+ GtkWidget *tree_view;
+ model = gtk_tree_model_ref_count_new ();
+
+ filter = gtk_tree_model_filter_new (model, NULL);
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
- specific_bug_540201_filter_func,
+ specific_bug_659022_visible_func,
NULL, NULL);
- gtk_tree_store_append (store, &iter, &root);
- gtk_tree_store_set (store, &iter, 0, 50, -1);
+ tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
- gtk_tree_store_append (store, &iter, &root);
- gtk_tree_store_set (store, &iter, 0, 22, -1);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent, 0);
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
- gtk_tree_store_append (store, &root, NULL);
- gtk_tree_store_set (store, &root, 0, 33, -1);
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
- gtk_tree_store_append (store, &iter, &root);
- gtk_tree_store_set (store, &iter, 0, 22, -1);
-}
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &child2);
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
-static gboolean
-specific_bug_549287_visible_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- gpointer data)
+ path = gtk_tree_model_get_path (model, &child);
+ gtk_tree_model_row_changed (model, path, &child);
+ gtk_tree_path_free (path);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter);
+ g_object_unref (model);
+}
+
+static void
+specific_bug_659022_row_deleted_node_invisible (void)
{
- gboolean result = FALSE;
+ GtkTreeModel *filter;
+ GtkTreeModel *model;
+ GtkTreeIter parent, child;
+ GtkTreeIter parent2, child2, child3;
+ GtkWidget *tree_view;
- result = gtk_tree_model_iter_has_child (model, iter);
+ model = gtk_tree_model_ref_count_new ();
- return result;
+ filter = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_659022_visible_func,
+ NULL, NULL);
+
+ tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
+
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
+
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &parent2, NULL, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent2, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child3, &parent2, 0);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter));
+
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter);
+ g_object_unref (model);
}
static void
-specific_bug_549287 (void)
+specific_bug_659022_row_deleted_free_level (void)
{
- /* Test case for GNOME Bugzilla bug 529287, provided by Julient Puydt */
+ GtkTreeModel *filter;
+ GtkTreeModel *model;
+ GtkTreeModelRefCount *ref_model;
+ GtkTreeIter parent, child;
+ GtkTreeIter parent2, child2, child3;
+ GtkWidget *tree_view;
- int i;
- GtkTreeStore *store;
- GtkTreeModel *filtered;
- GtkWidget *view;
- GtkTreeIter iter;
- GtkTreeIter *swap, *parent, *child;
+ model = gtk_tree_model_ref_count_new ();
+ ref_model = GTK_TREE_MODEL_REF_COUNT (model);
- 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),
- specific_bug_549287_visible_func,
+ filter = gtk_tree_model_filter_new (model, NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
+ specific_bug_659022_visible_func,
NULL, NULL);
- view = gtk_tree_view_new_with_model (filtered);
+ tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (filter));
- for (i = 0; i < 4; i++)
- {
- if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
- {
- parent = gtk_tree_iter_copy (&iter);
- child = gtk_tree_iter_copy (&iter);
+ /* Carefully construct a model */
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &parent, NULL, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child, &parent, 0);
- while (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (store),
- child, parent, 0))
- {
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &parent2, NULL, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child2, &parent2, 0);
+ gtk_tree_store_insert (GTK_TREE_STORE (model), &child3, &parent2, 0);
- swap = parent;
- parent = child;
- child = swap;
- }
+ /* Only parent2 is visible, child3 holds first ref count for that level
+ * (Note that above, both child2 as child3 are inserted at position 0).
+ */
+ assert_node_ref_count (ref_model, &parent, 0);
+ assert_node_ref_count (ref_model, &child, 0);
+ assert_node_ref_count (ref_model, &parent2, 3);
+ assert_node_ref_count (ref_model, &child3, 1);
+ assert_node_ref_count (ref_model, &child2, 0);
- gtk_tree_store_append (store, child, parent);
- gtk_tree_store_set (store, child,
- 0, "Something",
- -1);
+ /* Make sure child level is cached */
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
- gtk_tree_iter_free (parent);
- gtk_tree_iter_free (child);
- }
- else
- {
- gtk_tree_store_append (store, &iter, NULL);
- gtk_tree_store_set (store, &iter,
- 0, "Something",
- -1);
- }
+ assert_node_ref_count (ref_model, &parent, 0);
+ assert_node_ref_count (ref_model, &child, 0);
+ assert_node_ref_count (ref_model, &parent2, 3);
+ assert_node_ref_count (ref_model, &child3, 2);
+ assert_node_ref_count (ref_model, &child2, 1);
- /* since we inserted something, we changed the visibility conditions: */
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filtered));
- }
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (tree_view));
+
+ assert_node_ref_count (ref_model, &parent, 0);
+ assert_node_ref_count (ref_model, &child, 0);
+ assert_node_ref_count (ref_model, &parent2, 3);
+ assert_node_ref_count (ref_model, &child3, 1);
+ assert_node_ref_count (ref_model, &child2, 0);
+
+ /* Remove node with longer child level first */
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent2);
+ gtk_tree_store_remove (GTK_TREE_STORE (model), &parent);
+
+ gtk_widget_destroy (tree_view);
+ g_object_unref (filter);
+ g_object_unref (model);
}
/* main */
-int
-main (int argc,
- char **argv)
+void
+register_filter_model_tests (void)
{
- gtk_test_init (&argc, &argv, NULL);
-
- g_test_add ("/FilterModel/self/verify-test-suite",
+ 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 ("/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 ("/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 ("/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);
- g_test_add_func ("/FilterModel/specific/path-dependent-filter",
+ /* 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/filter-row/length-1",
+ ref_count_filter_row_length_1);
+ g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-1-remove-in-root-level",
+ ref_count_filter_row_length_1_remove_in_root_level);
+ g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-1-remove-in-child-level",
+ ref_count_filter_row_length_1_remove_in_child_level);
+ g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-gt-1",
+ ref_count_filter_row_length_gt_1);
+ g_test_add_func ("/TreeModelFilter/ref-count/filter-row/length-gt-1-visible-children",
+ ref_count_filter_row_length_gt_1_visible_children);
+ 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/remove",
+ ref_count_transfer_root_level_remove);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/remove/filtered",
+ ref_count_transfer_root_level_remove_filtered);
+ 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/root-level/reordered/filtered",
+ ref_count_transfer_root_level_reordered_filtered);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/root-level/filter",
+ ref_count_transfer_root_level_filter);
+ 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/remove",
+ ref_count_transfer_child_level_remove);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/remove/filtered",
+ ref_count_transfer_child_level_remove_filtered);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered",
+ ref_count_transfer_child_level_reordered);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/reordered/filtered",
+ ref_count_transfer_child_level_reordered_filtered);
+ g_test_add_func ("/TreeModelFilter/ref-count/transfer/child-level/filter",
+ ref_count_transfer_child_level_filter);
+
+ 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/bug-300089",
- specific_bug_300089);
- g_test_add_func ("/FilterModel/specific/bug-301558",
+ g_test_add_func ("/TreeModelFilter/specific/list-store-clear",
+ specific_list_store_clear);
+ 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);
+ g_test_add_func ("/TreeModelFilter/specific/bug-657353-related",
+ specific_bug_657353_related);
+ g_test_add_func ("/TreeModelFilter/specific/bug-657353",
+ specific_bug_657353);
+ g_test_add_func ("/TreeModelFilter/specific/bug-658696",
+ specific_bug_658696);
+ g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-changed-emission",
+ specific_bug_659022_row_changed_emission);
+ g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-deleted-node-invisible",
+ specific_bug_659022_row_deleted_node_invisible);
+ g_test_add_func ("/TreeModelFilter/specific/bug-659022/row-deleted-free-level",
+ specific_bug_659022_row_deleted_free_level);
}