]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/vikgotoxmltool.c
Improve key bindings for ModeLatLon.
[andy/viking.git] / src / vikgotoxmltool.c
... / ...
CommitLineData
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (C) 2009, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#ifdef HAVE_MATH_H
29#include "math.h"
30#endif
31#include <glib.h>
32#include <glib/gstdio.h>
33#include <glib/gprintf.h>
34#include <glib/gi18n.h>
35
36#include "viking.h"
37
38#include "vikgotoxmltool.h"
39
40
41static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass );
42static void _goto_xml_tool_init ( VikGotoXmlTool *self );
43
44static void _goto_xml_tool_finalize ( GObject *gob );
45
46static gchar *_goto_xml_tool_get_url_format ( VikGotoTool *self );
47static gboolean _goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll);
48
49typedef struct _VikGotoXmlToolPrivate VikGotoXmlToolPrivate;
50
51struct _VikGotoXmlToolPrivate
52{
53 gchar *url_format;
54 gchar *lat_path;
55 gchar *lat_attr;
56 gchar *lon_path;
57 gchar *lon_attr;
58
59 struct LatLon ll;
60};
61
62#define GOTO_XML_TOOL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
63 VIK_GOTO_XML_TOOL_TYPE, \
64 VikGotoXmlToolPrivate))
65
66GType vik_goto_xml_tool_get_type()
67{
68 static GType w_type = 0;
69
70 if (!w_type)
71 {
72 static const GTypeInfo w_info =
73 {
74 sizeof (VikGotoXmlToolClass),
75 NULL, /* base_init */
76 NULL, /* base_finalize */
77 (GClassInitFunc) _goto_xml_tool_class_init,
78 NULL, /* class_finalize */
79 NULL, /* class_data */
80 sizeof (VikGotoXmlTool),
81 0,
82 (GInstanceInitFunc) _goto_xml_tool_init,
83 };
84 w_type = g_type_register_static ( VIK_GOTO_TOOL_TYPE, "VikGotoXmlTool", &w_info, 0 );
85 }
86
87 return w_type;
88}
89
90enum
91{
92 PROP_0,
93
94 PROP_URL_FORMAT,
95 PROP_LAT_PATH,
96 PROP_LAT_ATTR,
97 PROP_LON_PATH,
98 PROP_LON_ATTR,
99};
100
101static void
102_goto_xml_tool_set_property (GObject *object,
103 guint property_id,
104 const GValue *value,
105 GParamSpec *pspec)
106{
107 VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object);
108 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
109 gchar **splitted = NULL;
110
111 switch (property_id)
112 {
113 case PROP_URL_FORMAT:
114 g_free (priv->url_format);
115 priv->url_format = g_value_dup_string (value);
116 break;
117
118 case PROP_LAT_PATH:
119 splitted = g_strsplit (g_value_get_string (value), "@", 2);
120 g_free (priv->lat_path);
121 priv->lat_path = splitted[0];
122 if (splitted[1])
123 {
124 g_object_set (object, "lat-attr", splitted[1], NULL);
125 g_free (splitted[1]);
126 }
127 /* only free the tab, not the strings */
128 g_free (splitted);
129 splitted = NULL;
130 break;
131
132 case PROP_LAT_ATTR:
133 /* Avoid to overwrite XPATH value */
134 /* NB: This disable future overwriting,
135 but as property is CONSTRUCT_ONLY there is no matter */
136 if (!priv->lat_attr || g_value_get_string (value))
137 {
138 g_free (priv->lat_attr);
139 priv->lat_attr = g_value_dup_string (value);
140 }
141 break;
142
143 case PROP_LON_PATH:
144 splitted = g_strsplit (g_value_get_string (value), "@", 2);
145 g_free (priv->lon_path);
146 priv->lon_path = splitted[0];
147 if (splitted[1])
148 {
149 g_object_set (object, "lon-attr", splitted[1], NULL);
150 g_free (splitted[1]);
151 }
152 /* only free the tab, not the strings */
153 g_free (splitted);
154 splitted = NULL;
155 break;
156
157 case PROP_LON_ATTR:
158 /* Avoid to overwrite XPATH value */
159 /* NB: This disable future overwriting,
160 but as property is CONSTRUCT_ONLY there is no matter */
161 if (!priv->lon_attr || g_value_get_string (value))
162 {
163 g_free (priv->lon_attr);
164 priv->lon_attr = g_value_dup_string (value);
165 }
166 break;
167
168 default:
169 /* We don't have any other property... */
170 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
171 break;
172 }
173}
174
175static void
176_goto_xml_tool_get_property (GObject *object,
177 guint property_id,
178 GValue *value,
179 GParamSpec *pspec)
180{
181 VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object);
182 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
183
184 switch (property_id)
185 {
186 case PROP_URL_FORMAT:
187 g_value_set_string (value, priv->url_format);
188 break;
189
190 case PROP_LAT_PATH:
191 g_value_set_string (value, priv->lat_path);
192 break;
193
194 case PROP_LAT_ATTR:
195 g_value_set_string (value, priv->lat_attr);
196 break;
197
198 case PROP_LON_PATH:
199 g_value_set_string (value, priv->lon_path);
200 break;
201
202 case PROP_LON_ATTR:
203 g_value_set_string (value, priv->lon_attr);
204 break;
205
206 default:
207 /* We don't have any other property... */
208 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
209 break;
210 }
211}
212
213static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass )
214{
215 GObjectClass *object_class;
216 VikGotoToolClass *parent_class;
217 GParamSpec *pspec;
218
219 object_class = G_OBJECT_CLASS (klass);
220
221 object_class->finalize = _goto_xml_tool_finalize;
222 object_class->set_property = _goto_xml_tool_set_property;
223 object_class->get_property = _goto_xml_tool_get_property;
224
225
226 pspec = g_param_spec_string ("url-format",
227 "URL format",
228 "The format of the URL",
229 "<no-set>" /* default value */,
230 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
231 g_object_class_install_property (object_class,
232 PROP_URL_FORMAT,
233 pspec);
234
235 pspec = g_param_spec_string ("lat-path",
236 "Latitude path",
237 "XPath of the latitude",
238 "<no-set>" /* default value */,
239 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
240 g_object_class_install_property (object_class,
241 PROP_LAT_PATH,
242 pspec);
243
244 pspec = g_param_spec_string ("lat-attr",
245 "Latitude attribute",
246 "XML attribute of the latitude",
247 NULL /* default value */,
248 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
249 g_object_class_install_property (object_class,
250 PROP_LAT_ATTR,
251 pspec);
252
253 pspec = g_param_spec_string ("lon-path",
254 "Longitude path",
255 "XPath of the longitude",
256 "<no-set>" /* default value */,
257 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
258 g_object_class_install_property (object_class,
259 PROP_LON_PATH,
260 pspec);
261
262 pspec = g_param_spec_string ("lon-attr",
263 "Longitude attribute",
264 "XML attribute of the longitude",
265 NULL /* default value */,
266 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
267 g_object_class_install_property (object_class,
268 PROP_LON_ATTR,
269 pspec);
270
271 parent_class = VIK_GOTO_TOOL_CLASS (klass);
272
273 parent_class->get_url_format = _goto_xml_tool_get_url_format;
274 parent_class->parse_file_for_latlon = _goto_xml_tool_parse_file_for_latlon;
275
276 g_type_class_add_private (klass, sizeof (VikGotoXmlToolPrivate));
277}
278
279VikGotoXmlTool *vik_goto_xml_tool_new ()
280{
281 return VIK_GOTO_XML_TOOL ( g_object_new ( VIK_GOTO_XML_TOOL_TYPE, "label", "Google", NULL ) );
282}
283
284static void _goto_xml_tool_init ( VikGotoXmlTool *self )
285{
286 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
287 priv->url_format = NULL;
288 priv->lat_path = NULL;
289 priv->lat_attr = NULL;
290 priv->lon_path = NULL;
291 priv->lon_attr = NULL;
292 //
293 priv->ll.lat = NAN;
294 priv->ll.lon = NAN;
295}
296
297static void _goto_xml_tool_finalize ( GObject *gob )
298{
299 G_OBJECT_GET_CLASS(gob)->finalize(gob);
300}
301
302static gboolean
303stack_is_path (const GSList *stack,
304 const gchar *path)
305{
306 gboolean equal = TRUE;
307 int stack_len = g_list_length((GList *)stack);
308 int i = 0;
309 i = stack_len - 1;
310 while (equal == TRUE && i >= 0)
311 {
312 if (*path != '/')
313 equal = FALSE;
314 else
315 path++;
316 const gchar *current = g_list_nth_data((GList *)stack, i);
317 size_t len = strlen(current);
318 if (strncmp(path, current, len) != 0 )
319 equal = FALSE;
320 else
321 {
322 path += len;
323 }
324 i--;
325 }
326 if (*path != '\0')
327 equal = FALSE;
328 return equal;
329}
330
331/* Called for open tags <foo bar="baz"> */
332static void
333_start_element (GMarkupParseContext *context,
334 const gchar *element_name,
335 const gchar **attribute_names,
336 const gchar **attribute_values,
337 gpointer user_data,
338 GError **error)
339{
340 VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (user_data);
341 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
342 const GSList *stack = g_markup_parse_context_get_element_stack (context);
343 /* Longitude */
344 if (priv->lon_attr != NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path))
345 {
346 int i=0;
347 while (attribute_names[i] != NULL)
348 {
349 if (strcmp (attribute_names[i], priv->lon_attr) == 0)
350 {
351 priv->ll.lon = g_ascii_strtod(attribute_values[i], NULL);
352 }
353 i++;
354 }
355 }
356 /* Latitude */
357 if (priv->lat_attr != NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path))
358 {
359 int i=0;
360 while (attribute_names[i] != NULL)
361 {
362 if (strcmp (attribute_names[i], priv->lat_attr) == 0)
363 {
364 priv->ll.lat = g_ascii_strtod(attribute_values[i], NULL);
365 }
366 i++;
367 }
368 }
369}
370
371/* Called for character data */
372/* text is not nul-terminated */
373static void
374_text (GMarkupParseContext *context,
375 const gchar *text,
376 gsize text_len,
377 gpointer user_data,
378 GError **error)
379{
380 VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (user_data);
381 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
382 const GSList *stack = g_markup_parse_context_get_element_stack (context);
383 gchar *textl = g_strndup(text, text_len);
384 /* Store only first result */
385 if (priv->lat_attr == NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path))
386 {
387 priv->ll.lat = g_ascii_strtod(textl, NULL);
388 }
389 if (priv->lon_attr == NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path))
390 {
391 priv->ll.lon = g_ascii_strtod(textl, NULL);
392 }
393 g_free(textl);
394}
395
396static gboolean
397_goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll)
398{
399 GMarkupParser xml_parser;
400 GMarkupParseContext *xml_context = NULL;
401 GError *error = NULL;
402 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
403 g_return_val_if_fail(priv != NULL, FALSE);
404
405 g_debug ("%s: %s@%s, %s@%s",
406 __FUNCTION__,
407 priv->lat_path, priv->lat_attr,
408 priv->lon_path, priv->lon_attr);
409
410 FILE *file = g_fopen (filename, "r");
411 if (file == NULL)
412 /* TODO emit warning */
413 return FALSE;
414
415 /* setup context parse (ie callbacks) */
416 if (priv->lat_attr != NULL || priv->lon_attr != NULL)
417 // At least one coordinate uses an attribute
418 xml_parser.start_element = &_start_element;
419 else
420 xml_parser.start_element = NULL;
421 xml_parser.end_element = NULL;
422 if (priv->lat_attr == NULL || priv->lon_attr == NULL)
423 // At least one coordinate uses a raw element
424 xml_parser.text = &_text;
425 else
426 xml_parser.text = NULL;
427 xml_parser.passthrough = NULL;
428 xml_parser.error = NULL;
429
430 xml_context = g_markup_parse_context_new(&xml_parser, 0, self, NULL);
431
432 /* setup result */
433 priv->ll.lat = NAN;
434 priv->ll.lon = NAN;
435
436 gchar buff[BUFSIZ];
437 size_t nb;
438 while (xml_context &&
439 (nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0)
440 {
441 if (!g_markup_parse_context_parse(xml_context, buff, nb, &error))
442 {
443 fprintf(stderr, "%s: parsing error: %s.\n",
444 __FUNCTION__, error->message);
445 g_markup_parse_context_free(xml_context);
446 xml_context = NULL;
447 }
448 g_clear_error (&error);
449 }
450 /* cleanup */
451 if (xml_context &&
452 !g_markup_parse_context_end_parse(xml_context, &error))
453 fprintf(stderr, "%s: errors occurred while reading file: %s.\n",
454 __FUNCTION__, error->message);
455 g_clear_error (&error);
456
457 if (xml_context)
458 g_markup_parse_context_free(xml_context);
459 xml_context = NULL;
460 fclose (file);
461
462 if (ll != NULL)
463 {
464 *ll = priv->ll;
465 }
466
467 if (isnan(priv->ll.lat) || isnan(priv->ll.lat))
468 /* At least one coordinate not found */
469 return FALSE;
470 else
471 return TRUE;
472}
473
474static gchar *
475_goto_xml_tool_get_url_format ( VikGotoTool *self )
476{
477 VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self);
478 g_return_val_if_fail(priv != NULL, NULL);
479 return priv->url_format;
480}