* <refsect2 id="ClutterModel-script">
* <title>ClutterModel custom properties for #ClutterScript</title>
* <para>#ClutterModel defines a custom property "columns" for #ClutterScript
- * which allows defining the column names and types.</para>
- * <example id="ClutterModel-script-column-example">
- * <title>Example of the "columns" custom property</title>
+ * which allows defining the column names and types. It also defines a custom
+ * "rows" property which allows filling the #ClutterModel with some
+ * data.</para>
+ * <example id="ClutterModel-script-example">
+ * <title>Example of the "columns" and "rows" custom properties</title>
* <para>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 #ClutterTexture<!-- -->s.</para>
+ * name "Icon" and containing #ClutterTexture<!-- -->s. 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.
+ * </para>
* <programlisting>
* {
* "type" : "ClutterListModel",
* [ "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" }
* ]
* }
* </programlisting>
#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);
const gchar *name,
JsonNode *node)
{
- GSList *columns = NULL;
- GList *elements, *l;
-
- if (strcmp (name, "columns") != 0)
- return FALSE;
+ if (strcmp (name, "columns") == 0)
+ {
+ GSList *columns = NULL;
+ GList *elements, *l;
- if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
- return FALSE;
+ if (JSON_NODE_TYPE (node) != JSON_NODE_ARRAY)
+ return FALSE;
- elements = json_array_get_elements (json_node_get_array (node));
+ 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)
+ 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;
+
+ /*
+ * 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);
- g_value_init (value, G_TYPE_POINTER);
- g_value_set_pointer (value, g_slist_reverse (columns));
+ g_value_init (value, G_TYPE_POINTER);
+ g_value_set_pointer (value, g_slist_reverse (rows));
- return TRUE;
+ return TRUE;
+ }
+ return FALSE;
}
static void
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);
+ }
}
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);
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);
}