gtk/tests/testtreeview.c
Matthias Clasen 386b63b85d scrolledwindow: Don't take adjustments in new()
In 99.9% of all cases, these are just NULL, NULL.
So just do away with these arguments, people can
use the setters for the rare cases where they want
the scrolled window to use a different adjustment.
2020-06-24 11:25:09 -04:00

1369 lines
36 KiB
C

/* testtreeview.c
* Copyright (C) 2001 Red Hat, Inc
* Author: Jonathan Blandford
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <gtk/gtk.h>
#include <stdlib.h>
/* Don't copy this bad example; inline RGB data is always a better
* idea than inline XPMs.
*/
static const char *book_closed_xpm[] = {
"16 16 6 1",
" c None s None",
". c black",
"X c red",
"o c yellow",
"O c #808080",
"# c white",
" ",
" .. ",
" ..XX. ",
" ..XXXXX. ",
" ..XXXXXXXX. ",
".ooXXXXXXXXX. ",
"..ooXXXXXXXXX. ",
".X.ooXXXXXXXXX. ",
".XX.ooXXXXXX.. ",
" .XX.ooXXX..#O ",
" .XX.oo..##OO. ",
" .XX..##OO.. ",
" .X.#OO.. ",
" ..O.. ",
" .. ",
" "
};
static void run_automated_tests (void);
/* This custom model is to test custom model use. */
#define GTK_TYPE_MODEL_TYPES (gtk_tree_model_types_get_type ())
#define GTK_TREE_MODEL_TYPES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_MODEL_TYPES, GtkTreeModelTypes))
#define GTK_TREE_MODEL_TYPES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_MODEL_TYPES, GtkTreeModelTypesClass))
#define GTK_IS_TREE_MODEL_TYPES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_MODEL_TYPES))
#define GTK_IS_TREE_MODEL_TYPES_GET_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MODEL_TYPES))
typedef struct _GtkTreeModelTypes GtkTreeModelTypes;
typedef struct _GtkTreeModelTypesClass GtkTreeModelTypesClass;
struct _GtkTreeModelTypes
{
GObject parent;
gint stamp;
};
struct _GtkTreeModelTypesClass
{
GObjectClass parent_class;
guint (* get_flags) (GtkTreeModel *tree_model);
gint (* get_n_columns) (GtkTreeModel *tree_model);
GType (* get_column_type) (GtkTreeModel *tree_model,
gint index);
gboolean (* get_iter) (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path);
GtkTreePath *(* get_path) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
void (* get_value) (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint column,
GValue *value);
gboolean (* iter_next) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
gboolean (* iter_children) (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent);
gboolean (* iter_has_child) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
gint (* iter_n_children) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
gboolean (* iter_nth_child) (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n);
gboolean (* iter_parent) (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child);
void (* ref_iter) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
void (* unref_iter) (GtkTreeModel *tree_model,
GtkTreeIter *iter);
/* These will be moved into the GtkTreeModelIface eventually */
void (* changed) (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter);
void (* inserted) (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter);
void (* child_toggled) (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter);
void (* deleted) (GtkTreeModel *tree_model,
GtkTreePath *path);
};
GType gtk_tree_model_types_get_type (void) G_GNUC_CONST;
GtkTreeModelTypes *gtk_tree_model_types_new (void);
typedef enum
{
COLUMNS_NONE,
COLUMNS_ONE,
COLUMNS_LOTS,
COLUMNS_LAST
} ColumnsType;
static const char *column_type_names[] = {
"No columns",
"One column",
"Many columns"
};
#define N_COLUMNS 9
static GType*
get_model_types (void)
{
static GType column_types[N_COLUMNS] = { 0 };
if (column_types[0] == 0)
{
column_types[0] = G_TYPE_STRING;
column_types[1] = G_TYPE_STRING;
column_types[2] = GDK_TYPE_PIXBUF;
column_types[3] = G_TYPE_FLOAT;
column_types[4] = G_TYPE_UINT;
column_types[5] = G_TYPE_UCHAR;
column_types[6] = G_TYPE_CHAR;
#define BOOL_COLUMN 7
column_types[BOOL_COLUMN] = G_TYPE_BOOLEAN;
column_types[8] = G_TYPE_INT;
}
return column_types;
}
static void
toggled_callback (GtkCellRendererToggle *celltoggle,
gchar *path_string,
GtkTreeView *tree_view)
{
GtkTreeModel *model = NULL;
GtkTreeModelSort *sort_model = NULL;
GtkTreePath *path;
GtkTreeIter iter;
gboolean active = FALSE;
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
model = gtk_tree_view_get_model (tree_view);
if (GTK_IS_TREE_MODEL_SORT (model))
{
sort_model = GTK_TREE_MODEL_SORT (model);
model = gtk_tree_model_sort_get_model (sort_model);
}
if (model == NULL)
return;
if (sort_model)
{
g_warning ("FIXME implement conversion from TreeModelSort iter to child model iter");
return;
}
path = gtk_tree_path_new_from_string (path_string);
if (!gtk_tree_model_get_iter (model,
&iter, path))
{
g_warning ("%s: bad path?", G_STRLOC);
return;
}
gtk_tree_path_free (path);
if (GTK_IS_LIST_STORE (model))
{
gtk_tree_model_get (GTK_TREE_MODEL (model),
&iter,
BOOL_COLUMN,
&active,
-1);
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
BOOL_COLUMN,
!active,
-1);
}
else if (GTK_IS_TREE_STORE (model))
{
gtk_tree_model_get (GTK_TREE_MODEL (model),
&iter,
BOOL_COLUMN,
&active,
-1);
gtk_tree_store_set (GTK_TREE_STORE (model),
&iter,
BOOL_COLUMN,
!active,
-1);
}
else
g_warning ("don't know how to actually toggle value for model type %s",
g_type_name (G_TYPE_FROM_INSTANCE (model)));
}
static void
edited_callback (GtkCellRendererText *renderer,
const gchar *path_string,
const gchar *new_text,
GtkTreeView *tree_view)
{
GtkTreeModel *model = NULL;
GtkTreeModelSort *sort_model = NULL;
GtkTreePath *path;
GtkTreeIter iter;
guint value = atoi (new_text);
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
model = gtk_tree_view_get_model (tree_view);
if (GTK_IS_TREE_MODEL_SORT (model))
{
sort_model = GTK_TREE_MODEL_SORT (model);
model = gtk_tree_model_sort_get_model (sort_model);
}
if (model == NULL)
return;
if (sort_model)
{
g_warning ("FIXME implement conversion from TreeModelSort iter to child model iter");
return;
}
path = gtk_tree_path_new_from_string (path_string);
if (!gtk_tree_model_get_iter (model,
&iter, path))
{
g_warning ("%s: bad path?", G_STRLOC);
return;
}
gtk_tree_path_free (path);
if (GTK_IS_LIST_STORE (model))
{
gtk_list_store_set (GTK_LIST_STORE (model),
&iter,
4,
value,
-1);
}
else if (GTK_IS_TREE_STORE (model))
{
gtk_tree_store_set (GTK_TREE_STORE (model),
&iter,
4,
value,
-1);
}
else
g_warning ("don't know how to actually toggle value for model type %s",
g_type_name (G_TYPE_FROM_INSTANCE (model)));
}
static ColumnsType current_column_type = COLUMNS_LOTS;
static void
set_columns_type (GtkTreeView *tree_view, ColumnsType type)
{
GtkTreeViewColumn *col;
GtkCellRenderer *rend;
GdkPixbuf *pixbuf;
GtkWidget *image;
GtkAdjustment *adjustment;
current_column_type = type;
col = gtk_tree_view_get_column (tree_view, 0);
while (col)
{
gtk_tree_view_remove_column (tree_view, col);
col = gtk_tree_view_get_column (tree_view, 0);
}
switch (type)
{
case COLUMNS_NONE:
break;
case COLUMNS_LOTS:
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 1",
rend,
"text", 1,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
col = gtk_tree_view_column_new();
gtk_tree_view_column_set_title (col, "Column 2");
rend = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (col, rend, FALSE);
gtk_tree_view_column_add_attribute (col, rend, "pixbuf", 2);
rend = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (col, rend, TRUE);
gtk_tree_view_column_add_attribute (col, rend, "text", 0);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
gtk_tree_view_set_expander_column (tree_view, col);
rend = gtk_cell_renderer_toggle_new ();
g_signal_connect (rend, "toggled",
G_CALLBACK (toggled_callback), tree_view);
col = gtk_tree_view_column_new_with_attributes ("Column 3",
rend,
"active", BOOL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)book_closed_xpm);
image = gtk_image_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
gtk_tree_view_column_set_widget (col, image);
rend = gtk_cell_renderer_toggle_new ();
/* you could also set this per-row by tying it to a column
* in the model of course.
*/
g_object_set (rend, "radio", TRUE, NULL);
g_signal_connect (rend, "toggled",
G_CALLBACK (toggled_callback), tree_view);
col = gtk_tree_view_column_new_with_attributes ("Column 4",
rend,
"active", BOOL_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
rend = gtk_cell_renderer_spin_new ();
adjustment = gtk_adjustment_new (0, 0, 10000, 100, 100, 100);
g_object_set (rend, "editable", TRUE, NULL);
g_object_set (rend, "adjustment", adjustment, NULL);
g_signal_connect (rend, "edited",
G_CALLBACK (edited_callback), tree_view);
col = gtk_tree_view_column_new_with_attributes ("Column 5",
rend,
"text", 4,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
#if 0
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 6",
rend,
"text", 4,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 7",
rend,
"text", 5,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 8",
rend,
"text", 6,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 9",
rend,
"text", 7,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 10",
rend,
"text", 8,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), col);
#endif
G_GNUC_FALLTHROUGH;
case COLUMNS_ONE:
rend = gtk_cell_renderer_text_new ();
col = gtk_tree_view_column_new_with_attributes ("Column 0",
rend,
"text", 0,
NULL);
gtk_tree_view_insert_column (GTK_TREE_VIEW (tree_view), col, 0);
break;
case COLUMNS_LAST:
default:
break;
}
}
static ColumnsType
get_columns_type (void)
{
return current_column_type;
}
static GdkPixbuf *our_pixbuf;
typedef enum
{
/* MODEL_TYPES, */
MODEL_TREE,
MODEL_LIST,
MODEL_SORTED_TREE,
MODEL_SORTED_LIST,
MODEL_EMPTY_LIST,
MODEL_EMPTY_TREE,
MODEL_NULL,
MODEL_LAST
} ModelType;
/* FIXME add a custom model to test */
static GtkTreeModel *models[MODEL_LAST];
static const char *model_names[MODEL_LAST] = {
"GtkTreeStore",
"GtkListStore",
"GtkTreeModelSort wrapping GtkTreeStore",
"GtkTreeModelSort wrapping GtkListStore",
"Empty GtkListStore",
"Empty GtkTreeStore",
"NULL (no model)"
};
static GtkTreeModel*
create_list_model (void)
{
GtkListStore *store;
GtkTreeIter iter;
gint i;
GType *t;
t = get_model_types ();
store = gtk_list_store_new (N_COLUMNS,
t[0], t[1], t[2],
t[3], t[4], t[5],
t[6], t[7], t[8]);
i = 0;
while (i < 200)
{
char *msg;
gtk_list_store_append (store, &iter);
msg = g_strdup_printf ("%d", i);
gtk_list_store_set (store, &iter, 0, msg, 1, "Foo! Foo! Foo!",
2, our_pixbuf,
3, 7.0, 4, (guint) 9000,
5, 'f', 6, 'g',
7, TRUE, 8, 23245454,
-1);
g_free (msg);
++i;
}
return GTK_TREE_MODEL (store);
}
static void
typesystem_recurse (GType type,
GtkTreeIter *parent_iter,
GtkTreeStore *store)
{
GType* children;
guint n_children = 0;
gint i;
GtkTreeIter iter;
gchar *str;
gtk_tree_store_append (store, &iter, parent_iter);
str = g_strdup_printf ("%ld", (glong)type);
gtk_tree_store_set (store, &iter, 0, str, 1, g_type_name (type),
2, our_pixbuf,
3, 7.0, 4, (guint) 9000,
5, 'f', 6, 'g',
7, TRUE, 8, 23245454,
-1);
g_free (str);
children = g_type_children (type, &n_children);
i = 0;
while (i < n_children)
{
typesystem_recurse (children[i], &iter, store);
++i;
}
g_free (children);
}
static GtkTreeModel*
create_tree_model (void)
{
GtkTreeStore *store;
gint i;
GType *t;
/* Make the tree more interesting */
/* - we need this magic here so we are sure the type ends up being
* registered and gcc doesn't optimize away the code */
g_type_class_unref (g_type_class_ref (gtk_scrolled_window_get_type ()));
g_type_class_unref (g_type_class_ref (gtk_label_get_type ()));
g_type_class_unref (g_type_class_ref (gtk_scrollbar_get_type ()));
g_type_class_unref (g_type_class_ref (pango_layout_get_type ()));
t = get_model_types ();
store = gtk_tree_store_new (N_COLUMNS,
t[0], t[1], t[2],
t[3], t[4], t[5],
t[6], t[7], t[8]);
i = 0;
while (i < G_TYPE_FUNDAMENTAL_MAX)
{
typesystem_recurse (i, NULL, store);
++i;
}
return GTK_TREE_MODEL (store);
}
static void
model_selected (GtkComboBox *combo_box, gpointer data)
{
GtkTreeView *tree_view = GTK_TREE_VIEW (data);
gint hist;
hist = gtk_combo_box_get_active (combo_box);
if (models[hist] != gtk_tree_view_get_model (tree_view))
{
gtk_tree_view_set_model (tree_view, models[hist]);
}
}
static void
columns_selected (GtkComboBox *combo_box, gpointer data)
{
GtkTreeView *tree_view = GTK_TREE_VIEW (data);
gint hist;
hist = gtk_combo_box_get_active (combo_box);
if (hist != get_columns_type ())
{
set_columns_type (tree_view, hist);
}
}
static void
on_row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
gpointer user_data)
{
g_print ("Row activated\n");
}
static void
quit_cb (GtkWidget *widget,
gpointer data)
{
gboolean *done = data;
*done = TRUE;
g_main_context_wakeup (NULL);
}
int
main (int argc,
char **argv)
{
GtkWidget *window;
GtkWidget *sw;
GtkWidget *tv;
GtkWidget *box;
GtkWidget *combo_box;
GtkTreeModel *model;
GdkContentFormats *targets;
gint i;
gboolean done = FALSE;
gtk_init ();
if (g_getenv ("RTL"))
gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
our_pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **) book_closed_xpm);
#if 0
models[MODEL_TYPES] = GTK_TREE_MODEL (gtk_tree_model_types_new ());
#endif
models[MODEL_LIST] = create_list_model ();
models[MODEL_TREE] = create_tree_model ();
model = create_list_model ();
models[MODEL_SORTED_LIST] = gtk_tree_model_sort_new_with_model (model);
g_object_unref (model);
model = create_tree_model ();
models[MODEL_SORTED_TREE] = gtk_tree_model_sort_new_with_model (model);
g_object_unref (model);
models[MODEL_EMPTY_LIST] = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_INT));
models[MODEL_EMPTY_TREE] = GTK_TREE_MODEL (gtk_tree_store_new (1, G_TYPE_INT));
models[MODEL_NULL] = NULL;
run_automated_tests ();
window = gtk_window_new ();
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
gtk_window_set_default_size (GTK_WINDOW (window), 430, 400);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_window_set_child (GTK_WINDOW (window), box);
tv = gtk_tree_view_new_with_model (models[0]);
g_signal_connect (tv, "row-activated", G_CALLBACK (on_row_activated), NULL);
targets = gdk_content_formats_new_for_gtype (GTK_TYPE_TREE_ROW_DATA);
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tv),
GDK_BUTTON1_MASK,
targets,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (tv),
targets,
GDK_ACTION_MOVE | GDK_ACTION_COPY);
gdk_content_formats_unref (targets);
/* Model menu */
combo_box = gtk_combo_box_text_new ();
gtk_widget_set_halign (combo_box, GTK_ALIGN_CENTER);
for (i = 0; i < MODEL_LAST; i++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), model_names[i]);
gtk_box_append (GTK_BOX (box), combo_box);
g_signal_connect (combo_box,
"changed",
G_CALLBACK (model_selected),
tv);
/* Columns menu */
combo_box = gtk_combo_box_text_new ();
gtk_widget_set_halign (combo_box, GTK_ALIGN_CENTER);
for (i = 0; i < COLUMNS_LAST; i++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), column_type_names[i]);
gtk_box_append (GTK_BOX (box), combo_box);
set_columns_type (GTK_TREE_VIEW (tv), COLUMNS_LOTS);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), COLUMNS_LOTS);
g_signal_connect (combo_box,
"changed",
G_CALLBACK (columns_selected),
tv);
sw = gtk_scrolled_window_new ();
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_box_append (GTK_BOX (box), sw);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), tv);
gtk_widget_show (window);
while (!done)
g_main_context_iteration (NULL, TRUE);
return 0;
}
/*
* GtkTreeModelTypes
*/
static void gtk_tree_model_types_init (GtkTreeModelTypes *model_types);
static void gtk_tree_model_types_tree_model_init (GtkTreeModelIface *iface);
static gint gtk_real_model_types_get_n_columns (GtkTreeModel *tree_model);
static GType gtk_real_model_types_get_column_type (GtkTreeModel *tree_model,
gint index);
static GtkTreePath *gtk_real_model_types_get_path (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static void gtk_real_model_types_get_value (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint column,
GValue *value);
static gboolean gtk_real_model_types_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gboolean gtk_real_model_types_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent);
static gboolean gtk_real_model_types_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gint gtk_real_model_types_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter);
static gboolean gtk_real_model_types_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n);
static gboolean gtk_real_model_types_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child);
GType
gtk_tree_model_types_get_type (void)
{
static GType model_types_type = 0;
if (!model_types_type)
{
const GTypeInfo model_types_info =
{
sizeof (GtkTreeModelTypesClass),
NULL, /* base_init */
NULL, /* base_finalize */
NULL, /* class_init */
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkTreeModelTypes),
0,
(GInstanceInitFunc) gtk_tree_model_types_init
};
const GInterfaceInfo tree_model_info =
{
(GInterfaceInitFunc) gtk_tree_model_types_tree_model_init,
NULL,
NULL
};
model_types_type = g_type_register_static (G_TYPE_OBJECT,
"GtkTreeModelTypes",
&model_types_info, 0);
g_type_add_interface_static (model_types_type,
GTK_TYPE_TREE_MODEL,
&tree_model_info);
}
return model_types_type;
}
GtkTreeModelTypes *
gtk_tree_model_types_new (void)
{
GtkTreeModelTypes *retval;
retval = g_object_new (GTK_TYPE_MODEL_TYPES, NULL);
return retval;
}
static void
gtk_tree_model_types_tree_model_init (GtkTreeModelIface *iface)
{
iface->get_n_columns = gtk_real_model_types_get_n_columns;
iface->get_column_type = gtk_real_model_types_get_column_type;
iface->get_path = gtk_real_model_types_get_path;
iface->get_value = gtk_real_model_types_get_value;
iface->iter_next = gtk_real_model_types_iter_next;
iface->iter_children = gtk_real_model_types_iter_children;
iface->iter_has_child = gtk_real_model_types_iter_has_child;
iface->iter_n_children = gtk_real_model_types_iter_n_children;
iface->iter_nth_child = gtk_real_model_types_iter_nth_child;
iface->iter_parent = gtk_real_model_types_iter_parent;
}
static void
gtk_tree_model_types_init (GtkTreeModelTypes *model_types)
{
model_types->stamp = g_random_int ();
}
static GType column_types[] = {
G_TYPE_STRING, /* GType */
G_TYPE_STRING /* type name */
};
static gint
gtk_real_model_types_get_n_columns (GtkTreeModel *tree_model)
{
return G_N_ELEMENTS (column_types);
}
static GType
gtk_real_model_types_get_column_type (GtkTreeModel *tree_model,
gint index)
{
g_return_val_if_fail (index < G_N_ELEMENTS (column_types), G_TYPE_INVALID);
return column_types[index];
}
#if 0
/* Use default implementation of this */
static gboolean
gtk_real_model_types_get_iter (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path)
{
}
#endif
/* The toplevel nodes of the tree are the reserved types, G_TYPE_NONE through
* G_TYPE_RESERVED_FUNDAMENTAL.
*/
static GtkTreePath *
gtk_real_model_types_get_path (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GtkTreePath *retval;
GType type;
GType parent;
g_return_val_if_fail (GTK_IS_TREE_MODEL_TYPES (tree_model), NULL);
g_return_val_if_fail (iter != NULL, NULL);
type = GPOINTER_TO_INT (iter->user_data);
retval = gtk_tree_path_new ();
parent = g_type_parent (type);
while (parent != G_TYPE_INVALID)
{
GType* children = g_type_children (parent, NULL);
gint i = 0;
if (!children || children[0] == G_TYPE_INVALID)
{
g_warning ("bad iterator?");
return NULL;
}
while (children[i] != type)
++i;
gtk_tree_path_prepend_index (retval, i);
g_free (children);
type = parent;
parent = g_type_parent (parent);
}
/* The fundamental type itself is the index on the toplevel */
gtk_tree_path_prepend_index (retval, type);
return retval;
}
static void
gtk_real_model_types_get_value (GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint column,
GValue *value)
{
GType type;
type = GPOINTER_TO_INT (iter->user_data);
switch (column)
{
case 0:
{
gchar *str;
g_value_init (value, G_TYPE_STRING);
str = g_strdup_printf ("%ld", (long int) type);
g_value_set_string (value, str);
g_free (str);
}
break;
case 1:
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, g_type_name (type));
break;
default:
g_warning ("Bad column %d requested", column);
}
}
static gboolean
gtk_real_model_types_iter_next (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GType parent;
GType type;
type = GPOINTER_TO_INT (iter->user_data);
parent = g_type_parent (type);
if (parent == G_TYPE_INVALID)
{
/* find next _valid_ fundamental type */
do
type++;
while (!g_type_name (type) && type <= G_TYPE_FUNDAMENTAL_MAX);
if (type <= G_TYPE_FUNDAMENTAL_MAX)
{
/* found one */
iter->user_data = GINT_TO_POINTER (type);
return TRUE;
}
else
return FALSE;
}
else
{
GType* children = g_type_children (parent, NULL);
gint i = 0;
g_assert (children != NULL);
while (children[i] != type)
++i;
++i;
if (children[i] != G_TYPE_INVALID)
{
iter->user_data = GINT_TO_POINTER (children[i]);
g_free (children);
return TRUE;
}
else
{
g_free (children);
return FALSE;
}
}
}
static gboolean
gtk_real_model_types_iter_children (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
GType type;
GType* children;
type = GPOINTER_TO_INT (parent->user_data);
children = g_type_children (type, NULL);
if (!children || children[0] == G_TYPE_INVALID)
{
g_free (children);
return FALSE;
}
else
{
iter->user_data = GINT_TO_POINTER (children[0]);
g_free (children);
return TRUE;
}
}
static gboolean
gtk_real_model_types_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GType type;
GType* children;
type = GPOINTER_TO_INT (iter->user_data);
children = g_type_children (type, NULL);
if (!children || children[0] == G_TYPE_INVALID)
{
g_free (children);
return FALSE;
}
else
{
g_free (children);
return TRUE;
}
}
static gint
gtk_real_model_types_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
if (iter == NULL)
{
return G_TYPE_FUNDAMENTAL_MAX;
}
else
{
GType type;
GType* children;
guint n_children = 0;
type = GPOINTER_TO_INT (iter->user_data);
children = g_type_children (type, &n_children);
g_free (children);
return n_children;
}
}
static gboolean
gtk_real_model_types_iter_nth_child (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n)
{
if (parent == NULL)
{
/* fundamental type */
if (n < G_TYPE_FUNDAMENTAL_MAX)
{
iter->user_data = GINT_TO_POINTER (n);
return TRUE;
}
else
return FALSE;
}
else
{
GType type = GPOINTER_TO_INT (parent->user_data);
guint n_children = 0;
GType* children = g_type_children (type, &n_children);
if (n_children == 0)
{
g_free (children);
return FALSE;
}
else if (n >= n_children)
{
g_free (children);
return FALSE;
}
else
{
iter->user_data = GINT_TO_POINTER (children[n]);
g_free (children);
return TRUE;
}
}
}
static gboolean
gtk_real_model_types_iter_parent (GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
GType type;
GType parent;
type = GPOINTER_TO_INT (child->user_data);
parent = g_type_parent (type);
if (parent == G_TYPE_INVALID)
{
if (type > G_TYPE_FUNDAMENTAL_MAX)
g_warning ("no parent for %ld %s\n",
(long int) type,
g_type_name (type));
return FALSE;
}
else
{
iter->user_data = GINT_TO_POINTER (parent);
return TRUE;
}
}
/*
* Automated testing
*/
#if 0
static void
treestore_torture_recurse (GtkTreeStore *store,
GtkTreeIter *root,
gint depth)
{
GtkTreeModel *model;
gint i;
GtkTreeIter iter;
model = GTK_TREE_MODEL (store);
if (depth > 2)
return;
++depth;
gtk_tree_store_append (store, &iter, root);
gtk_tree_model_iter_children (model, &iter, root);
i = 0;
while (i < 100)
{
gtk_tree_store_append (store, &iter, root);
++i;
}
while (gtk_tree_model_iter_children (model, &iter, root))
gtk_tree_store_remove (store, &iter);
gtk_tree_store_append (store, &iter, root);
/* inserts before last node in tree */
i = 0;
while (i < 100)
{
gtk_tree_store_insert_before (store, &iter, root, &iter);
++i;
}
/* inserts after the node before the last node */
i = 0;
while (i < 100)
{
gtk_tree_store_insert_after (store, &iter, root, &iter);
++i;
}
/* inserts after the last node */
gtk_tree_store_append (store, &iter, root);
i = 0;
while (i < 100)
{
gtk_tree_store_insert_after (store, &iter, root, &iter);
++i;
}
/* remove everything again */
while (gtk_tree_model_iter_children (model, &iter, root))
gtk_tree_store_remove (store, &iter);
/* Prepends */
gtk_tree_store_prepend (store, &iter, root);
i = 0;
while (i < 100)
{
gtk_tree_store_prepend (store, &iter, root);
++i;
}
/* remove everything again */
while (gtk_tree_model_iter_children (model, &iter, root))
gtk_tree_store_remove (store, &iter);
gtk_tree_store_append (store, &iter, root);
gtk_tree_store_append (store, &iter, root);
gtk_tree_store_append (store, &iter, root);
gtk_tree_store_append (store, &iter, root);
while (gtk_tree_model_iter_children (model, &iter, root))
{
treestore_torture_recurse (store, &iter, depth);
gtk_tree_store_remove (store, &iter);
}
}
#endif
static void
run_automated_tests (void)
{
g_print ("Running automated tests...\n");
/* FIXME TreePath basic verification */
/* FIXME generic consistency checks on the models */
{
/* Make sure list store mutations don't crash anything */
GtkListStore *store;
GtkTreeModel *model;
gint i;
GtkTreeIter iter;
store = gtk_list_store_new (1, G_TYPE_INT);
model = GTK_TREE_MODEL (store);
i = 0;
while (i < 100)
{
gtk_list_store_append (store, &iter);
++i;
}
while (gtk_tree_model_get_iter_first (model, &iter))
gtk_list_store_remove (store, &iter);
gtk_list_store_append (store, &iter);
/* inserts before last node in list */
i = 0;
while (i < 100)
{
gtk_list_store_insert_before (store, &iter, &iter);
++i;
}
/* inserts after the node before the last node */
i = 0;
while (i < 100)
{
gtk_list_store_insert_after (store, &iter, &iter);
++i;
}
/* inserts after the last node */
gtk_list_store_append (store, &iter);
i = 0;
while (i < 100)
{
gtk_list_store_insert_after (store, &iter, &iter);
++i;
}
/* remove everything again */
while (gtk_tree_model_get_iter_first (model, &iter))
gtk_list_store_remove (store, &iter);
/* Prepends */
gtk_list_store_prepend (store, &iter);
i = 0;
while (i < 100)
{
gtk_list_store_prepend (store, &iter);
++i;
}
/* remove everything again */
while (gtk_tree_model_get_iter_first (model, &iter))
gtk_list_store_remove (store, &iter);
g_object_unref (store);
}
{
/* Make sure tree store mutations don't crash anything */
GtkTreeStore *store;
GtkTreeIter root;
store = gtk_tree_store_new (1, G_TYPE_INT);
gtk_tree_store_append (GTK_TREE_STORE (store), &root, NULL);
/* Remove test until it is rewritten to work */
/* treestore_torture_recurse (store, &root, 0);*/
g_object_unref (store);
}
g_print ("Passed.\n");
}