]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/vikroutingwebengine.c
Fix display of map tile source information when it has extended characters.
[andy/viking.git] / src / vikroutingwebengine.c
... / ...
CommitLineData
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (c) 2013, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22/**
23 * SECTION:vikroutingwebengine
24 * @short_description: A generic class for WEB based routing engine
25 *
26 * The #VikRoutingWebEngine class handles WEB based
27 * routing engine.
28 */
29
30#ifdef HAVE_CONFIG_H
31#include "config.h"
32#endif
33
34#include <string.h>
35
36#include <glib.h>
37#include <glib/gstdio.h>
38
39#include "babel.h"
40
41#include "vikroutingwebengine.h"
42
43static void vik_routing_web_engine_finalize ( GObject *gob );
44
45static gboolean vik_routing_web_engine_find ( VikRoutingEngine *self, VikTrwLayer *vtl, struct LatLon start, struct LatLon end );
46static gchar *vik_routing_web_engine_get_cmd_from_directions(VikRoutingEngine *self, const gchar *start, const gchar *end);
47static gboolean vik_routing_web_engine_supports_direction(VikRoutingEngine *self);
48static gboolean vik_routing_web_engine_refine ( VikRoutingEngine *self, VikTrwLayer *vtl, VikTrack *vt );
49static gboolean vik_routing_web_engine_supports_refine ( VikRoutingEngine *self );
50
51typedef struct _VikRoutingWebEnginePrivate VikRoutingWebEnginePrivate;
52struct _VikRoutingWebEnginePrivate
53{
54 gchar *url_base;
55
56 /* LatLon */
57 gchar *url_start_ll_fmt;
58 gchar *url_stop_ll_fmt;
59 gchar *url_via_ll_fmt;
60
61 /* Directions */
62 gchar *url_start_dir_fmt;
63 gchar *url_stop_dir_fmt;
64
65 DownloadMapOptions options;
66};
67
68#define VIK_ROUTING_WEB_ENGINE_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), VIK_ROUTING_WEB_ENGINE_TYPE, VikRoutingWebEnginePrivate))
69
70/* properties */
71enum
72{
73 PROP_0,
74
75 PROP_URL_BASE,
76
77 /* LatLon */
78 PROP_URL_START_LL,
79 PROP_URL_STOP_LL,
80 PROP_URL_VIA_LL,
81
82 /* Direction */
83 PROP_URL_START_DIR,
84 PROP_URL_STOP_DIR,
85
86 PROP_REFERER,
87 PROP_FOLLOW_LOCATION,
88};
89
90G_DEFINE_TYPE (VikRoutingWebEngine, vik_routing_web_engine, VIK_ROUTING_ENGINE_TYPE)
91
92static void
93vik_routing_web_engine_set_property (GObject *object,
94 guint property_id,
95 const GValue *value,
96 GParamSpec *pspec)
97{
98 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
99
100 switch (property_id)
101 {
102 case PROP_URL_BASE:
103 g_free (priv->url_base);
104 priv->url_base = g_strdup(g_value_get_string (value));
105 break;
106
107 case PROP_URL_START_LL:
108 g_free (priv->url_start_ll_fmt);
109 priv->url_start_ll_fmt = g_strdup(g_value_get_string (value));
110 break;
111
112 case PROP_URL_STOP_LL:
113 g_free (priv->url_stop_ll_fmt);
114 priv->url_stop_ll_fmt = g_strdup(g_value_get_string (value));
115 break;
116
117 case PROP_URL_VIA_LL:
118 g_free (priv->url_via_ll_fmt);
119 priv->url_via_ll_fmt = g_strdup(g_value_get_string (value));
120 break;
121
122 case PROP_URL_START_DIR:
123 g_free (priv->url_start_dir_fmt);
124 priv->url_start_dir_fmt = g_strdup(g_value_get_string (value));
125 break;
126
127 case PROP_URL_STOP_DIR:
128 g_free (priv->url_stop_dir_fmt);
129 priv->url_stop_dir_fmt = g_strdup(g_value_get_string (value));
130 break;
131
132 case PROP_REFERER:
133 g_free (priv->options.referer);
134 priv->options.referer = g_value_dup_string (value);
135 break;
136
137 case PROP_FOLLOW_LOCATION:
138 priv->options.follow_location = g_value_get_long (value);
139 break;
140
141 default:
142 /* We don't have any other property... */
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
144 break;
145 }
146}
147
148static void
149vik_routing_web_engine_get_property (GObject *object,
150 guint property_id,
151 GValue *value,
152 GParamSpec *pspec)
153{
154 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( object );
155
156 switch (property_id)
157 {
158 case PROP_URL_BASE:
159 g_value_set_string (value, priv->url_base);
160 break;
161
162 case PROP_URL_START_LL:
163 g_value_set_string (value, priv->url_start_ll_fmt);
164 break;
165
166 case PROP_URL_STOP_LL:
167 g_value_set_string (value, priv->url_stop_ll_fmt);
168 break;
169
170 case PROP_URL_VIA_LL:
171 g_value_set_string (value, priv->url_via_ll_fmt);
172 break;
173
174 case PROP_URL_START_DIR:
175 g_value_set_string (value, priv->url_start_dir_fmt);
176 break;
177
178 case PROP_URL_STOP_DIR:
179 g_value_set_string (value, priv->url_stop_dir_fmt);
180 break;
181
182 case PROP_REFERER:
183 g_value_set_string (value, priv->options.referer);
184 break;
185
186 case PROP_FOLLOW_LOCATION:
187 g_value_set_long (value, priv->options.follow_location);
188 break;
189
190 default:
191 /* We don't have any other property... */
192 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
193 break;
194 }
195}
196
197static void vik_routing_web_engine_class_init ( VikRoutingWebEngineClass *klass )
198{
199 GObjectClass *object_class;
200 VikRoutingEngineClass *parent_class;
201 GParamSpec *pspec = NULL;
202
203 object_class = G_OBJECT_CLASS (klass);
204
205 object_class->set_property = vik_routing_web_engine_set_property;
206 object_class->get_property = vik_routing_web_engine_get_property;
207 object_class->finalize = vik_routing_web_engine_finalize;
208
209 parent_class = VIK_ROUTING_ENGINE_CLASS (klass);
210
211 parent_class->find = vik_routing_web_engine_find;
212 parent_class->supports_direction = vik_routing_web_engine_supports_direction;
213 parent_class->get_cmd_from_directions = vik_routing_web_engine_get_cmd_from_directions;
214 parent_class->refine = vik_routing_web_engine_refine;
215 parent_class->supports_refine = vik_routing_web_engine_supports_refine;
216
217 /**
218 * VikRoutingWebEngine:url-base:
219 *
220 * The base URL of the routing engine.
221 */
222 pspec = g_param_spec_string ("url-base",
223 "URL's base",
224 "The base URL of the routing engine",
225 "<no-set>" /* default value */,
226 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
227 g_object_class_install_property (object_class, PROP_URL_BASE, pspec);
228
229
230 /**
231 * VikRoutingWebEngine:url-start-ll:
232 *
233 * The part of the request hosting the end point.
234 */
235 pspec = g_param_spec_string ("url-start-ll",
236 "Start part of the URL",
237 "The part of the request hosting the start point",
238 "<no-set>" /* default value */,
239 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
240 g_object_class_install_property (object_class, PROP_URL_START_LL, pspec);
241
242
243 /**
244 * VikRoutingWebEngine:url-stop-ll:
245 *
246 * The part of the request hosting the end point.
247 */
248 pspec = g_param_spec_string ("url-stop-ll",
249 "Stop part of the URL",
250 "The part of the request hosting the end point",
251 "<no-set>" /* default value */,
252 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
253 g_object_class_install_property (object_class, PROP_URL_STOP_LL, pspec);
254
255
256 /**
257 * VikRoutingWebEngine:url-via-ll:
258 *
259 * The param of the request for setting a via point.
260 */
261 pspec = g_param_spec_string ("url-via-ll",
262 "Via part of the URL",
263 "The param of the request for setting a via point",
264 NULL /* default value */,
265 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
266 g_object_class_install_property (object_class, PROP_URL_VIA_LL, pspec);
267
268
269 /**
270 * VikRoutingWebEngine:url-start-dir:
271 *
272 * The part of the request hosting the end point.
273 */
274 pspec = g_param_spec_string ("url-start-dir",
275 "Start part of the URL",
276 "The part of the request hosting the start point",
277 NULL /* default value */,
278 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
279 g_object_class_install_property (object_class, PROP_URL_START_DIR, pspec);
280
281
282 /**
283 * VikRoutingWebEngine:url-stop-dir:
284 *
285 * The part of the request hosting the end point.
286 */
287 pspec = g_param_spec_string ("url-stop-dir",
288 "Stop part of the URL",
289 "The part of the request hosting the end point",
290 NULL /* default value */,
291 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
292 g_object_class_install_property (object_class, PROP_URL_STOP_DIR, pspec);
293
294
295 /**
296 * VikRoutingWebEngine:referer:
297 *
298 * The REFERER string to use in HTTP request.
299 */
300 pspec = g_param_spec_string ("referer",
301 "Referer",
302 "The REFERER string to use in HTTP request",
303 NULL /* default value */,
304 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
305 g_object_class_install_property (object_class, PROP_REFERER, pspec);
306
307
308 /**
309 * VikRoutingWebEngine:follow-location:
310 *
311 * Specifies the number of retries to follow a redirect while downloading a page.
312 */
313 pspec = g_param_spec_long ("follow-location",
314 "Follow location",
315 "Specifies the number of retries to follow a redirect while downloading a page",
316 0 /* minimum value */,
317 G_MAXLONG /* maximum value */,
318 2 /* default value */,
319 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
320 g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
321
322 g_type_class_add_private (klass, sizeof (VikRoutingWebEnginePrivate));
323}
324
325static void vik_routing_web_engine_init ( VikRoutingWebEngine *self )
326{
327 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
328
329 priv->url_base = NULL;
330
331 /* LatLon */
332 priv->url_start_ll_fmt = NULL;
333 priv->url_stop_ll_fmt = NULL;
334 priv->url_via_ll_fmt = NULL;
335
336 /* Directions */
337 priv->url_start_dir_fmt = NULL;
338 priv->url_stop_dir_fmt = NULL;
339
340 priv->options.referer = NULL;
341 priv->options.follow_location = 0;
342 priv->options.check_file = NULL;
343 priv->options.check_file_server_time = FALSE;
344 priv->options.use_etag = FALSE;
345}
346
347static void vik_routing_web_engine_finalize ( GObject *gob )
348{
349 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( gob );
350
351 g_free (priv->url_base);
352 priv->url_base = NULL;
353
354 /* LatLon */
355 g_free (priv->url_start_ll_fmt);
356 priv->url_start_ll_fmt = NULL;
357 g_free (priv->url_stop_ll_fmt);
358 priv->url_stop_ll_fmt = NULL;
359 g_free (priv->url_via_ll_fmt);
360 priv->url_via_ll_fmt = NULL;
361
362 /* Directions */
363 g_free (priv->url_start_dir_fmt);
364 priv->url_start_dir_fmt = NULL;
365 g_free (priv->url_stop_dir_fmt);
366 priv->url_stop_dir_fmt = NULL;
367
368 g_free (priv->options.referer);
369 priv->options.referer = NULL;
370
371 G_OBJECT_CLASS (vik_routing_web_engine_parent_class)->finalize(gob);
372}
373
374static DownloadMapOptions *
375vik_routing_web_engine_get_download_options ( VikRoutingEngine *self )
376{
377 g_return_val_if_fail (VIK_IS_ROUTING_WEB_ENGINE(self), NULL);
378
379 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE(self);
380
381 return &(priv->options);
382}
383
384static gchar *
385substitute_latlon ( const gchar *fmt, struct LatLon ll )
386{
387 gchar lat[G_ASCII_DTOSTR_BUF_SIZE], lon[G_ASCII_DTOSTR_BUF_SIZE];
388 gchar *substituted = g_strdup_printf(fmt,
389 g_ascii_dtostr (lat, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) ll.lat),
390 g_ascii_dtostr (lon, G_ASCII_DTOSTR_BUF_SIZE, (gdouble) ll.lon));
391 return substituted;
392}
393
394static gchar *
395vik_routing_web_engine_get_url_for_coords ( VikRoutingEngine *self, struct LatLon start, struct LatLon end )
396{
397 gchar *startURL;
398 gchar *endURL;
399 gchar *url;
400
401 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
402
403 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
404
405 g_return_val_if_fail ( priv->url_base != NULL, NULL);
406 g_return_val_if_fail ( priv->url_start_ll_fmt != NULL, NULL);
407 g_return_val_if_fail ( priv->url_stop_ll_fmt != NULL, NULL);
408
409 startURL = substitute_latlon ( priv->url_start_ll_fmt, start );
410 endURL = substitute_latlon ( priv->url_stop_ll_fmt, end );
411 url = g_strconcat ( priv->url_base, startURL, endURL, NULL );
412
413 /* Free memory */
414 g_free ( startURL );
415 g_free ( endURL );
416
417 return url;
418}
419
420static gboolean
421vik_routing_web_engine_find ( VikRoutingEngine *self, VikTrwLayer *vtl, struct LatLon start, struct LatLon end )
422{
423 gchar *uri = vik_routing_web_engine_get_url_for_coords(self, start, end);
424
425 DownloadMapOptions *options = vik_routing_web_engine_get_download_options(self);
426
427 gchar *format = vik_routing_engine_get_format ( self );
428 gboolean ret = a_babel_convert_from_url ( vtl, uri, format, NULL, NULL, options );
429
430 g_free(uri);
431
432 return ret;
433}
434
435static gchar *
436vik_routing_web_engine_get_cmd_from_directions ( VikRoutingEngine *self, const gchar *start, const gchar *end )
437{
438 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), NULL);
439
440 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
441
442 g_return_val_if_fail ( priv->url_base != NULL, NULL);
443 g_return_val_if_fail ( priv->url_start_dir_fmt != NULL, NULL);
444 g_return_val_if_fail ( priv->url_stop_dir_fmt != NULL, NULL);
445
446 gchar *from_quoted, *to_quoted;
447 gchar **from_split, **to_split;
448 from_quoted = g_shell_quote ( start );
449 to_quoted = g_shell_quote ( end );
450
451 from_split = g_strsplit( from_quoted, " ", 0);
452 to_split = g_strsplit( to_quoted, " ", 0);
453
454 from_quoted = g_strjoinv( "%20", from_split);
455 to_quoted = g_strjoinv( "%20", to_split);
456
457 gchar *url_fmt = g_strconcat ( priv->url_base, priv->url_start_dir_fmt, priv->url_stop_dir_fmt, NULL );
458 gchar *url = g_strdup_printf ( url_fmt, from_quoted, to_quoted );
459
460 g_free ( url_fmt );
461
462 g_free(from_quoted);
463 g_free(to_quoted);
464 g_strfreev(from_split);
465 g_strfreev(to_split);
466
467 return url;
468}
469
470static gboolean
471vik_routing_web_engine_supports_direction ( VikRoutingEngine *self )
472{
473 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
474
475 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
476
477 return (priv->url_start_dir_fmt) != NULL;
478}
479
480struct _append_ctx {
481 VikRoutingWebEnginePrivate *priv;
482 gchar **urlParts;
483 int nb;
484};
485
486static void
487_append_stringified_coords ( gpointer data, gpointer user_data )
488{
489 VikTrackpoint *vtp = (VikTrackpoint*)data;
490 struct _append_ctx *ctx = (struct _append_ctx*)user_data;
491
492 /* Stringify coordinate */
493 struct LatLon position;
494 vik_coord_to_latlon ( &(vtp->coord), &position );
495 gchar *string = substitute_latlon ( ctx->priv->url_via_ll_fmt, position );
496
497 /* Append */
498 ctx->urlParts[ctx->nb] = string;
499 ctx->nb++;
500}
501
502static gchar *
503vik_routing_web_engine_get_url_for_track ( VikRoutingEngine *self, VikTrack *vt )
504{
505 gchar **urlParts;
506 gchar *url;
507
508 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
509
510 g_return_val_if_fail ( priv->url_base != NULL, NULL );
511 g_return_val_if_fail ( priv->url_start_ll_fmt != NULL, NULL );
512 g_return_val_if_fail ( priv->url_stop_ll_fmt != NULL, NULL );
513 g_return_val_if_fail ( priv->url_via_ll_fmt != NULL, NULL );
514
515 /* Init temporary storage */
516 gsize len = 1 + g_list_length ( vt->trackpoints ) + 1; /* base + trackpoints + NULL */
517 urlParts = g_malloc ( sizeof(gchar*)*len );
518 urlParts[0] = g_strdup ( priv->url_base );
519 urlParts[len-1] = NULL;
520
521 struct _append_ctx ctx;
522 ctx.priv = priv;
523 ctx.urlParts = urlParts;
524 ctx.nb = 1; /* First cell available, previous used for base URL */
525
526 /* Append all trackpoints to URL */
527 g_list_foreach ( vt->trackpoints, _append_stringified_coords, &ctx );
528
529 /* Override first and last positions with associated formats */
530 struct LatLon position;
531 VikTrackpoint *vtp;
532 g_free ( urlParts[1] );
533 vtp = g_list_first ( vt->trackpoints )->data;
534 vik_coord_to_latlon ( &(vtp->coord ), &position );
535 urlParts[1] = substitute_latlon ( priv->url_start_ll_fmt, position );
536 g_free ( urlParts[len-2] );
537 vtp = g_list_last ( vt->trackpoints )->data;
538 vik_coord_to_latlon ( &(vtp->coord), &position );
539 urlParts[len-2] = substitute_latlon ( priv->url_stop_ll_fmt, position );
540
541 /* Concat */
542 url = g_strjoinv ( NULL, urlParts );
543 g_debug ( "%s: %s", __FUNCTION__, url );
544
545 /* Free */
546 g_strfreev ( urlParts );
547
548 return url;
549}
550
551static gboolean
552vik_routing_web_engine_refine ( VikRoutingEngine *self, VikTrwLayer *vtl, VikTrack *vt )
553{
554 /* Compute URL */
555 gchar *uri = vik_routing_web_engine_get_url_for_track ( self, vt );
556
557 /* Download data */
558 DownloadMapOptions *options = vik_routing_web_engine_get_download_options ( self );
559
560 /* Convert and insert data in model */
561 gchar *format = vik_routing_engine_get_format ( self );
562 gboolean ret = a_babel_convert_from_url ( vtl, uri, format, NULL, NULL, options );
563
564 g_free(uri);
565
566 return ret;
567}
568
569static gboolean
570vik_routing_web_engine_supports_refine ( VikRoutingEngine *self )
571{
572 g_return_val_if_fail ( VIK_IS_ROUTING_WEB_ENGINE (self), FALSE);
573
574 VikRoutingWebEnginePrivate *priv = VIK_ROUTING_WEB_ENGINE_PRIVATE ( self );
575
576 return priv->url_via_ll_fmt != NULL;
577}