Improve error handling for enum/flags, rename the converter functions to

2007-06-30  Johan Dahlin  <jdahlin@async.com.br>

    * gtk/gtkbuilder.c:
    * gtk/gtkbuilder.h:
    * gtk/gtkbuilderparser.c:
    * gtk/gtkbuilderprivate.h:
    * gtk/gtkwidget.c: 
    * tests/buildertest.c:

    Improve error handling for enum/flags, rename the converter functions
    to be consistent. Add tests. Fixes #452465


svn path=/trunk/; revision=18312
This commit is contained in:
Johan Dahlin 2007-06-30 18:27:39 +00:00 committed by Johan Dahlin
parent d793d416da
commit aaab9c05a5
7 changed files with 199 additions and 101 deletions

View File

@ -1,3 +1,15 @@
2007-06-30 Johan Dahlin <jdahlin@async.com.br>
* gtk/gtkbuilder.c:
* gtk/gtkbuilder.h:
* gtk/gtkbuilderparser.c:
* gtk/gtkbuilderprivate.h:
* gtk/gtkwidget.c:
* tests/buildertest.c:
Improve error handling for enum/flags, rename the converter functions
to be consistent. Add tests. Fixes #452465
2007-06-30 Richard Hult <richard@imendio.com> 2007-06-30 Richard Hult <richard@imendio.com>
* gdk/quartz/gdkwindow-quartz.c: (gdk_window_get_origin): Make * gdk/quartz/gdkwindow-quartz.c: (gdk_window_get_origin): Make

View File

@ -49,8 +49,10 @@ static void gtk_builder_get_property (GObject *object,
GParamSpec *pspec); GParamSpec *pspec);
static GType gtk_builder_real_get_type_from_name (GtkBuilder *builder, static GType gtk_builder_real_get_type_from_name (GtkBuilder *builder,
const gchar *type_name); const gchar *type_name);
static gint _gtk_builder_enum_from_string (GType type, static gboolean _gtk_builder_enum_from_string (GType type,
const gchar *string); const gchar *string,
gint *enum_value,
GError **error);
enum { enum {
@ -1038,7 +1040,7 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
{ {
gboolean b; gboolean b;
if (!_gtk_builder_parse_boolean (string, &b, error)) if (!_gtk_builder_boolean_from_string (string, &b, error))
{ {
ret = FALSE; ret = FALSE;
break; break;
@ -1093,11 +1095,27 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
break; break;
} }
case G_TYPE_ENUM: case G_TYPE_ENUM:
g_value_set_enum (value, _gtk_builder_enum_from_string (type, string)); {
gint enum_value;
if (!_gtk_builder_enum_from_string (type, string, &enum_value, error))
{
ret = FALSE;
break; break;
}
g_value_set_enum (value, enum_value);
break;
}
case G_TYPE_FLAGS: case G_TYPE_FLAGS:
g_value_set_flags (value, _gtk_builder_flags_from_string (type, string)); {
gint flags_value;
if (!_gtk_builder_flags_from_string (type, string, &flags_value, error))
{
ret = FALSE;
break; break;
}
g_value_set_flags (value, flags_value);
break;
}
case G_TYPE_FLOAT: case G_TYPE_FLOAT:
case G_TYPE_DOUBLE: case G_TYPE_DOUBLE:
{ {
@ -1195,42 +1213,57 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
return ret; return ret;
} }
static gint static gboolean
_gtk_builder_enum_from_string (GType type, _gtk_builder_enum_from_string (GType type,
const gchar *string) const gchar *string,
gint *enum_value,
GError **error)
{ {
GEnumClass *eclass; GEnumClass *eclass;
GEnumValue *ev; GEnumValue *ev;
gchar *endptr; gchar *endptr;
gint ret = 0; gint value;
g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0); g_return_val_if_fail (G_TYPE_IS_ENUM (type), 0);
g_return_val_if_fail (string != NULL, 0); g_return_val_if_fail (string != NULL, 0);
ret = strtoul (string, &endptr, 0); value = strtoul (string, &endptr, 0);
if (endptr != string) /* parsed a number */ if (endptr != string) /* parsed a number */
return ret; *enum_value = value;
else
{
eclass = g_type_class_ref (type); eclass = g_type_class_ref (type);
ev = g_enum_get_value_by_name (eclass, string); ev = g_enum_get_value_by_name (eclass, string);
if (!ev) if (!ev)
ev = g_enum_get_value_by_nick (eclass, string); ev = g_enum_get_value_by_nick (eclass, string);
if (ev) if (ev)
ret = ev->value; *enum_value = ev->value;
else
g_type_class_unref (eclass); {
g_set_error (error,
return ret; GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_VALUE,
"Could not parse enum: `%s'",
string);
return FALSE;
} }
guint g_type_class_unref (eclass);
}
return TRUE;
}
gboolean
_gtk_builder_flags_from_string (GType type, _gtk_builder_flags_from_string (GType type,
const gchar *string) const gchar *string,
gint *flags_value,
GError **error)
{ {
GFlagsClass *fclass; GFlagsClass *fclass;
gchar *endptr, *prevptr; gchar *endptr, *prevptr;
guint i, j, ret; guint i, j, ret, value;
gchar *flagstr; gchar *flagstr;
GFlagsValue *fv; GFlagsValue *fv;
const gchar *flag; const gchar *flag;
@ -1240,14 +1273,17 @@ _gtk_builder_flags_from_string (GType type,
g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0); g_return_val_if_fail (G_TYPE_IS_FLAGS (type), 0);
g_return_val_if_fail (string != 0, 0); g_return_val_if_fail (string != 0, 0);
ret = strtoul (string, &endptr, 0); ret = TRUE;
if (endptr != string) /* parsed a number */
return ret;
value = strtoul (string, &endptr, 0);
if (endptr != string) /* parsed a number */
*flags_value = value;
else
{
fclass = g_type_class_ref (type); fclass = g_type_class_ref (type);
flagstr = g_strdup (string); flagstr = g_strdup (string);
for (ret = i = j = 0; ; i++) for (value = i = j = 0; ; i++)
{ {
eos = flagstr[i] == '\0'; eos = flagstr[i] == '\0';
@ -1291,18 +1327,30 @@ _gtk_builder_flags_from_string (GType type,
fv = g_flags_get_value_by_nick (fclass, flag); fv = g_flags_get_value_by_nick (fclass, flag);
if (fv) if (fv)
ret |= fv->value; value |= fv->value;
else else
g_warning ("Unknown flag: '%s'", flag); {
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_VALUE,
"Unknown flag: `%s'",
flag);
ret = FALSE;
break;
}
} }
if (eos) if (eos)
{
*flags_value = value;
break; break;
} }
}
g_free (flagstr); g_free (flagstr);
g_type_class_unref (fclass); g_type_class_unref (fclass);
}
return ret; return ret;
} }

View File

@ -117,8 +117,6 @@ gboolean gtk_builder_value_from_string_type (GtkBuilder *builder,
const gchar *string, const gchar *string,
GValue *value, GValue *value,
GError **error); GError **error);
guint _gtk_builder_flags_from_string (GType type,
const char *string);
#define GTK_BUILDER_WARN_INVALID_CHILD_TYPE(object, type) \ #define GTK_BUILDER_WARN_INVALID_CHILD_TYPE(object, type) \
g_warning ("'%s' is not a valid child type of '%s'", type, g_type_name (G_OBJECT_TYPE (type))) g_warning ("'%s' is not a valid child type of '%s'", type, g_type_name (G_OBJECT_TYPE (type)))

View File

@ -158,12 +158,11 @@ error_missing_property_value (ParserData *data,
} }
gboolean gboolean
_gtk_builder_parse_boolean (const gchar *string, _gtk_builder_boolean_from_string (const gchar *string,
gboolean *value, gboolean *value,
GError **error) GError **error)
{ {
gboolean retval = TRUE; gboolean retval = TRUE;
int i;
int length; int length;
g_assert (string != NULL); g_assert (string != NULL);
@ -405,7 +404,8 @@ parse_property (ParserData *data,
name = g_strdelimit (g_strdup (values[i]), "_", '-'); name = g_strdelimit (g_strdup (values[i]), "_", '-');
else if (strcmp (names[i], "translatable") == 0) else if (strcmp (names[i], "translatable") == 0)
{ {
if (!_gtk_builder_parse_boolean (values[i], &translatable, error)) if (!_gtk_builder_boolean_from_string (values[i], &translatable,
error))
return; return;
} }
else else
@ -463,12 +463,12 @@ parse_signal (ParserData *data,
handler = g_strdup (values[i]); handler = g_strdup (values[i]);
else if (strcmp (names[i], "after") == 0) else if (strcmp (names[i], "after") == 0)
{ {
if (!_gtk_builder_parse_boolean (values[i], &after, error)) if (!_gtk_builder_boolean_from_string (values[i], &after, error))
return; return;
} }
else if (strcmp (names[i], "swapped") == 0) else if (strcmp (names[i], "swapped") == 0)
{ {
if (!_gtk_builder_parse_boolean (values[i], &swapped, error)) if (!_gtk_builder_boolean_from_string (values[i], &swapped, error))
return; return;
swapped_set = TRUE; swapped_set = TRUE;
} }

View File

@ -107,8 +107,12 @@ void _gtk_builder_add (GtkBuilder *builder,
void _gtk_builder_finish (GtkBuilder *builder); void _gtk_builder_finish (GtkBuilder *builder);
void _free_signal_info (SignalInfo *info, void _free_signal_info (SignalInfo *info,
gpointer user_data); gpointer user_data);
gboolean _gtk_builder_parse_boolean (const gchar *string, gboolean _gtk_builder_boolean_from_string (const gchar *string,
gboolean *value, gboolean *value,
GError **error); GError **error);
gboolean _gtk_builder_flags_from_string (GType type,
const char *string,
gint *value,
GError **error);
#endif /* __GTK_BUILDER_PRIVATE_H__ */ #endif /* __GTK_BUILDER_PRIVATE_H__ */

View File

@ -53,6 +53,7 @@
#include "gtktooltip.h" #include "gtktooltip.h"
#include "gtkinvisible.h" #include "gtkinvisible.h"
#include "gtkbuildable.h" #include "gtkbuildable.h"
#include "gtkbuilderprivate.h"
#include "gtkalias.h" #include "gtkalias.h"
#define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w) #define WIDGET_CLASS(w) GTK_WIDGET_GET_CLASS (w)
@ -8517,7 +8518,13 @@ accel_group_start_element (GMarkupParseContext *context,
if (strcmp (names[i], "key") == 0) if (strcmp (names[i], "key") == 0)
key = gdk_keyval_from_name (values[i]); key = gdk_keyval_from_name (values[i]);
else if (strcmp (names[i], "modifiers") == 0) else if (strcmp (names[i], "modifiers") == 0)
modifiers = _gtk_builder_flags_from_string (GDK_TYPE_MODIFIER_TYPE, values[i]); {
if (!_gtk_builder_flags_from_string (GDK_TYPE_MODIFIER_TYPE,
values[i],
&modifiers,
error))
return;
}
else if (strcmp (names[i], "signal") == 0) else if (strcmp (names[i], "signal") == 0)
signal = g_strdup (values[i]); signal = g_strdup (values[i]);
} }

View File

@ -1602,6 +1602,35 @@ test_value_from_string (void)
g_error_free (error); g_error_free (error);
error = NULL; error = NULL;
g_return_val_if_fail (gtk_builder_value_from_string_type (builder, GTK_TYPE_WINDOW_TYPE, "toplevel", &value, &error) == TRUE, FALSE);
g_return_val_if_fail (G_VALUE_HOLDS_ENUM (&value), FALSE);
g_return_val_if_fail (g_value_get_enum (&value) == GTK_WINDOW_TOPLEVEL, FALSE);
g_value_unset (&value);
g_return_val_if_fail (gtk_builder_value_from_string_type (builder, GTK_TYPE_WINDOW_TYPE, "sliff", &value, &error) == FALSE, FALSE);
g_value_unset (&value);
g_return_val_if_fail (error->domain == GTK_BUILDER_ERROR, FALSE);
g_return_val_if_fail (error->code == GTK_BUILDER_ERROR_INVALID_VALUE, FALSE);
g_error_free (error);
error = NULL;
g_return_val_if_fail (gtk_builder_value_from_string_type (builder, GTK_TYPE_WIDGET_FLAGS, "mapped", &value, &error) == TRUE, FALSE);
g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (&value), FALSE);
g_return_val_if_fail (g_value_get_flags (&value) == GTK_MAPPED, FALSE);
g_value_unset (&value);
g_return_val_if_fail (gtk_builder_value_from_string_type (builder, GTK_TYPE_WIDGET_FLAGS, "GTK_VISIBLE | GTK_REALIZED", &value, &error) == TRUE, FALSE);
g_return_val_if_fail (G_VALUE_HOLDS_FLAGS (&value), FALSE);
g_return_val_if_fail (g_value_get_flags (&value) == (GTK_VISIBLE | GTK_REALIZED), FALSE);
g_value_unset (&value);
g_return_val_if_fail (gtk_builder_value_from_string_type (builder, GTK_TYPE_WINDOW_TYPE, "foobar", &value, &error) == FALSE, FALSE);
g_value_unset (&value);
g_return_val_if_fail (error->domain == GTK_BUILDER_ERROR, FALSE);
g_return_val_if_fail (error->code == GTK_BUILDER_ERROR_INVALID_VALUE, FALSE);
g_error_free (error);
error = NULL;
g_object_unref (builder); g_object_unref (builder);
return TRUE; return TRUE;