diff --git a/.gitignore b/.gitignore index fe8c173e6..04d89196b 100644 --- a/.gitignore +++ b/.gitignore @@ -238,6 +238,7 @@ TAGS /tests/conform/test-texture-fbo /tests/conform/test-script-single /tests/conform/test-script-child +/tests/conform/test-list-model-from-script /tests/conform/test-script-implicit-alpha /tests/conform/test-script-object-property /tests/conform/test-script-animation diff --git a/clutter/clutter-model.c b/clutter/clutter-model.c index b8c68d5df..27e0dafe4 100644 --- a/clutter/clutter-model.c +++ b/clutter/clutter-model.c @@ -132,8 +132,14 @@ #include "clutter-marshal.h" #include "clutter-private.h" #include "clutter-debug.h" +#include "clutter-scriptable.h" -G_DEFINE_ABSTRACT_TYPE (ClutterModel, clutter_model, G_TYPE_OBJECT); +static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE + (ClutterModel, clutter_model, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, + clutter_scriptable_iface_init)); enum { @@ -445,6 +451,103 @@ clutter_model_check_type (GType gtype) } +typedef struct { + gchar *name; + GType type; +} ColumnInfo; + +static gboolean +clutter_model_parse_custom_node (ClutterScriptable *scriptable, + ClutterScript *script, + GValue *value, + 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) + { + 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); + } + + g_list_free (elements); + + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, g_slist_reverse (columns)); + + return TRUE; +} + +static void +clutter_model_set_custom_property (ClutterScriptable *scriptable, + ClutterScript *script, + const gchar *name, + const GValue *value) +{ + if (strcmp (name, "columns") == 0) + { + ClutterModel *model = CLUTTER_MODEL (scriptable); + GSList *columns, *l; + guint n_columns; + gint i; + + columns = g_value_get_pointer (value); + n_columns = g_slist_length (columns); + + clutter_model_set_n_columns (model, n_columns, TRUE, TRUE); + + for (i = 0, l = columns; l != NULL; l = l->next, i++) + { + ColumnInfo *cinfo = l->data; + + clutter_model_set_column_name (model, i, cinfo->name); + clutter_model_set_column_type (model, i, cinfo->type); + + g_free (cinfo->name); + g_slice_free (ColumnInfo, cinfo); + } + + g_slist_free (columns); + } +} + + +static void +clutter_scriptable_iface_init (ClutterScriptableIface *iface) +{ + iface->parse_custom_node = clutter_model_parse_custom_node; + iface->set_custom_property = clutter_model_set_custom_property; +} /** * clutter_model_resort: diff --git a/tests/conform/test-conform-main.c b/tests/conform/test-conform-main.c index df551b5ef..54c4fd979 100644 --- a/tests/conform/test-conform-main.c +++ b/tests/conform/test-conform-main.c @@ -158,6 +158,7 @@ main (int argc, char **argv) TEST_CONFORM_SIMPLE ("/model", test_list_model_populate); TEST_CONFORM_SIMPLE ("/model", test_list_model_iterate); TEST_CONFORM_SIMPLE ("/model", test_list_model_filter); + TEST_CONFORM_SIMPLE ("/model", test_list_model_from_script); TEST_CONFORM_SIMPLE ("/color", test_color_from_string); TEST_CONFORM_SIMPLE ("/color", test_color_to_string); diff --git a/tests/conform/test-model.c b/tests/conform/test-model.c index 45ffc6492..056537ed3 100644 --- a/tests/conform/test-model.c +++ b/tests/conform/test-model.c @@ -335,3 +335,37 @@ test_list_model_populate (TestConformSimpleFixture *fixture, g_object_unref (test_data.model); } + +void +test_list_model_from_script (TestConformSimpleFixture *fixture, + gconstpointer dummy) +{ + ClutterScript *script = clutter_script_new (); + GObject *model; + GError *error = NULL; + gchar *test_file; + const gchar *name; + GType type; + + test_file = clutter_test_get_data_file ("test-script-model.json"); + clutter_script_load_from_file (script, test_file, &error); + if (g_test_verbose () && error) + g_print ("Error: %s", error->message); + g_assert (error == NULL); + + model = clutter_script_get_object (script, "test-model"); + + g_assert (CLUTTER_IS_MODEL (model)); + g_assert (clutter_model_get_n_columns (CLUTTER_MODEL (model)) == 3); + + name = clutter_model_get_column_name (CLUTTER_MODEL (model), 0); + type = clutter_model_get_column_type (CLUTTER_MODEL (model), 0); + g_assert (strcmp (name, "text-column") == 0); + g_assert (type == G_TYPE_STRING); + + name = clutter_model_get_column_name (CLUTTER_MODEL (model), 2); + type = clutter_model_get_column_type (CLUTTER_MODEL (model), 2); + g_print ("type: %s\n", g_type_name (type)); + g_assert (strcmp (name, "actor-column") == 0); + g_assert (type == CLUTTER_TYPE_RECTANGLE); +} diff --git a/tests/data/test-script-model.json b/tests/data/test-script-model.json new file mode 100644 index 000000000..075bfbe6a --- /dev/null +++ b/tests/data/test-script-model.json @@ -0,0 +1,9 @@ +{ + "id" : "test-model", + "type" : "ClutterListModel", + "columns" : [ + [ "text-column", "gchararray" ], + [ "int-column", "gint" ], + [ "actor-column", "ClutterRectangle" ] + ] +}