From 6bffd407fd4f4d4d5b5c5f5ef6d9b43c44b7fe03 Mon Sep 17 00:00:00 2001 From: Bastian Winkler Date: Fri, 21 Jan 2011 14:50:44 +0100 Subject: [PATCH] model: Add support to define rows in ClutterScript This adds a custom "rows" property, that allows to define the rows of a ClutterModel. A single row can either an array of all columns or an object with column-name : column-value pairs. http://bugzilla.clutter-project.org/show_bug.cgi?id=2528 --- clutter/clutter-model.c | 212 +++++++++++++++++++++++++----- tests/conform/test-model.c | 35 +++++ tests/data/test-script-model.json | 8 ++ 3 files changed, 219 insertions(+), 36 deletions(-) diff --git a/clutter/clutter-model.c b/clutter/clutter-model.c index 7bf2fb55f..880b73a91 100644 --- a/clutter/clutter-model.c +++ b/clutter/clutter-model.c @@ -117,13 +117,19 @@ * * ClutterModel custom properties for #ClutterScript * #ClutterModel defines a custom property "columns" for #ClutterScript - * which allows defining the column names and types. - * - * Example of the "columns" custom property + * which allows defining the column names and types. It also defines a custom + * "rows" property which allows filling the #ClutterModel with some + * data. + * + * Example of the "columns" and "rows" custom properties * The definition below will create a #ClutterListModel with three * columns: the first one with name "Name" and containing strings; the * second one with name "Score" and containing integers; the third one with - * name "Icon" and containing #ClutterTextures. + * name "Icon" and containing #ClutterTextures. The model is filled + * with three rows. A row can be defined either with an array that holds + * all columns of a row, or an object that holds "column-name" : + * "column-value" pairs. + * * * { * "type" : "ClutterListModel", @@ -132,6 +138,11 @@ * [ "Name", "gchararray" ], * [ "Score", "gint" ], * [ "Icon", "ClutterTexture" ] + * ], + * "rows" : [ + * [ "Team 1", 42, { "type" : "ClutterTexture", "filename" : "team1.png" } ], + * [ "Team 2", 23, "team2-icon-script-id" ], + * { "Name" : "Team 3", "Icon" : "team3-icon-script-id" } * ] * } * @@ -157,6 +168,7 @@ #include "clutter-private.h" #include "clutter-debug.h" #include "clutter-scriptable.h" +#include "clutter-script-private.h" static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); @@ -528,49 +540,73 @@ clutter_model_parse_custom_node (ClutterScriptable *scriptable, const gchar *name, JsonNode *node) { - GSList *columns = NULL; - GList *elements, *l; - - if (strcmp (name, "columns") != 0) - return FALSE; - - if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) - return FALSE; - - elements = json_array_get_elements (json_node_get_array (node)); - - for (l = elements; l != NULL; l = l->next) + if (strcmp (name, "columns") == 0) { - JsonNode *child_node = l->data; - JsonArray *array = json_node_get_array (child_node); - ColumnInfo *cinfo; - const gchar *column_name; - const gchar *type_name; + GSList *columns = NULL; + GList *elements, *l; - if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY || - json_array_get_length (array) != 2) + if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) + return FALSE; + + elements = json_array_get_elements (json_node_get_array (node)); + + for (l = elements; l != NULL; l = l->next) { - g_warning ("A column must be an array of " - "[\"column-name\", \"GType-name\"] pairs"); - return FALSE; + JsonNode *child_node = l->data; + JsonArray *array = json_node_get_array (child_node); + ColumnInfo *cinfo; + const gchar *column_name; + const gchar *type_name; + + if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY || + json_array_get_length (array) != 2) + { + g_warning ("A column must be an array of " + "[\"column-name\", \"GType-name\"] pairs"); + return FALSE; + } + + column_name = json_array_get_string_element (array, 0); + type_name = json_array_get_string_element (array, 1); + + cinfo = g_slice_new0 (ColumnInfo); + cinfo->name = g_strdup (column_name); + cinfo->type = clutter_script_get_type_from_name (script, type_name); + + columns = g_slist_prepend (columns, cinfo); } - column_name = json_array_get_string_element (array, 0); - type_name = json_array_get_string_element (array, 1); + g_list_free (elements); - cinfo = g_slice_new0 (ColumnInfo); - cinfo->name = g_strdup (column_name); - cinfo->type = clutter_script_get_type_from_name (script, type_name); + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, g_slist_reverse (columns)); - columns = g_slist_prepend (columns, cinfo); + return TRUE; } + else if (strcmp (name, "rows") == 0) + { + GSList *rows = NULL; + GList *elements, *l; - g_list_free (elements); + if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY) + return FALSE; - g_value_init (value, G_TYPE_POINTER); - g_value_set_pointer (value, g_slist_reverse (columns)); + /* + * at this point we have no information about the column types, so + * we just copy the json elements and resolve them in the + * set_custom_property method + */ + elements = json_array_get_elements (json_node_get_array (node)); + for (l = elements; l != NULL; l = l->next) + rows = g_slist_prepend (rows, json_node_copy (l->data)); + g_list_free (elements); - return TRUE; + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, g_slist_reverse (rows)); + + return TRUE; + } + return FALSE; } static void @@ -604,6 +640,110 @@ clutter_model_set_custom_property (ClutterScriptable *scriptable, g_slist_free (columns); } + else if (strcmp (name, "rows") == 0) + { + ClutterModel *model = CLUTTER_MODEL (scriptable); + GSList *rows, *l; + guint n_columns, row = 0; + + rows = g_value_get_pointer (value); + n_columns = clutter_model_get_n_columns (model); + + for (l = rows; l; l = l->next) + { + JsonNode *node = l->data; + guint *columns, i, n_values = 0; + GValueArray *values; + + if (JSON_NODE_TYPE (node) == JSON_NODE_ARRAY) + { + JsonArray *array = json_node_get_array (node); + if (json_array_get_length (array) != n_columns) + { + g_warning ("Row %d contains the wrong count of columns", + g_slist_position (rows, l) + 1); + row++; + continue; + } + + n_values = n_columns; + columns = g_new (guint, n_values); + values = g_value_array_new (n_values); + + for (i = 0; i < n_values; i++) + { + GType column_type; + const gchar *column_name; + GValue v = { 0, }; + + column_type = clutter_model_get_column_type (model, i); + column_name = clutter_model_get_column_name (model, i); + columns[i] = i; + g_value_init (&v, column_type); + clutter_script_parse_node (script, &v, column_name, + json_array_get_element (array, i), + NULL); + g_value_array_append (values, &v); + g_value_unset (&v); + } + } + else if (JSON_NODE_TYPE (node) == JSON_NODE_OBJECT) + { + JsonObject *object = json_node_get_object (node); + GList *members, *m; + guint column = 0; + + n_values = json_object_get_size (object); + columns = g_new (guint, n_values); + values = g_value_array_new (n_values); + + members = json_object_get_members (object); + for (m = members; m; m = m->next) + { + const gchar *mname = m->data; + + for (i = 0; i < clutter_model_get_n_columns (model); i++) + { + const gchar *cname; + + cname = clutter_model_get_column_name (model, i); + if (strcmp (mname, cname) == 0) + { + JsonNode *member; + GType col_type; + const gchar *col_name; + GValue v = { 0, }; + + col_type = clutter_model_get_column_type (model, i); + col_name = clutter_model_get_column_name (model, i); + columns[column] = i; + g_value_init (&v, col_type); + member = json_object_get_member (object, mname); + clutter_script_parse_node (script, &v, + col_name, member, + NULL); + g_value_array_append (values, &v); + g_value_unset (&v); + break; + } + } + column++; + } + } + else + { + row++; + continue; + } + + clutter_model_insertv (model, row, n_values, columns, values->values); + g_value_array_free (values); + g_free (columns); + json_node_free (node); + row++; + } + g_slist_free (rows); + } } diff --git a/tests/conform/test-model.c b/tests/conform/test-model.c index b9fb279c8..e702063e7 100644 --- a/tests/conform/test-model.c +++ b/tests/conform/test-model.c @@ -363,6 +363,8 @@ test_list_model_from_script (TestConformSimpleFixture *fixture, gchar *test_file; const gchar *name; GType type; + ClutterModelIter *iter; + GValue value = { 0, }; test_file = clutter_test_get_data_file ("test-script-model.json"); clutter_script_load_from_file (script, test_file, &error); @@ -397,4 +399,37 @@ test_list_model_from_script (TestConformSimpleFixture *fixture, g_assert (strcmp (name, "actor-column") == 0); g_assert (type == CLUTTER_TYPE_RECTANGLE); + + g_assert (clutter_model_get_n_rows (CLUTTER_MODEL (model)) == 3); + + iter = clutter_model_get_iter_at_row (CLUTTER_MODEL (model), 0); + clutter_model_iter_get_value (iter, 0, &value); + g_assert (G_VALUE_HOLDS_STRING (&value)); + g_assert (strcmp (g_value_get_string (&value), "text-row-1") == 0); + g_value_unset (&value); + + clutter_model_iter_get_value (iter, 1, &value); + g_assert (G_VALUE_HOLDS_INT (&value)); + g_assert (g_value_get_int (&value) == 1); + g_value_unset (&value); + + clutter_model_iter_get_value (iter, 2, &value); + g_assert (G_VALUE_HOLDS_OBJECT (&value)); + g_assert (g_value_get_object (&value) == NULL); + g_value_unset (&value); + + iter = clutter_model_iter_next (iter); + clutter_model_iter_get_value (iter, 2, &value); + g_assert (G_VALUE_HOLDS_OBJECT (&value)); + g_assert (CLUTTER_IS_RECTANGLE (g_value_get_object (&value))); + g_value_unset (&value); + + iter = clutter_model_iter_next (iter); + clutter_model_iter_get_value (iter, 2, &value); + g_assert (G_VALUE_HOLDS_OBJECT (&value)); + g_assert (CLUTTER_IS_RECTANGLE (g_value_get_object (&value))); + g_assert (strcmp (clutter_actor_get_name (g_value_get_object (&value)), + "actor-row-3") == 0); + g_value_unset (&value); + g_object_unref (iter); } diff --git a/tests/data/test-script-model.json b/tests/data/test-script-model.json index 075bfbe6a..9bd6aefc5 100644 --- a/tests/data/test-script-model.json +++ b/tests/data/test-script-model.json @@ -5,5 +5,13 @@ [ "text-column", "gchararray" ], [ "int-column", "gint" ], [ "actor-column", "ClutterRectangle" ] + ], + "rows" : [ + [ "text-row-1", 1, null ], + [ "text-row-2", 2, { "type" : "ClutterRectangle", "color" : "blue" } ], + { + "int-column" : 3, + "actor-column" : { "type" : "ClutterRectangle", "name" : "actor-row-3" } + } ] }