]> git.street.me.uk Git - andy/viking.git/blob - src/vikgobjectbuilder.c
Merge branch 'master' into i18n-launchpad
[andy/viking.git] / src / vikgobjectbuilder.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * viking
4  * Copyright (C) Guilhem Bonnefille 2009 <guilhem.bonnefille@gmail.com>
5  * 
6  * viking is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  * 
11  * viking is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28
29 #include <glib.h>
30 #include <glib/gstdio.h>
31
32 #include <gtk/gtkbuilder.h>
33
34 #include "vikgobjectbuilder.h"
35
36 /* FIXME use private fields */
37 static gchar *class_name = NULL;
38 GType gtype = 0;
39 gchar *property_name = NULL;
40 GParameter *parameters = NULL;
41 gint nb_parameters = 0;
42
43 /* signals */
44 enum
45 {
46         NEW_OBJECT,
47
48         LAST_SIGNAL
49 };
50
51
52 static guint gobject_builder_signals[LAST_SIGNAL] = { 0 };
53
54 G_DEFINE_TYPE (VikGobjectBuilder, vik_gobject_builder, G_TYPE_OBJECT);
55
56 static void
57 vik_gobject_builder_init (VikGobjectBuilder *object)
58 {
59         /* TODO: Add initialization code here */
60 }
61
62 static void
63 vik_gobject_builder_finalize (GObject *object)
64 {
65         /* TODO: Add deinitalization code here */
66
67         G_OBJECT_CLASS (vik_gobject_builder_parent_class)->finalize (object);
68 }
69
70 static void
71 vik_gobject_builder_new_object (VikGobjectBuilder *self, GObject *object)
72 {
73         /* TODO: Add default signal handler implementation here */
74 }
75
76 static void
77 vik_gobject_builder_class_init (VikGobjectBuilderClass *klass)
78 {
79         GObjectClass* object_class = G_OBJECT_CLASS (klass);
80         GObjectClass* parent_class = G_OBJECT_CLASS (klass);
81
82         object_class->finalize = vik_gobject_builder_finalize;
83
84         klass->new_object = vik_gobject_builder_new_object;
85
86         gobject_builder_signals[NEW_OBJECT] =
87                 g_signal_new ("new-object",
88                               G_OBJECT_CLASS_TYPE (klass),
89                               0,
90                               G_STRUCT_OFFSET (VikGobjectBuilderClass, new_object),
91                               NULL, NULL,
92                               g_cclosure_marshal_VOID__OBJECT,
93                               G_TYPE_NONE, 1,
94                               G_TYPE_OBJECT);
95 }
96
97 /* Called for open tags <foo bar="baz"> */
98 static void
99 _start_element (GMarkupParseContext *context,
100                 const gchar         *element_name,
101                 const gchar        **attribute_names,
102                 const gchar        **attribute_values,
103                 gpointer             user_data,
104                 GError             **error)
105 {
106         if (strcmp(element_name, "object") == 0)
107         {
108                 class_name = g_strdup(attribute_values[0]);
109                 gtype = g_type_from_name (class_name);
110         }
111         if (strcmp(element_name, "property") == 0 && gtype != 0)
112         {
113                 int i=0;
114                 while (attribute_names[i] != NULL)
115                 {
116                         if (strcmp (attribute_names[i], "name") == 0)
117                         {
118                                 g_free (property_name);
119                                 property_name = g_strdup (attribute_values[i]);
120                         }
121                         i++;
122                 }
123         }
124 }
125
126 /* Called for close tags </foo> */
127 static void
128 _end_element (GMarkupParseContext *context,
129               const gchar         *element_name,
130               gpointer             user_data,
131               GError             **error)
132 {
133         VikGobjectBuilder *self = VIK_GOBJECT_BUILDER (user_data);
134         gpointer object = NULL;
135         if (strcmp(element_name, "object") == 0 && gtype != 0)
136         {
137                 object = g_object_newv(gtype, nb_parameters, parameters);
138                 if (object != NULL)
139                 {
140                         g_debug("VikGobjectBuilder: new GObject of type %s", g_type_name(gtype));
141                         g_signal_emit ( G_OBJECT(self), gobject_builder_signals[NEW_OBJECT], 0, object );
142                         g_object_unref (object);
143                 }
144                 /* Free memory */
145                 int i = 0;
146                 for (i = 0 ; i < nb_parameters ; i++)
147                 {
148                         g_free (parameters[i].name);
149                         g_value_unset (&(parameters[i].value));
150                 }
151                 g_free (parameters);
152                 parameters = NULL;
153                 nb_parameters = 0;
154                 gtype = 0;
155         }
156         if (strcmp(element_name, "property") == 0)
157         {
158                 g_free (property_name);
159                 property_name = NULL;
160         }
161 }
162
163 /* Called for character data */
164 /* text is not nul-terminated */
165 static void
166 _text (GMarkupParseContext *context,
167        const gchar         *text,
168        gsize                text_len,  
169        gpointer             user_data,
170        GError             **error)
171 {
172         if (strcmp (g_markup_parse_context_get_element (context), "property") == 0)
173         {
174                 GValue gvalue = {0};
175                 gboolean found = FALSE;
176                 if (gtype != 0 && property_name != NULL)
177                 {
178                         /* parameter value */
179                         /* We have to retrieve the expected type of the value 
180                          * in order to do the correct transformation */
181                         GObjectClass *oclass;
182                         oclass = g_type_class_ref (gtype);
183                         g_assert (oclass != NULL);
184                         GParamSpec *pspec;
185                         pspec = g_object_class_find_property (G_OBJECT_CLASS (oclass), property_name);
186                         if (!pspec)
187                         {
188                                 g_warning ("Unknown property: %s.%s", g_type_name (gtype), property_name);
189                                 return;
190                         }
191                         gchar *value = g_strndup (text, text_len);
192                         found = gtk_builder_value_from_string_type(NULL, pspec->value_type, value, &gvalue, NULL);
193                         g_free (value);
194                 }
195                 if (G_IS_VALUE (&gvalue) && found == TRUE)
196                 {
197                         /* store new parameter */
198                         g_debug("VikGobjectBuilder: store new GParameter for %s: (%s)%s=%*s",
199                                 g_type_name(gtype), g_type_name(G_VALUE_TYPE(&gvalue)), property_name, text_len, text);
200                         nb_parameters++;
201                         parameters = g_realloc(parameters, sizeof(GParameter)*nb_parameters);
202                         /* parameter name */
203                         parameters[nb_parameters-1].name = g_strdup(property_name);
204                         /* parameter value */
205                         parameters[nb_parameters-1].value = gvalue;
206                 }
207         }
208 }
209
210 VikGobjectBuilder *
211 vik_gobject_builder_new (void)
212 {
213         return g_object_new (VIK_TYPE_GOBJECT_BUILDER, NULL);
214 }
215
216 void
217 vik_gobject_builder_parse (VikGobjectBuilder *self, const gchar *filename)
218 {
219         GMarkupParser xml_parser;
220         GMarkupParseContext *xml_context;
221         GError *error;
222
223         FILE *file = g_fopen (filename, "r");
224         if (file == NULL)
225                 /* TODO emit warning */
226                 return;
227         
228         /* setup context parse (ie callbacks) */
229         xml_parser.start_element = &_start_element;
230         xml_parser.end_element = &_end_element;
231         xml_parser.text = &_text;
232         xml_parser.passthrough = NULL;
233         xml_parser.error = NULL;
234         
235         xml_context = g_markup_parse_context_new(&xml_parser, 0, self, NULL);
236         
237         gchar buff[BUFSIZ];
238         size_t nb;
239         while ((nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0)
240         {
241                 if (!g_markup_parse_context_parse(xml_context, buff, nb, &error))
242                         printf("read_xml() : parsing error.\n");
243         }
244         /* cleanup */
245         if (!g_markup_parse_context_end_parse(xml_context, &error))
246                 printf("read_xml() : errors occurred reading file.\n");
247         
248         g_markup_parse_context_free(xml_context);
249         fclose (file);
250 }