[gtk/builder-treestore-data: 2/6] treestore: Copy liststore buildable implementation




commit c2e8604805416a60607c4655cce0ed5c54609835
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri May 6 07:48:28 2022 -0400

    treestore: Copy liststore buildable implementation
    
    This add support for data, but does not allow
    nesting yet.

 gtk/gtktreestore.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 224 insertions(+), 29 deletions(-)
---
diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c
index 137f76a215..83c83072c1 100644
--- a/gtk/gtktreestore.c
+++ b/gtk/gtktreestore.c
@@ -177,11 +177,11 @@ static gboolean gtk_tree_store_buildable_custom_tag_start (GtkBuildable       *b
                                                            const char         *tagname,
                                                            GtkBuildableParser *parser,
                                                            gpointer           *data);
-static void     gtk_tree_store_buildable_custom_finished  (GtkBuildable       *buildable,
+static void     gtk_tree_store_buildable_custom_tag_end   (GtkBuildable       *buildable,
                                                            GtkBuilder         *builder,
                                                            GObject            *child,
                                                            const char         *tagname,
-                                                           gpointer            user_data);
+                                                           gpointer            parser_data);
 
 static void     gtk_tree_store_move                    (GtkTreeStore           *tree_store,
                                                         GtkTreeIter            *iter,
@@ -275,7 +275,7 @@ void
 gtk_tree_store_buildable_init (GtkBuildableIface *iface)
 {
   iface->custom_tag_start = gtk_tree_store_buildable_custom_tag_start;
-  iface->custom_finished = gtk_tree_store_buildable_custom_finished;
+  iface->custom_tag_end = gtk_tree_store_buildable_custom_tag_end;
 }
 
 static void
@@ -3315,10 +3315,25 @@ validate_gnode (GNode* node)
  *   <column type="..."/>
  * </columns>
  */
+typedef struct {
+  gboolean translatable;
+  char *context;
+  int id;
+} ColInfo;
+
 typedef struct {
   GtkBuilder *builder;
   GObject *object;
   GSList *column_type_names;
+  GType *column_types;
+  GValue *values;
+  int *colids;
+  ColInfo **columns;
+  int last_row;
+  int n_columns;
+  int row_column;
+  gboolean is_data;
+  const char *domain;
 } SubParserData;
 
 static void
@@ -3331,16 +3346,84 @@ tree_store_start_element (GtkBuildableParseContext  *context,
 {
   SubParserData *data = (SubParserData*)user_data;
 
-  if (strcmp (element_name, "columns") == 0)
+  if (strcmp (element_name, "col") == 0)
     {
-      if (!_gtk_builder_check_parent (data->builder, context, "object", error))
+      int id = -1;
+      const char *id_str;
+      const char *msg_context = NULL;
+      gboolean translatable = FALSE;
+      ColInfo *info;
+      GValue val = G_VALUE_INIT;
+
+      if (!_gtk_builder_check_parent (data->builder, context, "row", error))
+        return;
+
+      if (data->row_column >= data->n_columns)
+        {
+          g_set_error (error,
+                       GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE,
+                       "Too many columns, maximum is %d", data->n_columns - 1);
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      if (!g_markup_collect_attributes (element_name, names, values, error,
+                                        G_MARKUP_COLLECT_STRING, "id", &id_str,
+                                        G_MARKUP_COLLECT_BOOLEAN|G_MARKUP_COLLECT_OPTIONAL, "translatable", 
&translatable,
+                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "comments", NULL,
+                                        G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "context", 
&msg_context,
+                                        G_MARKUP_COLLECT_INVALID))
+        {
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+     if (!gtk_builder_value_from_string_type (data->builder, G_TYPE_INT, id_str, &val, error))
+        {
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      id = g_value_get_int (&val);
+      if (id < 0 || id >= data->n_columns)
+        {
+          g_set_error (error,
+                       GTK_BUILDER_ERROR, GTK_BUILDER_ERROR_INVALID_VALUE,
+                       "id value %d out of range", id);
+          _gtk_builder_prefix_error (data->builder, context, error);
+          return;
+        }
+
+      info = g_slice_new0 (ColInfo);
+      info->translatable = translatable;
+      info->context = g_strdup (msg_context);
+      info->id = id;
+
+      data->colids[data->row_column] = id;
+      data->columns[data->row_column] = info;
+      data->row_column++;
+      data->is_data = TRUE;
+    }
+  else if (strcmp (element_name, "row") == 0)
+    {
+      if (!_gtk_builder_check_parent (data->builder, context, "data", error))
         return;
 
       if (!g_markup_collect_attributes (element_name, names, values, error,
                                         G_MARKUP_COLLECT_INVALID, NULL, NULL,
                                         G_MARKUP_COLLECT_INVALID))
         _gtk_builder_prefix_error (data->builder, context, error);
+    }
+  else if (strcmp (element_name, "columns") == 0 ||
+           strcmp (element_name, "data") == 0)
+    {
+      if (!_gtk_builder_check_parent (data->builder, context, "object", error))
+        return;
 
+      if (!g_markup_collect_attributes (element_name, names, values, error,
+                                        G_MARKUP_COLLECT_INVALID, NULL, NULL,
+                                        G_MARKUP_COLLECT_INVALID))
+        _gtk_builder_prefix_error (data->builder, context, error);
     }
   else if (strcmp (element_name, "column") == 0)
     {
@@ -3359,6 +3442,7 @@ tree_store_start_element (GtkBuildableParseContext  *context,
 
       data->column_type_names = g_slist_prepend (data->column_type_names, g_strdup (type));
     }
+
   else
     {
       _gtk_builder_error_unhandled_tag (data->builder, context,
@@ -3377,16 +3461,41 @@ tree_store_end_element (GtkBuildableParseContext  *context,
 
   g_assert(data->builder);
 
-  if (strcmp (element_name, "columns") == 0)
+  if (strcmp (element_name, "row") == 0)
+    {
+      GtkTreeIter iter;
+      int i;
+
+      gtk_tree_store_insert_with_valuesv (GTK_TREE_STORE (data->object),
+                                          &iter,
+                                          NULL,
+                                          data->last_row,
+                                          data->colids,
+                                          data->values,
+                                          data->row_column);
+      for (i = 0; i < data->row_column; i++)
+        {
+          ColInfo *info = data->columns[i];
+          g_free (info->context);
+          g_slice_free (ColInfo, info);
+          data->columns[i] = NULL;
+          g_value_unset (&data->values[i]);
+        }
+      g_free (data->values);
+      data->values = g_new0 (GValue, data->n_columns);
+      data->last_row++;
+      data->row_column = 0;
+    }
+  else if (strcmp (element_name, "columns") == 0)
     {
+      GType *column_types;
       GSList *l;
-      GType *types;
       int i;
       GType type;
 
       data = (SubParserData*)user_data;
       data->column_type_names = g_slist_reverse (data->column_type_names);
-      types = g_new0 (GType, g_slist_length (data->column_type_names));
+      column_types = g_new0 (GType, g_slist_length (data->column_type_names));
 
       for (l = data->column_type_names, i = 0; l; l = l->next, i++)
         {
@@ -3398,23 +3507,72 @@ tree_store_end_element (GtkBuildableParseContext  *context,
                          gtk_buildable_get_buildable_id (GTK_BUILDABLE (data->object)));
               continue;
             }
-          types[i] = type;
+          column_types[i] = type;
 
           g_free (l->data);
         }
 
-      gtk_tree_store_set_column_types (GTK_TREE_STORE (data->object), i, types);
+      gtk_tree_store_set_column_types (GTK_TREE_STORE (data->object), i, column_types);
 
-      g_free (types);
+      g_free (column_types);
+    }
+  else if (strcmp (element_name, "col") == 0)
+    {
+      data->is_data = FALSE;
     }
 }
 
-static const GtkBuildableParser tree_store_parser =
-  {
-    tree_store_start_element,
-    tree_store_end_element
-  };
+static void
+tree_store_text (GtkBuildableParseContext  *context,
+                 const char                *text,
+                 gsize                      text_len,
+                 gpointer                   user_data,
+                 GError                   **error)
+{
+  SubParserData *data = (SubParserData*)user_data;
+  int i;
+  char *string;
+  ColInfo *info;
+
+  if (!data->is_data)
+    return;
+
+  i = data->row_column - 1;
+  info = data->columns[i];
+
+  string = g_strndup (text, text_len);
+  if (info->translatable && text_len)
+    {
+      char *translated;
 
+      /* FIXME: This will not use the domain set in the .ui file,
+       * since the parser is not telling the builder about the domain.
+       * However, it will work for gtk_builder_set_translation_domain() calls.
+       */
+      translated = g_strdup (_gtk_builder_parser_translate (data->domain,
+                                                            info->context,
+                                                            string));
+      g_free (string);
+      string = translated;
+    }
+
+  if (!gtk_builder_value_from_string_type (data->builder,
+                                           data->column_types[info->id],
+                                           string,
+                                           &data->values[i],
+                                           error))
+    {
+      _gtk_builder_prefix_error (data->builder, context, error);
+    }
+  g_free (string);
+}
+
+static const GtkBuildableParser tree_store_parser =
+{
+  tree_store_start_element,
+  tree_store_end_element,
+  tree_store_text
+};
 
 static gboolean
 gtk_tree_store_buildable_custom_tag_start (GtkBuildable       *buildable,
@@ -3439,6 +3597,28 @@ gtk_tree_store_buildable_custom_tag_start (GtkBuildable       *buildable,
       *parser = tree_store_parser;
       *parser_data = data;
 
+      return TRUE;
+    }
+  else if (strcmp (tagname, "data") == 0)
+    {
+      int n_columns = gtk_tree_store_get_n_columns (GTK_TREE_MODEL (buildable));
+      if (n_columns == 0)
+        g_error ("Cannot append data to an empty model");
+
+      data = g_slice_new0 (SubParserData);
+      data->builder = builder;
+      data->object = G_OBJECT (buildable);
+      data->values = g_new0 (GValue, n_columns);
+      data->colids = g_new0 (int, n_columns);
+      data->columns = g_new0 (ColInfo *, n_columns);
+      data->column_types = GTK_TREE_STORE (buildable)->priv->column_headers;
+      data->n_columns = n_columns;
+      data->last_row = 0;
+      data->domain = gtk_builder_get_translation_domain (builder);
+
+      *parser = tree_store_parser;
+      *parser_data = data;
+
       return TRUE;
     }
 
@@ -3446,19 +3626,34 @@ gtk_tree_store_buildable_custom_tag_start (GtkBuildable       *buildable,
 }
 
 static void
-gtk_tree_store_buildable_custom_finished (GtkBuildable *buildable,
-                                          GtkBuilder   *builder,
-                                          GObject      *child,
-                                          const char   *tagname,
-                                          gpointer      user_data)
+gtk_tree_store_buildable_custom_tag_end (GtkBuildable *buildable,
+                                         GtkBuilder   *builder,
+                                         GObject      *child,
+                                         const char   *tagname,
+                                         gpointer      parser_data)
 {
-  SubParserData *data;
-
-  if (strcmp (tagname, "columns"))
-    return;
+  SubParserData *data = (SubParserData*)parser_data;
 
-  data = (SubParserData*)user_data;
-
-  g_slist_free (data->column_type_names);
-  g_slice_free (SubParserData, data);
+  if (strcmp (tagname, "columns") == 0)
+    {
+      g_slist_free (data->column_type_names);
+      g_slice_free (SubParserData, data);
+    }
+  else if (strcmp (tagname, "data") == 0)
+    {
+      int i;
+      for (i = 0; i < data->n_columns; i++)
+        {
+          ColInfo *info = data->columns[i];
+          if (info)
+            {
+              g_free (info->context);
+              g_slice_free (ColInfo, info);
+            }
+        }
+      g_free (data->colids);
+      g_free (data->columns);
+      g_free (data->values);
+      g_slice_free (SubParserData, data);
+    }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]