]> git.street.me.uk Git - andy/viking.git/blob - src/vikgobjectbuilder.c
Use the correct definition.
[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) 2009, Guilhem Bonnefille <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 2 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/gtk.h>
33
34 #include "vikgobjectbuilder.h"
35
36 /* FIXME use private fields */
37 GType gtype = 0;
38 gchar *property_name = NULL;
39 GParameter *parameters = NULL;
40 gint nb_parameters = 0;
41
42 /* signals */
43 enum
44 {
45         NEW_OBJECT,
46
47         LAST_SIGNAL
48 };
49
50
51 static guint gobject_builder_signals[LAST_SIGNAL] = { 0 };
52
53 G_DEFINE_TYPE (VikGobjectBuilder, vik_gobject_builder, G_TYPE_OBJECT);
54
55 static void
56 vik_gobject_builder_init (VikGobjectBuilder *object)
57 {
58         /* TODO: Add initialization code here */
59 }
60
61 static void
62 vik_gobject_builder_finalize (GObject *object)
63 {
64         /* TODO: Add deinitalization code here */
65
66         G_OBJECT_CLASS (vik_gobject_builder_parent_class)->finalize (object);
67 }
68
69 static void
70 vik_gobject_builder_new_object (VikGobjectBuilder *self, GObject *object)
71 {
72         /* TODO: Add default signal handler implementation here */
73 }
74
75 static void
76 vik_gobject_builder_class_init (VikGobjectBuilderClass *klass)
77 {
78         GObjectClass* object_class = G_OBJECT_CLASS (klass);
79
80         object_class->finalize = vik_gobject_builder_finalize;
81
82         klass->new_object = vik_gobject_builder_new_object;
83
84         gobject_builder_signals[NEW_OBJECT] =
85                 g_signal_new ("new-object",
86                               G_OBJECT_CLASS_TYPE (klass),
87                               0,
88                               G_STRUCT_OFFSET (VikGobjectBuilderClass, new_object),
89                               NULL, NULL,
90                               g_cclosure_marshal_VOID__OBJECT,
91                               G_TYPE_NONE, 1,
92                               G_TYPE_OBJECT);
93 }
94
95 /* Called for open tags <foo bar="baz"> */
96 static void
97 _start_element (GMarkupParseContext *context,
98                 const gchar         *element_name,
99                 const gchar        **attribute_names,
100                 const gchar        **attribute_values,
101                 gpointer             user_data,
102                 GError             **error)
103 {
104         if (strcmp(element_name, "object") == 0)
105         {
106                 gchar *class_name = g_strdup(attribute_values[0]);
107                 gtype = g_type_from_name (class_name);
108                 if (gtype == 0)
109                 {
110                         g_warning("Unknown GObject type '%s'", class_name);
111                         return;
112                 }
113                 g_free (class_name);
114         }
115         if (strcmp(element_name, "property") == 0 && gtype != 0)
116         {
117                 int i=0;
118                 while (attribute_names[i] != NULL)
119                 {
120                         if (strcmp (attribute_names[i], "name") == 0)
121                         {
122                                 g_free (property_name);
123                                 property_name = g_strdup (attribute_values[i]);
124                         }
125                         i++;
126                 }
127         }
128 }
129
130 /* Called for close tags </foo> */
131 static void
132 _end_element (GMarkupParseContext *context,
133               const gchar         *element_name,
134               gpointer             user_data,
135               GError             **error)
136 {
137         VikGobjectBuilder *self = VIK_GOBJECT_BUILDER (user_data);
138         gpointer object = NULL;
139         if (strcmp(element_name, "object") == 0 && gtype != 0)
140         {
141                 object = g_object_newv(gtype, nb_parameters, parameters);
142                 if (object != NULL)
143                 {
144                         g_debug("VikGobjectBuilder: new GObject of type %s", g_type_name(gtype));
145                         g_signal_emit ( G_OBJECT(self), gobject_builder_signals[NEW_OBJECT], 0, object );
146                         g_object_unref (object);
147                 }
148                 /* Free memory */
149                 int i = 0;
150                 for (i = 0 ; i < nb_parameters ; i++)
151                 {
152                         g_free ((gchar *)parameters[i].name);
153                         g_value_unset (&(parameters[i].value));
154                 }
155                 g_free (parameters);
156                 parameters = NULL;
157                 nb_parameters = 0;
158                 gtype = 0;
159         }
160         if (strcmp(element_name, "property") == 0)
161         {
162                 g_free (property_name);
163                 property_name = NULL;
164         }
165 }
166
167 /* Called for character data */
168 /* text is not nul-terminated */
169 static void
170 _text (GMarkupParseContext *context,
171        const gchar         *text,
172        gsize                text_len,  
173        gpointer             user_data,
174        GError             **error)
175 {
176         if (strcmp (g_markup_parse_context_get_element (context), "property") == 0)
177         {
178                 GValue gvalue = {0};
179                 gboolean found = FALSE;
180                 if (gtype != 0 && property_name != NULL)
181                 {
182                         /* parameter value */
183                         /* We have to retrieve the expected type of the value 
184                          * in order to do the correct transformation */
185                         GObjectClass *oclass;
186                         oclass = g_type_class_ref (gtype);
187                         g_assert (oclass != NULL);
188                         GParamSpec *pspec;
189                         pspec = g_object_class_find_property (G_OBJECT_CLASS (oclass), property_name);
190                         if (!pspec)
191                         {
192                                 g_warning ("Unknown property: %s.%s", g_type_name (gtype), property_name);
193                                 return;
194                         }
195                         gchar *value = g_strndup (text, text_len);
196                         found = gtk_builder_value_from_string_type(NULL, pspec->value_type, value, &gvalue, NULL);
197                         g_free (value);
198                 }
199                 if (G_IS_VALUE (&gvalue) && found == TRUE)
200                 {
201                         /* store new parameter */
202                         g_debug("VikGobjectBuilder: store new GParameter for %s: (%s)%s=%*s",
203                                 g_type_name(gtype), g_type_name(G_VALUE_TYPE(&gvalue)), property_name, (gint)text_len, text);
204                         nb_parameters++;
205                         parameters = g_realloc(parameters, sizeof(GParameter)*nb_parameters);
206                         /* parameter name */
207                         parameters[nb_parameters-1].name = g_strdup(property_name);
208                         /* parameter value */
209                         parameters[nb_parameters-1].value = gvalue;
210                 }
211         }
212 }
213
214 VikGobjectBuilder *
215 vik_gobject_builder_new (void)
216 {
217         return g_object_new (VIK_TYPE_GOBJECT_BUILDER, NULL);
218 }
219
220 void
221 vik_gobject_builder_parse (VikGobjectBuilder *self, const gchar *filename)
222 {
223         GMarkupParser xml_parser;
224         GMarkupParseContext *xml_context;
225         GError *error = NULL;
226
227         FILE *file = g_fopen (filename, "r");
228         if (file == NULL)
229                 /* TODO emit warning */
230                 return;
231         
232         /* setup context parse (ie callbacks) */
233         xml_parser.start_element = &_start_element;
234         xml_parser.end_element = &_end_element;
235         xml_parser.text = &_text;
236         xml_parser.passthrough = NULL;
237         xml_parser.error = NULL;
238         
239         xml_context = g_markup_parse_context_new(&xml_parser, 0, self, NULL);
240         
241         gchar buff[BUFSIZ];
242         size_t nb;
243         while ((nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0)
244         {
245                 if (!g_markup_parse_context_parse(xml_context, buff, nb, &error))
246                         g_warning("%s: parsing error: %s", __FUNCTION__,
247                                   error != NULL ? error->message : "???");
248         }
249         /* cleanup */
250         if (!g_markup_parse_context_end_parse(xml_context, &error))
251                 g_warning("%s: errors occurred reading file '%s': %s", __FUNCTION__, filename,
252                           error != NULL ? error->message : "???");
253         
254         g_markup_parse_context_free(xml_context);
255         fclose (file);
256 }