model: Add support to define rows in ClutterScript
authorBastian Winkler <buz@netbuz.org>
Fri, 21 Jan 2011 13:50:44 +0000 (14:50 +0100)
committerEmmanuele Bassi <ebassi@linux.intel.com>
Fri, 21 Jan 2011 20:44:17 +0000 (20:44 +0000)
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
tests/conform/test-model.c
tests/data/test-script-model.json

index 7bf2fb5..880b73a 100644 (file)
  * <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);
 
@@ -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 (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
@@ -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);
+    }
 }
 
 
index b9fb279..e702063 100644 (file)
@@ -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);
 }
index 075bfbe..9bd6aef 100644 (file)
@@ -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" }
+    }
   ]
 }