Exemple #1
0
static void
parse_template (GMarkupParseContext  *context,
                ParserData           *data,
                const gchar          *element_name,
                const gchar         **names,
                const gchar         **values,
                GError              **error)
{
  ObjectInfo *object_info;
  const gchar *object_class = NULL;
  const gchar *parent_class = NULL;
  gint line;
  GType template_type;
  GType parsed_type;

  template_type = _gtk_builder_get_template_type (data->builder);

  if (!g_markup_collect_attributes (element_name, names, values, error,
                                    G_MARKUP_COLLECT_STRING, "class", &object_class,
                                    G_MARKUP_COLLECT_STRING|G_MARKUP_COLLECT_OPTIONAL, "parent", &parent_class,
                                    G_MARKUP_COLLECT_INVALID))
    {
      _gtk_builder_prefix_error (data->builder, data->ctx, error);
      return;
    }

  if (template_type == 0)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_UNHANDLED_TAG,
                   "Not expecting to handle a template (class '%s', parent '%s')",
                   object_class, parent_class ? parent_class : "GtkWidget");
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }
  else if (state_peek (data) != NULL)
    {
      error_invalid_tag (data, "template", NULL, error);
      return;
    }

  parsed_type = g_type_from_name (object_class);
  if (template_type != parsed_type)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
                   "Parsed template definition for type '%s', expected type '%s'",
                   object_class, g_type_name (template_type));
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }

  if (parent_class)
    {
      GType parent_type = g_type_from_name (parent_class);
      GType expected_type = g_type_parent (parsed_type);

      if (parent_type == G_TYPE_INVALID)
        {
          g_set_error (error, GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_INVALID_VALUE,
                       "Invalid template parent type '%s'", parent_class);
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }
      if (parent_type != expected_type)
        {
          g_set_error (error, GTK_BUILDER_ERROR,
                       GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
                       "Template parent type '%s' does not match instance parent type '%s'.",
                       parent_class, g_type_name (expected_type));
          _gtk_builder_prefix_error (data->builder, context, error);
          return;
        }
    }

  ++data->cur_object_level;

  object_info = g_slice_new0 (ObjectInfo);
  object_info->tag.name = element_name;
  object_info->type = parsed_type;
  object_info->oclass = g_type_class_ref (parsed_type);
  object_info->id = g_strdup (object_class);
  object_info->object = gtk_builder_get_object (data->builder, object_class);
  state_push (data, object_info);

  line = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_class));
  if (line != 0)
    {
      g_set_error (error,
                   GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_DUPLICATE_ID,
                   "Duplicate object ID '%s' (previously on line %d)",
                   object_class, line);
      _gtk_builder_prefix_error (data->builder, context, error);
      return;
    }

  g_markup_parse_context_get_position (context, &line, NULL);
  g_hash_table_insert (data->object_ids, g_strdup (object_class), GINT_TO_POINTER (line));
}
static void
parse_template (GMarkupParseContext  *context,
		ParserData           *data,
		const gchar          *element_name,
		const gchar         **names,
		const gchar         **values,
		GError              **error)
{
  ObjectInfo *object_info;
  int i;
  gchar *object_class = NULL;
  gint line, line2;
  GType template_type = _gtk_builder_get_template_type (data->builder);
  GType parsed_type;

  if (template_type == 0)
    {
      g_set_error (error,
		   GTK_BUILDER_ERROR,
		   GTK_BUILDER_ERROR_UNHANDLED_TAG,
		   "Encountered template definition but not parsing a template.");
      return;
    }
  else if (state_peek (data) != NULL)
    {
      g_set_error (error,
		   GTK_BUILDER_ERROR,
		   GTK_BUILDER_ERROR_UNHANDLED_TAG,
		   "Encountered template definition that is not at the top level.");
      return;
    }

  for (i = 0; names[i] != NULL; i++)
    {
      if (strcmp (names[i], "class") == 0)
        object_class = g_strdup (values[i]);
      else if (strcmp (names[i], "parent") == 0)
        /* Ignore 'parent' attribute, however it's needed by Glade */;
      else
	{
	  error_invalid_attribute (data, element_name, names[i], error);
	  return;
	}
    }

  if (!object_class)
    {
      error_missing_attribute (data, element_name, "class", error);
      return;
    }

  parsed_type = g_type_from_name (object_class);
  if (template_type != parsed_type)
    {
      g_set_error (error,
		   GTK_BUILDER_ERROR,
		   GTK_BUILDER_ERROR_TEMPLATE_MISMATCH,
		   "Parsed template definition for type `%s', expected type `%s'.",
		   object_class, g_type_name (template_type));
      return;
    }

  ++data->cur_object_level;

  object_info = g_slice_new0 (ObjectInfo);
  object_info->class_name = object_class;
  object_info->id = g_strdup (object_class);
  object_info->object = gtk_builder_get_object (data->builder, object_class);
  state_push (data, object_info);
  object_info->tag.name = element_name;

  g_markup_parse_context_get_position (context, &line, NULL);
  line2 = GPOINTER_TO_INT (g_hash_table_lookup (data->object_ids, object_class));
  if (line2 != 0)
    {
      g_set_error (error, GTK_BUILDER_ERROR,
                   GTK_BUILDER_ERROR_DUPLICATE_ID,
                   _("Duplicate object ID '%s' on line %d (previously on line %d)"),
                   object_class, line, line2);
      return;
    }

  g_hash_table_insert (data->object_ids, g_strdup (object_class), GINT_TO_POINTER (line));
}