From 1cb14a16b761a8a415b9271233d938ffdbd7ddeb Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Sat, 28 May 2011 16:41:49 +0200 Subject: [PATCH] Add GtkTreeModelRefCount, only to be used in unit tests --- gtk/tests/gtktreemodelrefcount.c | 273 +++++++++++++++++++++++++++++++ gtk/tests/gtktreemodelrefcount.h | 65 ++++++++ 2 files changed, 338 insertions(+) create mode 100644 gtk/tests/gtktreemodelrefcount.c create mode 100644 gtk/tests/gtktreemodelrefcount.h diff --git a/gtk/tests/gtktreemodelrefcount.c b/gtk/tests/gtktreemodelrefcount.c new file mode 100644 index 0000000000..b4945402c2 --- /dev/null +++ b/gtk/tests/gtktreemodelrefcount.c @@ -0,0 +1,273 @@ +/* gtktreemodelrefcount.c + * Copyright (C) 2011 Kristian Rietveld + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "gtktreemodelrefcount.h" + + +/* The purpose of this GtkTreeModel is to keep record of the reference count + * of each node. The reference count does not effect the functioning of + * the model in any way. Because this model is a subclass of GtkTreeStore, + * the GtkTreeStore API should be used to add to and remove nodes from + * this model. We depend on the iter format of GtkTreeStore, which means + * that this model needs to be revised in case the iter format of + * GtkTreeStore is modified. Currently, we make use of the fact that + * the value stored in the user_data field is unique for each node. + */ + +struct _GtkTreeModelRefCountPrivate +{ + GHashTable *node_hash; +}; + +typedef struct +{ + int ref_count; +} +NodeInfo; + + +static void gtk_tree_model_ref_count_tree_model_init (GtkTreeModelIface *iface); +static void gtk_tree_model_ref_count_finalize (GObject *object); + +static NodeInfo *node_info_new (void); +static void node_info_free (NodeInfo *info); + +/* GtkTreeModel interface */ +static void gtk_tree_model_ref_count_ref_node (GtkTreeModel *model, + GtkTreeIter *iter); +static void gtk_tree_model_ref_count_unref_node (GtkTreeModel *model, + GtkTreeIter *iter); + + +G_DEFINE_TYPE_WITH_CODE (GtkTreeModelRefCount, gtk_tree_model_ref_count, GTK_TYPE_TREE_STORE, + G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, + gtk_tree_model_ref_count_tree_model_init)) + +static void +gtk_tree_model_ref_count_init (GtkTreeModelRefCount *ref_model) +{ + ref_model->priv = G_TYPE_INSTANCE_GET_PRIVATE (ref_model, + GTK_TYPE_TREE_MODEL_REF_COUNT, + GtkTreeModelRefCountPrivate); + + ref_model->priv->node_hash = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify)node_info_free); +} + +static void +gtk_tree_model_ref_count_class_init (GtkTreeModelRefCountClass *ref_model_class) +{ + GObjectClass *object_class; + + object_class = (GObjectClass *) ref_model_class; + + object_class->finalize = gtk_tree_model_ref_count_finalize; + + g_type_class_add_private (object_class, sizeof (GtkTreeModelRefCountPrivate)); +} + +static void +gtk_tree_model_ref_count_tree_model_init (GtkTreeModelIface *iface) +{ + iface->ref_node = gtk_tree_model_ref_count_ref_node; + iface->unref_node = gtk_tree_model_ref_count_unref_node; +} + +static void +gtk_tree_model_ref_count_finalize (GObject *object) +{ + GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (object); + + if (ref_model->priv->node_hash) + { + g_hash_table_destroy (ref_model->priv->node_hash); + ref_model->priv->node_hash = NULL; + } + + G_OBJECT_CLASS (gtk_tree_model_ref_count_parent_class)->finalize (object); +} + + +static NodeInfo * +node_info_new (void) +{ + NodeInfo *info = g_slice_new (NodeInfo); + info->ref_count = 0; + + return info; +} + +static void +node_info_free (NodeInfo *info) +{ + g_slice_free (NodeInfo, info); +} + +static void +gtk_tree_model_ref_count_ref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + NodeInfo *info; + GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (model); + + info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data); + if (!info) + { + info = node_info_new (); + + g_hash_table_insert (ref_model->priv->node_hash, iter->user_data, info); + } + + info->ref_count++; +} + +static void +gtk_tree_model_ref_count_unref_node (GtkTreeModel *model, + GtkTreeIter *iter) +{ + NodeInfo *info; + GtkTreeModelRefCount *ref_model = GTK_TREE_MODEL_REF_COUNT (model); + + info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data); + g_assert (info != NULL); + g_assert (info->ref_count > 0); + + info->ref_count--; +} + + +GtkTreeModel * +gtk_tree_model_ref_count_new (void) +{ + GtkTreeModel *retval; + + retval = g_object_new (gtk_tree_model_ref_count_get_type (), NULL); + + return retval; +} + +static void +dump_iter (GtkTreeModelRefCount *ref_model, + GtkTreeIter *iter) +{ + gchar *path_str; + NodeInfo *info; + GtkTreePath *path; + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (ref_model), iter); + path_str = gtk_tree_path_to_string (path); + gtk_tree_path_free (path); + + info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data); + if (!info) + g_print ("%-16s ref_count=0\n", path_str); + else + g_print ("%-16s ref_count=%d\n", path_str, info->ref_count); + + g_free (path_str); +} + +static void +gtk_tree_model_ref_count_dump_recurse (GtkTreeModelRefCount *ref_model, + GtkTreeIter *iter) +{ + do + { + GtkTreeIter child; + + dump_iter (ref_model, iter); + + if (gtk_tree_model_iter_children (GTK_TREE_MODEL (ref_model), + &child, iter)) + gtk_tree_model_ref_count_dump_recurse (ref_model, &child); + } + while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ref_model), iter)); +} + +void +gtk_tree_model_ref_count_dump (GtkTreeModelRefCount *ref_model) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ref_model), &iter)) + return; + + gtk_tree_model_ref_count_dump_recurse (ref_model, &iter); +} + +static gboolean +check_iter (GtkTreeModelRefCount *ref_model, + GtkTreeIter *iter, + gint expected_ref_count) +{ + NodeInfo *info; + + info = g_hash_table_lookup (ref_model->priv->node_hash, iter->user_data); + if (!info) + { + if (expected_ref_count == 0) + return TRUE; + else + return FALSE; + } + + return expected_ref_count == info->ref_count; +} + +gboolean +gtk_tree_model_ref_count_check_level (GtkTreeModelRefCount *ref_model, + GtkTreeIter *parent, + gint expected_ref_count, + gboolean recurse) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (ref_model), + &iter, parent)) + return TRUE; + + do + { + if (!check_iter (ref_model, &iter, expected_ref_count)) + return FALSE; + + if (recurse && + gtk_tree_model_iter_has_child (GTK_TREE_MODEL (ref_model), &iter)) + { + if (!gtk_tree_model_ref_count_check_level (ref_model, &iter, + expected_ref_count, + recurse)) + return FALSE; + } + } + while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ref_model), &iter)); + + return TRUE; +} + +gboolean +gtk_tree_model_ref_count_check_node (GtkTreeModelRefCount *ref_model, + GtkTreeIter *iter, + gint expected_ref_count) +{ + return check_iter (ref_model, iter, expected_ref_count); +} diff --git a/gtk/tests/gtktreemodelrefcount.h b/gtk/tests/gtktreemodelrefcount.h new file mode 100644 index 0000000000..c8c8e89dfd --- /dev/null +++ b/gtk/tests/gtktreemodelrefcount.h @@ -0,0 +1,65 @@ +/* gtktreemodelrefcount.h + * Copyright (C) 2011 Kristian Rietveld + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GTK_TREE_MODEL_REF_COUNT_H__ +#define __GTK_TREE_MODEL_REF_COUNT_H__ + +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_TREE_MODEL_REF_COUNT (gtk_tree_model_ref_count_get_type ()) +#define GTK_TREE_MODEL_REF_COUNT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCount)) +#define GTK_TREE_MODEL_REF_COUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCountClass)) +#define GTK_IS_TREE_MODEL_REF_COUNT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT)) +#define GTK_IS_TREE_MODEL_REF_COUNT_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), GTK_TYPE_TREE_MODEL_REF_COUNT)) +#define GTK_TREE_MODEL_REF_COUNT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_TREE_MODEL_REF_COUNT, GtkTreeModelRefCountClass)) + + +typedef struct _GtkTreeModelRefCount GtkTreeModelRefCount; +typedef struct _GtkTreeModelRefCountClass GtkTreeModelRefCountClass; +typedef struct _GtkTreeModelRefCountPrivate GtkTreeModelRefCountPrivate; + +struct _GtkTreeModelRefCount +{ + GtkTreeStore parent; + + /* < private > */ + GtkTreeModelRefCountPrivate *priv; +}; + +struct _GtkTreeModelRefCountClass +{ + GtkTreeStoreClass parent_class; +}; + + +GType gtk_tree_model_ref_count_get_type (void) G_GNUC_CONST; +GtkTreeModel *gtk_tree_model_ref_count_new (void); + +void gtk_tree_model_ref_count_dump (GtkTreeModelRefCount *ref_model); +gboolean gtk_tree_model_ref_count_check_level (GtkTreeModelRefCount *ref_model, + GtkTreeIter *parent, + gint expected_ref_count, + gboolean recurse); +gboolean gtk_tree_model_ref_count_check_node (GtkTreeModelRefCount *ref_model, + GtkTreeIter *iter, + gint expected_ref_count); + +#endif /* __GTK_TREE_MODEL_REF_COUNT_H__ */