[gtk+/composite-templates: 7/15] Added template_id parameter to gtk_builder_add_to_parent_*() functions This makes it more consistent



commit a45d85d6465e0b1cf89885ee4bb7572450fcef21
Author: Juan Pablo Ugarte <juanpablougarte gmail com>
Date:   Fri Nov 2 12:05:53 2012 -0300

    Added template_id parameter to gtk_builder_add_to_parent_*() functions
    This makes it more consistent since now you have to name the template
    and let you have more than one template in a file.

 gtk/gtkbuilder.c        |  317 +++++++++++++++++++++--------------------------
 gtk/gtkbuilder.h        |    5 +-
 gtk/gtkbuilderparser.c  |  164 ++++++++++++++----------
 gtk/gtkbuilderprivate.h |   16 ++-
 gtk/gtkcontainer.c      |   11 ++-
 5 files changed, 259 insertions(+), 254 deletions(-)
---
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index f306d75..80be5e9 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -894,6 +894,43 @@ gtk_builder_new (void)
   return g_object_new (GTK_TYPE_BUILDER, NULL);
 }
 
+static guint
+gtk_builder_add_from_file_real (GtkBuilder   *builder,
+                                GObject      *parent,
+                                const gchar  *template_id,
+                                const gchar  *filename,
+                                gchar       **object_ids,
+                                GError      **error)
+{
+  GError *tmp_error = NULL;
+  gchar *buffer;
+  gsize length;
+
+  if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+  
+  g_free (builder->priv->filename);
+  g_free (builder->priv->resource_prefix);
+  builder->priv->filename = g_strdup (filename);
+  builder->priv->resource_prefix = NULL;
+
+  _gtk_builder_parser_parse_buffer (builder, parent, template_id, filename,
+                                    buffer, length, object_ids, &tmp_error);
+
+  g_free (buffer);
+
+  if (tmp_error != NULL)
+    {
+      g_propagate_error (error, tmp_error);
+      return 0;
+    }
+
+  return 1;
+}
+
 /**
  * gtk_builder_add_from_file:
  * @builder: a #GtkBuilder
@@ -916,20 +953,25 @@ gtk_builder_add_from_file (GtkBuilder   *builder,
                            const gchar  *filename,
                            GError      **error)
 {
-  return gtk_builder_add_to_parent_from_file (builder, NULL, filename, error);
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (filename != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+  
+  return gtk_builder_add_from_file_real (builder, NULL, NULL, filename,
+                                         NULL, error);
 }
 
 /**
  * gtk_builder_add_to_parent_from_file:
  * @builder: a #GtkBuilder
- * @parent: the parent object to be assumed in context while parsing the file
+ * @parent: the parent container where children will be added, or %NULL
+ * @template_id: the template id to use, or %NULL
  * @filename: the name of the file to parse
  * @error: (allow-none): return location for an error, or %NULL
  *
  * Like gtk_builder_add_from_file() except the format will expect
- * <child> instead of <object> as its first elements and expose
- * @parent in the build context, children defined in the UI fragment
- * will be added to @parent.
+ * <template> instead of <object> with id @template_id.
+ * The children defined in the UI fragment will be added to @parent.
  * 
  * Returns: A positive value on success, 0 if an error occurred
  *
@@ -938,44 +980,18 @@ gtk_builder_add_from_file (GtkBuilder   *builder,
 guint
 gtk_builder_add_to_parent_from_file (GtkBuilder   *builder,
                                      GObject      *parent,
+                                     const gchar  *template_id,
                                      const gchar  *filename,
                                      GError      **error)
 {
-  gchar *buffer;
-  gsize length;
-  GError *tmp_error;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
+  g_return_val_if_fail (template_id != NULL, 0);
   g_return_val_if_fail (filename != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  tmp_error = NULL;
-
-  if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-  
-  g_free (builder->priv->filename);
-  g_free (builder->priv->resource_prefix);
-  builder->priv->filename = g_strdup (filename);
-  builder->priv->resource_prefix = NULL;
-
-  _gtk_builder_parser_parse_buffer (builder, parent, filename,
-                                    buffer, length,
-                                    NULL,
-                                    &tmp_error);
-
-  g_free (buffer);
-
-  if (tmp_error != NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-
-  return 1;
+  return gtk_builder_add_from_file_real (builder, parent, template_id,
+                                         filename, NULL, error);
 }
 
 /**
@@ -1009,34 +1025,55 @@ gtk_builder_add_objects_from_file (GtkBuilder   *builder,
                                    gchar       **object_ids,
                                    GError      **error)
 {
-  gchar *buffer;
-  gsize length;
-  GError *tmp_error;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
   g_return_val_if_fail (filename != NULL, 0);
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
+  return gtk_builder_add_from_file_real (builder, NULL, NULL, filename,
+                                         object_ids, error);
+}
+
+static guint
+gtk_builder_add_from_resource_real (GtkBuilder   *builder,
+                                    GObject      *parent,
+                                    const gchar  *template_id,
+                                    const gchar  *path,
+                                    gchar       **object_ids,
+                                    GError      **error)
+{
+  GError *tmp_error;
+  GBytes *data;
+  char *filename_for_errors;
+  char *slash;
+
   tmp_error = NULL;
 
-  if (!g_file_get_contents (filename, &buffer, &length, &tmp_error))
+  data = g_resources_lookup_data (path, 0, &tmp_error);
+  if (data == NULL)
     {
       g_propagate_error (error, tmp_error);
       return 0;
     }
-  
+
   g_free (builder->priv->filename);
   g_free (builder->priv->resource_prefix);
-  builder->priv->filename = g_strdup (filename);
-  builder->priv->resource_prefix = NULL;
+  builder->priv->filename = g_strdup (".");
 
-  _gtk_builder_parser_parse_buffer (builder, NULL, filename,
-                                    buffer, length,
-                                    object_ids,
-                                    &tmp_error);
+  slash = strrchr (path, '/');
+  if (slash != NULL)
+    builder->priv->resource_prefix = g_strndup (path, slash - path + 1);
+  else
+    builder->priv->resource_prefix = g_strdup ("/");
 
-  g_free (buffer);
+  filename_for_errors = g_strconcat ("<resource>", path, NULL);
+
+  _gtk_builder_parser_parse_buffer (builder, parent, template_id, filename_for_errors,
+                                    g_bytes_get_data (data, NULL), g_bytes_get_size (data),
+                                    object_ids, &tmp_error);
+
+  g_free (filename_for_errors);
+  g_bytes_unref (data);
 
   if (tmp_error != NULL)
     {
@@ -1069,20 +1106,26 @@ gtk_builder_add_from_resource (GtkBuilder   *builder,
 			       const gchar  *resource_path,
 			       GError      **error)
 {
-  return gtk_builder_add_to_parent_from_resource (builder, NULL, resource_path, error);
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (resource_path != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+
+  return gtk_builder_add_from_resource_real (builder, NULL, NULL,
+                                             resource_path, NULL,
+                                             error);
 }
 
 /**
  * gtk_builder_add_to_parent_from_resource:
  * @builder: a #GtkBuilder
- * @parent: the parent object to be assumed in context while parsing the file
- * @path: the resource path to parse
+ * @parent: the parent container where children will be added, or %NULL
+ * @template_id: the template id to use, or %NULL
+ * @resource_path: the resource path to parse
  * @error: (allow-none): return location for an error, or %NULL
  *
- * Like gtk_builder_add_from_file() except the format will expect
- * <child> instead of <object> as its first elements and expose
- * @parent in the build context, children defined in the UI fragment
- * will be added to @parent.
+ * Like gtk_builder_add_from_resource() except the format will expect
+ * <template> instead of <object> with id @template_id.
+ * The children defined in the UI fragment will be added to @parent.
  * 
  * Returns: A positive value on success, 0 if an error occurred
  *
@@ -1091,54 +1134,18 @@ gtk_builder_add_from_resource (GtkBuilder   *builder,
 guint
 gtk_builder_add_to_parent_from_resource (GtkBuilder   *builder,
                                          GObject      *parent,
-                                         const gchar  *path,
+                                         const gchar  *template_id,
+                                         const gchar  *resource_path,
                                          GError      **error)
 {
-  GError *tmp_error;
-  GBytes *data;
-  char *filename_for_errors;
-  char *slash;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
-  g_return_val_if_fail (path != NULL, 0);
+  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
+  g_return_val_if_fail (template_id != NULL, 0);
+  g_return_val_if_fail (resource_path != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  tmp_error = NULL;
-
-  data = g_resources_lookup_data (path, 0, &tmp_error);
-  if (data == NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-
-  g_free (builder->priv->filename);
-  g_free (builder->priv->resource_prefix);
-  builder->priv->filename = g_strdup (".");
-
-  slash = strrchr (path, '/');
-  if (slash != NULL)
-    builder->priv->resource_prefix = g_strndup (path, slash - path + 1);
-  else
-    builder->priv->resource_prefix = g_strdup ("/");
-
-  filename_for_errors = g_strconcat ("<resource>", path, NULL);
-
-  _gtk_builder_parser_parse_buffer (builder, parent, filename_for_errors,
-                                    g_bytes_get_data (data, NULL), g_bytes_get_size (data),
-                                    NULL,
-                                    &tmp_error);
-
-  g_free (filename_for_errors);
-  g_bytes_unref (data);
-
-  if (tmp_error != NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-
-  return 1;
+  return gtk_builder_add_from_resource_real (builder, parent, template_id,
+                                             resource_path, NULL, error);
 }
 
 /**
@@ -1172,46 +1179,34 @@ gtk_builder_add_objects_from_resource (GtkBuilder   *builder,
 				       gchar       **object_ids,
 				       GError      **error)
 {
-  GError *tmp_error;
-  GBytes *data;
-  char *filename_for_errors;
-  char *slash;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
   g_return_val_if_fail (resource_path != NULL, 0);
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  tmp_error = NULL;
+  return gtk_builder_add_from_resource_real (builder, NULL, NULL,
+                                             resource_path, object_ids,
+                                             error);
+}
 
-  data = g_resources_lookup_data (resource_path, 0, &tmp_error);
-  if (data == NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
+static guint
+gtk_builder_add_from_string_real (GtkBuilder   *builder,
+                                  GObject      *parent,
+                                  const gchar  *template_id,
+                                  const gchar  *buffer,
+                                  gsize         length,
+                                  gchar       **object_ids,
+                                  GError      **error)
+{
+  GError *tmp_error = NULL;
 
   g_free (builder->priv->filename);
   g_free (builder->priv->resource_prefix);
   builder->priv->filename = g_strdup (".");
+  builder->priv->resource_prefix = NULL;
 
-  slash = strrchr (resource_path, '/');
-  if (slash != NULL)
-    builder->priv->resource_prefix =
-      g_strndup (resource_path, slash - resource_path + 1);
-  else
-    builder->priv->resource_prefix =
-      g_strdup ("/");
-
-  filename_for_errors = g_strconcat ("<resource>", resource_path, NULL);
-
-  _gtk_builder_parser_parse_buffer (builder, NULL, filename_for_errors,
-                                    g_bytes_get_data (data, NULL), g_bytes_get_size (data),
-                                    object_ids,
-                                    &tmp_error);
-  g_free (filename_for_errors);
-  g_bytes_unref (data);
-
+  _gtk_builder_parser_parse_buffer (builder, parent, template_id, "<input>",
+                                    buffer, length, object_ids, &tmp_error);
   if (tmp_error != NULL)
     {
       g_propagate_error (error, tmp_error);
@@ -1244,22 +1239,28 @@ gtk_builder_add_from_string (GtkBuilder   *builder,
                              gsize         length,
                              GError      **error)
 {
-  return gtk_builder_add_to_parent_from_string (builder, NULL, buffer, length, error);
+  g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (buffer != NULL, 0);
+  g_return_val_if_fail (error == NULL || *error == NULL, 0);
+  
+  return gtk_builder_add_from_string_real (builder, NULL, NULL,
+                                           buffer, length,
+                                           NULL, error);
 }
 
 
 /**
  * gtk_builder_add_to_parent_from_string:
  * @builder: a #GtkBuilder
- * @parent: the parent object to be assumed in context while parsing
+ * @parent: the parent container where children will be added, or %NULL
+ * @template_id: the template id to use, or %NULL
  * @buffer: the string to parse
  * @length: the length of @buffer (may be -1 if @buffer is nul-terminated)
  * @error: (allow-none): return location for an error, or %NULL
  *
  * Like gtk_builder_add_from_string() except the format will expect
- * <child> instead of <object> as its first elements and expose
- * @parent in the build context, children defined in the UI fragment
- * will be added to @parent.
+ * <template> instead of <object> with id @template_id.
+ * The children defined in the UI fragment will be added to @parent.
  * 
  * Returns: A positive value on success, 0 if an error occurred
  *
@@ -1268,34 +1269,20 @@ gtk_builder_add_from_string (GtkBuilder   *builder,
 guint
 gtk_builder_add_to_parent_from_string (GtkBuilder   *builder,
                                        GObject      *parent,
+                                       const gchar  *template_id,
                                        const gchar  *buffer,
                                        gsize         length,
                                        GError      **error)
 {
-  GError *tmp_error;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
+  g_return_val_if_fail (GTK_IS_CONTAINER (parent), 0);
+  g_return_val_if_fail (template_id != NULL, 0);
   g_return_val_if_fail (buffer != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  tmp_error = NULL;
-
-  g_free (builder->priv->filename);
-  g_free (builder->priv->resource_prefix);
-  builder->priv->filename = g_strdup (".");
-  builder->priv->resource_prefix = NULL;
-
-  _gtk_builder_parser_parse_buffer (builder, parent, "<input>",
-                                    buffer, length,
-                                    NULL,
-                                    &tmp_error);
-  if (tmp_error != NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-
-  return 1;
+  return gtk_builder_add_from_string_real (builder, parent, template_id,
+                                           buffer, length,
+                                           NULL, error);
 }
 
 /**
@@ -1330,32 +1317,14 @@ gtk_builder_add_objects_from_string (GtkBuilder   *builder,
                                      gchar       **object_ids,
                                      GError      **error)
 {
-  GError *tmp_error;
-
   g_return_val_if_fail (GTK_IS_BUILDER (builder), 0);
   g_return_val_if_fail (buffer != NULL, 0);
   g_return_val_if_fail (object_ids != NULL && object_ids[0] != NULL, 0);
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
-  tmp_error = NULL;
-
-  g_free (builder->priv->filename);
-  g_free (builder->priv->resource_prefix);
-  builder->priv->filename = g_strdup (".");
-  builder->priv->resource_prefix = NULL;
-
-  _gtk_builder_parser_parse_buffer (builder, NULL, "<input>",
-                                    buffer, length,
-                                    object_ids,
-                                    &tmp_error);
-
-  if (tmp_error != NULL)
-    {
-      g_propagate_error (error, tmp_error);
-      return 0;
-    }
-
-  return 1;
+  return gtk_builder_add_from_string_real (builder, NULL, NULL,
+                                           buffer, length,
+                                           object_ids, error);
 }
 
 /**
diff --git a/gtk/gtkbuilder.h b/gtk/gtkbuilder.h
index 77fc0a8..dc22f8d 100644
--- a/gtk/gtkbuilder.h
+++ b/gtk/gtkbuilder.h
@@ -142,16 +142,19 @@ guint        gtk_builder_add_objects_from_string (GtkBuilder    *builder,
                                                   GError       **error);
 guint        gtk_builder_add_to_parent_from_file     (GtkBuilder   *builder,
                                                       GObject      *parent,
+                                                      const gchar  *template_id,
                                                       const gchar  *filename,
                                                       GError      **error);
 guint        gtk_builder_add_to_parent_from_string   (GtkBuilder   *builder,
                                                       GObject      *parent,
+                                                      const gchar  *template_id,
                                                       const gchar  *buffer,
                                                       gsize         length,
                                                       GError      **error);
 guint        gtk_builder_add_to_parent_from_resource (GtkBuilder   *builder,
                                                       GObject      *parent,
-                                                      const gchar  *path,
+                                                      const gchar  *template_id,
+                                                      const gchar  *resource_path,
                                                       GError      **error);
 GObject*     gtk_builder_get_object              (GtkBuilder    *builder,
                                                   const gchar   *name);
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index a006664..914f566 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -327,8 +327,9 @@ parse_object (GMarkupParseContext  *context,
   GType object_type = G_TYPE_INVALID;
   ObjectInfo *object_info;
   ChildInfo *child_info;
-  gchar *object_id = NULL;
-  gchar *constructor = NULL;
+  const gchar *object_class = NULL;
+  const gchar *object_id = NULL;
+  const gchar *constructor = NULL;
   gint i, line, line2;
 
   child_info = state_peek_info (data, ChildInfo);
@@ -341,12 +342,11 @@ parse_object (GMarkupParseContext  *context,
   for (i = 0; names[i] != NULL; i++)
     {
       if (strcmp (names[i], "class") == 0)
-        /* Make sure the class is initialized so we have intern string available */
-        object_type = gtk_builder_get_type_from_name (data->builder, values[i]);
+        object_class = values[i];
       else if (strcmp (names[i], "id") == 0)
-        object_id = g_strdup (values[i]);
+        object_id = values[i];
       else if (strcmp (names[i], "constructor") == 0)
-        constructor = g_strdup (values[i]);
+        constructor = values[i];
       else if (strcmp (names[i], "type-func") == 0)
         {
 	  /* Call the GType function, and return the name of the GType,
@@ -371,7 +371,7 @@ parse_object (GMarkupParseContext  *context,
 	}
     }
 
-  if (object_type == G_TYPE_INVALID)
+  if (object_type == G_TYPE_INVALID && !object_class)
     {
       error_missing_attribute (data, element_name, "class", error);
       return;
@@ -383,6 +383,20 @@ parse_object (GMarkupParseContext  *context,
       return;
     }
 
+  if (object_type == G_TYPE_INVALID)
+    {
+      /* Make sure the class is initialized so we have intern string available */
+      object_type = gtk_builder_get_type_from_name (data->builder, object_class);
+
+      if (object_type == G_TYPE_INVALID)
+	{
+	  g_set_error (error, GTK_BUILDER_ERROR,
+	               GTK_BUILDER_ERROR_INVALID_VALUE,
+	               _("Invalid class: '%s'"), object_class);
+	  return;
+	}
+    }
+
   ++data->cur_object_level;
 
   /* check if we reached a requested object (if it is specified) */
@@ -400,16 +414,16 @@ parse_object (GMarkupParseContext  *context,
         }
       else
         {
-          g_free (object_id);
-          g_free (constructor);
           return;
         }
     }
+  else if (data->template_object && !data->inside_requested_template)
+    return;
 
   object_info = g_slice_new0 (ObjectInfo);
   object_info->object_type = object_type;
-  object_info->id = object_id;
-  object_info->constructor = constructor;
+  object_info->id = g_strdup (object_id);
+  object_info->constructor = g_strdup (constructor);
   state_push (data, object_info);
   object_info->tag.name = element_name;
 
@@ -680,16 +694,8 @@ parse_template (ParserData   *data,
   const gchar *parent_class = NULL;
   const gchar *class_name = NULL;
   const gchar *id = NULL;
-  GType parent_type, class_type;
-  ObjectInfo *object_info;
   gint i;
 
-  if (parent == NULL)
-    {
-      error_invalid_tag (data, element_name, NULL, error);
-      return;
-    }
-
   for (i = 0; names[i] != NULL; i++)
     {
       if (strcmp (names[i], "class") == 0)
@@ -711,58 +717,62 @@ parse_template (ParserData   *data,
       return;
     }
 
-  if (!parent_class)
-    {
-      error_missing_attribute (data, element_name, "parent", error);
-      return;
-    }
-
   if (!id)
     {
       error_missing_attribute (data, element_name, "id", error);
       return;
     }
 
-  if (strcmp (id, "this"))
+  if (parent)
     {
-      error_generic (error, GTK_BUILDER_ERROR_INVALID_VALUE, data,
-                     element_name, "%s template should be named 'this' not %s '%s'",
-                     class_name, id);
-      return;
-    }
+      const gchar *template_name= _gtk_builder_object_get_name (parent);
+      GType class_type, parent_type = G_OBJECT_TYPE (parent);
+      ObjectInfo *object_info;
 
-  if ((class_type = g_type_from_name (class_name)) == G_TYPE_INVALID)
-    {
-      error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
-                     element_name, "invalid class type found '%s'", class_name);
-      return;
-    }
+      if (!data->inside_requested_template && g_strcmp0 (template_name, id) == 0)
+        data->inside_requested_template = TRUE;
+      else
+        return;
 
-  parent_type = G_OBJECT_TYPE (parent);
-  
-  if (!g_type_is_a (parent_type, class_type))
-    {
-      error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
-                     element_name, "this template is for a class type %s not for %s",
-                     class_name, G_OBJECT_TYPE_NAME (parent));
-      return;
-    }
+      if (!(class_type = g_type_from_name (class_name)))
+        {
+          error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
+                         element_name, "invalid class type found '%s'", class_name);
+          return;
+        }
+
+      if (!g_type_is_a (parent_type, class_type))
+        {
+          error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
+                         element_name, "this template is for a class type %s not for %s",
+                         class_name, G_OBJECT_TYPE_NAME (parent));
+          return;
+        }
 
-  if (!g_type_is_a (class_type, g_type_from_name (parent_class)))
+      if (parent_class && 
+          !g_type_is_a (class_type, g_type_from_name (parent_class)))
+        {
+          error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
+                         element_name, "class %s should derive from parent %s",
+                         class_name, parent_class);
+          return;
+        }
+
+      /* push parent to build its children from the template */
+      object_info = g_slice_new0 (ObjectInfo);
+      object_info->object = parent;
+      object_info->object_type = parent_type;
+      object_info->id = g_strdup (_gtk_builder_object_get_name (parent));
+      object_info->tag.name = "object";
+
+      state_push (data, object_info);
+    }
+  else
     {
-      error_generic (error, GTK_BUILDER_ERROR_TEMPLATE_CLASS_MISMATCH, data,
-                     element_name, "class %s should derive from parent %s",
-                     class_name, parent_class);
+      error_invalid_tag (data, element_name, NULL, error);
       return;
     }
-    
-  object_info = g_slice_new0 (ObjectInfo);
-  object_info->object = parent;
-  object_info->object_type = parent_type;
-  object_info->id = g_strdup (_gtk_builder_object_get_name (parent));
-  object_info->tag.name = "object";
 
-  state_push (data, object_info);
 }
 
 /* Called by GtkBuilder */
@@ -1010,6 +1020,13 @@ start_element (GMarkupParseContext *context,
 
   if (strcmp (element_name, "requires") == 0)
     parse_requires (data, element_name, names, values, error);
+  else if (strcmp (element_name, "template") == 0)
+    parse_template (data, element_name, names, values, error);
+  else if (data->template_object && !data->inside_requested_template)
+    {
+      /* If outside a requested template, ignore this tag */
+      return;
+    }
   else if (strcmp (element_name, "object") == 0)
     parse_object (context, data, element_name, names, values, error);
   else if (data->requested_objects && !data->inside_requested_object)
@@ -1027,8 +1044,6 @@ start_element (GMarkupParseContext *context,
     parse_interface (data, element_name, names, values, error);
   else if (strcmp (element_name, "menu") == 0)
     _gtk_builder_menu_start (data, element_name, names, values, error);
-  else if (strcmp (element_name, "template") == 0)
-    parse_template (data, element_name, names, values, error);
   else if (strcmp (element_name, "placeholder") == 0)
     {
       /* placeholder has no special treatmeant, but it needs an
@@ -1100,9 +1115,10 @@ end_element (GMarkupParseContext *context,
   else if (strcmp (element_name, "interface") == 0)
     {
     }
-  else if (data->requested_objects && !data->inside_requested_object)
+  else if ((data->requested_objects && !data->inside_requested_object) ||
+           (data->template_object && !data->inside_requested_template))
     {
-      /* If outside a requested object, simply ignore this tag */
+      /* If outside a requested object or template, simply ignore this tag */
       return;
     }
   else if (strcmp (element_name, "menu") == 0)
@@ -1193,7 +1209,7 @@ end_element (GMarkupParseContext *context,
     }
   else if (strcmp (element_name, "template") == 0)
     {
-      if (data->template_object)
+      if (data->template_object && data->inside_requested_template)
         {
           ObjectInfo *object_info = state_pop_info (data, ObjectInfo);
 
@@ -1208,6 +1224,8 @@ end_element (GMarkupParseContext *context,
           free_object_info (object_info);
 
           data->template_object = NULL;
+
+          data->inside_requested_template = FALSE;
         }
     }
   else
@@ -1283,6 +1301,7 @@ static const GMarkupParser parser = {
 void
 _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
                                   GObject      *parent,
+                                  const gchar  *template_id,
                                   const gchar  *filename,
                                   const gchar  *buffer,
                                   gsize         length,
@@ -1306,13 +1325,6 @@ _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
   data->domain = g_strdup (domain);
   data->object_ids = g_hash_table_new_full (g_str_hash, g_str_equal,
 					    (GDestroyNotify)g_free, NULL);
-
-  if (parent)
-    {
-      GTK_NOTE (BUILDER, g_print ("parsing with contextual parent %s ptr %p\n", G_OBJECT_TYPE_NAME (parent), parent));
-      data->template_object = parent;
-    }
-
   data->requested_objects = NULL;
   if (requested_objs)
     {
@@ -1331,6 +1343,20 @@ _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
       data->inside_requested_object = TRUE;
     }
 
+  if (parent)
+    {
+      data->inside_requested_template = FALSE;
+      
+      if (template_id)
+        {
+          GTK_NOTE (BUILDER, g_print ("parsing with contextual parent %s class %s ptr %p\n",
+                                      template_id, G_OBJECT_TYPE_NAME (parent), parent));
+
+          data->template_object = parent;
+          gtk_builder_expose_object (builder, template_id, parent);
+        }
+    }
+
   data->ctx = g_markup_parse_context_new (&parser, 
                                           G_MARKUP_TREAT_CDATA_AS_TEXT, 
                                           data, NULL);
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index 9e4b292..eb7051d 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -110,18 +110,20 @@ typedef struct {
 
   GHashTable *object_ids;
   GObject *template_object;
+  gboolean inside_requested_template;
 } ParserData;
 
 typedef GType (*GTypeGetFunc) (void);
 
 /* Things only GtkBuilder should use */
-void _gtk_builder_parser_parse_buffer (GtkBuilder *builder,
-                                       GObject     *parent,
-                                       const gchar *filename,
-                                       const gchar *buffer,
-                                       gsize length,
-                                       gchar **requested_objs,
-                                       GError **error);
+void _gtk_builder_parser_parse_buffer (GtkBuilder   *builder,
+                                       GObject      *parent,
+                                       const gchar  *template_id,
+                                       const gchar  *filename,
+                                       const gchar  *buffer,
+                                       gsize         length,
+                                       gchar       **requested_objs,
+                                       GError      **error);
 GObject * _gtk_builder_construct (GtkBuilder *builder,
                                   ObjectInfo *info,
 				  GError    **error);
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index fa3379c..dd4b265 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -1668,15 +1668,20 @@ gtk_container_constructor (GType                  type,
       guint ret;
         
       builder = gtk_builder_new ();
-      gtk_builder_expose_object (builder, "this", object);
 
       switch (cpriv->tmpl_type)
         {
           case TMPL_STRING:
-            ret = gtk_builder_add_to_parent_from_string (builder, object, cpriv->tmpl, -1, &error);
+            ret = gtk_builder_add_to_parent_from_string (builder, object,
+                                                         "this",
+                                                         cpriv->tmpl,
+                                                         -1, &error);
           break;
           case TMPL_RESOURCE:
-            ret = gtk_builder_add_to_parent_from_resource (builder, object, cpriv->tmpl, &error);
+            ret = gtk_builder_add_to_parent_from_resource (builder, object,
+                                                           "this",
+                                                           cpriv->tmpl,
+                                                           &error);
           break;
           default:
             ret = 0;



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