]> git.street.me.uk Git - andy/viking.git/blob - src/vikwebtool_datasource.c
Add OSRM routing engine
[andy/viking.git] / src / vikwebtool_datasource.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4  *
5  * Copyright (C) 2013, Rob Norris <rw_norris@hotmail.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
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "vikwebtool_datasource.h"
28
29 #include <string.h>
30
31 #include <glib.h>
32 #include <glib/gi18n.h>
33
34 #include "globals.h"
35 #include "acquire.h"
36 #include "util.h"
37
38 static GObjectClass *parent_class;
39
40 static void webtool_datasource_finalize ( GObject *gob );
41
42 static gchar *webtool_datasource_get_url ( VikWebtool *self, VikWindow *vw );
43
44 typedef struct _VikWebtoolDatasourcePrivate VikWebtoolDatasourcePrivate;
45
46 struct _VikWebtoolDatasourcePrivate
47 {
48         gchar *url;
49         gchar *url_format_code;
50         gchar *file_type;
51 };
52
53 #define WEBTOOL_DATASOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
54                                            VIK_WEBTOOL_DATASOURCE_TYPE,      \
55                                            VikWebtoolDatasourcePrivate))
56
57 G_DEFINE_TYPE (VikWebtoolDatasource, vik_webtool_datasource, VIK_WEBTOOL_TYPE)
58
59 enum
60 {
61         PROP_0,
62         PROP_URL,
63         PROP_URL_FORMAT_CODE,
64         PROP_FILE_TYPE,
65 };
66
67 static void webtool_datasource_set_property (GObject      *object,
68                                              guint         property_id,
69                                              const GValue *value,
70                                              GParamSpec   *pspec)
71 {
72         VikWebtoolDatasource *self = VIK_WEBTOOL_DATASOURCE ( object );
73         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
74
75         switch ( property_id ) {
76         case PROP_URL:
77                 g_free ( priv->url );
78                 priv->url = g_value_dup_string ( value );
79                 g_debug ( "VikWebtoolDatasource.url: %s", priv->url );
80                 break;
81
82         case PROP_URL_FORMAT_CODE:
83                 g_free ( priv->url_format_code );
84                 priv->url_format_code = g_value_dup_string ( value );
85                 g_debug ( "VikWebtoolDatasource.url_format_code: %s", priv->url_format_code );
86                 break;
87
88         case PROP_FILE_TYPE:
89                 g_free ( priv->file_type );
90                 priv->file_type = g_value_dup_string ( value );
91                 g_debug ( "VikWebtoolDatasource.file_type: %s", priv->url_format_code );
92                 break;
93
94         default:
95                 /* We don't have any other property... */
96                 G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, property_id, pspec );
97                 break;
98     }
99 }
100
101 static void webtool_datasource_get_property (GObject    *object,
102                                              guint       property_id,
103                                              GValue     *value,
104                                              GParamSpec *pspec)
105 {
106         VikWebtoolDatasource *self = VIK_WEBTOOL_DATASOURCE ( object );
107         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
108
109         switch ( property_id ) {
110
111         case PROP_URL:              g_value_set_string ( value, priv->url ); break;
112         case PROP_URL_FORMAT_CODE:      g_value_set_string ( value, priv->url_format_code ); break;
113         case PROP_FILE_TYPE:        g_value_set_string ( value, priv->url ); break;
114
115         default:
116                 /* We don't have any other property... */
117                 G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, property_id, pspec );
118                 break;
119     }
120 }
121
122 typedef struct {
123         VikExtTool *self;
124         VikWindow *vw;
125         VikViewport *vvp;
126 } datasource_t;
127
128 static gpointer datasource_init ( acq_vik_t *avt )
129 {
130         datasource_t *data = g_malloc(sizeof(*data));
131         data->self = avt->userdata;
132         data->vw = avt->vw;
133         data->vvp = avt->vvp;
134         return data;
135 }
136
137 static void datasource_get_cmd_string ( gpointer user_data, gchar **cmd, gchar **extra, DownloadMapOptions *options )
138 {
139         datasource_t *data = (datasource_t*) user_data;
140
141         VikWebtool *vwd = VIK_WEBTOOL ( data->self );
142         gchar *url = vik_webtool_get_url ( vwd, data->vw );
143         g_debug ("%s: %s", __FUNCTION__, url );
144
145         // if url starts with 'http://' then only the copy the part after it - as the download code always inserts it!
146         if ( !strncmp(url, "http://", 7 ) )
147                 *cmd = g_strndup ( &url[7], strlen (url) );
148         else
149                 *cmd = g_strdup ( url );
150
151         // Only use first section of the file_type string
152         // One can't use values like 'kml -x transform,rte=wpt' in order to do fancy things
153         //  since it won't be in the right order for the overall GPSBabel command
154         // So prevent any potentially dangerous behaviour
155         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( data->self );
156         gchar **parts = NULL;
157         if ( priv->file_type )
158                 parts = g_strsplit ( priv->file_type, " ", 0);
159         if ( parts )
160                 *extra = g_strdup ( parts[0] );
161         else
162                 *extra = NULL;
163         g_strfreev ( parts );
164
165         options = NULL;
166 }
167
168 static gboolean datasource_process ( VikTrwLayer *vtl, const gchar *cmd, const gchar *extra, BabelStatusFunc status_cb, acq_dialog_widgets_t *adw, DownloadMapOptions *options )
169 {
170         //datasource_t *data = (datasource_t *)adw->user_data;
171         // Dependent on the ExtTool / what extra has been set to...
172         // When extra is NULL - then it interprets results as a GPX
173         gboolean result = a_babel_convert_from_url ( vtl, cmd, extra, status_cb, adw, options);
174         return result;
175 }
176
177 static void cleanup ( gpointer data )
178 {
179         g_free ( data );
180 }
181
182 static void webtool_datasource_open ( VikExtTool *self, VikWindow *vw )
183 {
184         // Use VikDataSourceInterface to give thready goodness controls of downloading stuff (i.e. can cancel the request)
185
186         // Can now create a 'VikDataSourceInterface' on the fly...
187         VikDataSourceInterface *vik_datasource_interface = g_malloc(sizeof(VikDataSourceInterface));
188
189         // An 'easy' way of assigning values
190         VikDataSourceInterface data = {
191                 vik_ext_tool_get_label (self),
192                 vik_ext_tool_get_label (self),
193                 VIK_DATASOURCE_ADDTOLAYER,
194                 VIK_DATASOURCE_INPUTTYPE_NONE,
195                 FALSE, // Maintain current view - rather than setting it to the acquired points
196                 TRUE,
197                 TRUE,
198                 (VikDataSourceInitFunc)               datasource_init,
199                 (VikDataSourceCheckExistenceFunc)     NULL,
200                 (VikDataSourceAddSetupWidgetsFunc)    NULL,
201                 (VikDataSourceGetCmdStringFunc)       datasource_get_cmd_string,
202                 (VikDataSourceProcessFunc)            datasource_process,
203                 (VikDataSourceProgressFunc)           NULL,
204                 (VikDataSourceAddProgressWidgetsFunc) NULL,
205                 (VikDataSourceCleanupFunc)            cleanup,
206                 (VikDataSourceOffFunc)                NULL,
207                 NULL,
208                 0,
209                 NULL,
210                 NULL,
211                 0
212         };
213         memcpy ( vik_datasource_interface, &data, sizeof(VikDataSourceInterface) );
214
215         a_acquire ( vw, vik_window_layers_panel(vw), vik_window_viewport (vw), vik_datasource_interface, self, cleanup );
216 }
217
218 static void vik_webtool_datasource_class_init ( VikWebtoolDatasourceClass *klass )
219 {
220         GObjectClass *gobject_class;
221         VikWebtoolClass *base_class;
222         GParamSpec *pspec;
223
224         gobject_class = G_OBJECT_CLASS (klass);
225
226         gobject_class->finalize = webtool_datasource_finalize;
227         gobject_class->set_property = webtool_datasource_set_property;
228         gobject_class->get_property = webtool_datasource_get_property;
229
230         pspec = g_param_spec_string ("url",
231                                      "Template URL",
232                                      "Set the template URL",
233                                      VIKING_URL /* default value */,
234                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
235         g_object_class_install_property (gobject_class,
236                                          PROP_URL,
237                                          pspec);
238
239         pspec = g_param_spec_string ("url_format_code",
240                                      "Template URL Format Code",
241                                      "Set the template URL format code",
242                                      "LRBT", // default value
243                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
244         g_object_class_install_property (gobject_class,
245                                          PROP_URL_FORMAT_CODE,
246                                          pspec);
247
248         pspec = g_param_spec_string ("file_type",
249                                      "The file type expected",
250                                      "Set the file type",
251                                      NULL, // default value ~ equates to internal GPX reading
252                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
253         g_object_class_install_property (gobject_class,
254                                          PROP_FILE_TYPE,
255                                          pspec);
256
257         parent_class = g_type_class_peek_parent (klass);
258
259         base_class = VIK_WEBTOOL_CLASS ( klass );
260         base_class->get_url = webtool_datasource_get_url;
261
262         // Override default open function here:
263         VikExtToolClass *ext_tool_class = VIK_EXT_TOOL_CLASS ( klass );
264         ext_tool_class->open = webtool_datasource_open;
265
266         g_type_class_add_private (klass, sizeof (VikWebtoolDatasourcePrivate));
267 }
268
269 VikWebtoolDatasource *vik_webtool_datasource_new ()
270 {
271         return VIK_WEBTOOL_DATASOURCE ( g_object_new ( VIK_WEBTOOL_DATASOURCE_TYPE, NULL ) );
272 }
273
274 VikWebtoolDatasource *vik_webtool_datasource_new_with_members ( const gchar *label,
275                                                                 const gchar *url,
276                                                                 const gchar *url_format_code,
277                                                                 const gchar *file_type )
278 {
279         VikWebtoolDatasource *result = VIK_WEBTOOL_DATASOURCE ( g_object_new ( VIK_WEBTOOL_DATASOURCE_TYPE,
280                                                                 "label", label,
281                                                                 "url", url,
282                                                                 "url_format_code", url_format_code,
283                                                                 "file_type", file_type,
284                                                                 NULL ) );
285
286         return result;
287 }
288
289 static void vik_webtool_datasource_init ( VikWebtoolDatasource *self )
290 {
291         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE (self);
292         priv->url = NULL;
293         priv->url_format_code = NULL;
294         priv->file_type = NULL;
295 }
296
297 static void webtool_datasource_finalize ( GObject *gob )
298 {
299         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( gob );
300         g_free ( priv->url ); priv->url = NULL;
301         g_free ( priv->url_format_code ); priv->url_format_code = NULL;
302         g_free ( priv->file_type ); priv->file_type = NULL;
303         G_OBJECT_CLASS(parent_class)->finalize(gob);
304 }
305
306 #define MAX_NUMBER_CODES 7
307
308 /**
309  * Calculate individual elements (similarly to the VikWebtool Bounds & Center) for *all* potential values
310  * Then only values specified by the URL format are used in parameterizing the URL
311  */
312 static gchar *webtool_datasource_get_url ( VikWebtool *self, VikWindow *vw )
313 {
314         VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
315         VikViewport *viewport = vik_window_viewport ( vw );
316
317         // Get top left and bottom right lat/lon pairs from the viewport
318         gdouble min_lat, max_lat, min_lon, max_lon;
319         gchar sminlon[G_ASCII_DTOSTR_BUF_SIZE];
320         gchar smaxlon[G_ASCII_DTOSTR_BUF_SIZE];
321         gchar sminlat[G_ASCII_DTOSTR_BUF_SIZE];
322         gchar smaxlat[G_ASCII_DTOSTR_BUF_SIZE];
323         vik_viewport_get_min_max_lat_lon ( viewport, &min_lat, &max_lat, &min_lon, &max_lon );
324
325         // Cannot simply use g_strdup_printf and gdouble due to locale.
326         // As we compute an URL, we have to think in C locale.
327         g_ascii_dtostr (sminlon, G_ASCII_DTOSTR_BUF_SIZE, min_lon);
328         g_ascii_dtostr (smaxlon, G_ASCII_DTOSTR_BUF_SIZE, max_lon);
329         g_ascii_dtostr (sminlat, G_ASCII_DTOSTR_BUF_SIZE, min_lat);
330         g_ascii_dtostr (smaxlat, G_ASCII_DTOSTR_BUF_SIZE, max_lat);
331
332         // Center values
333         const VikCoord *coord = vik_viewport_get_center ( viewport );
334         struct LatLon ll;
335         vik_coord_to_latlon ( coord, &ll );
336
337         gchar scenterlat[G_ASCII_DTOSTR_BUF_SIZE];
338         gchar scenterlon[G_ASCII_DTOSTR_BUF_SIZE];
339         g_ascii_dtostr (scenterlat, G_ASCII_DTOSTR_BUF_SIZE, ll.lat);
340         g_ascii_dtostr (scenterlon, G_ASCII_DTOSTR_BUF_SIZE, ll.lon);
341
342         guint8 zoom = 17; // A zoomed in default
343         // zoom - ideally x & y factors need to be the same otherwise use the default
344         if ( vik_viewport_get_xmpp ( viewport ) == vik_viewport_get_ympp ( viewport ) )
345                 zoom = mpp_to_zoom ( vik_viewport_get_zoom ( viewport ) );
346
347         gchar szoom[G_ASCII_DTOSTR_BUF_SIZE];
348         g_snprintf ( szoom, G_ASCII_DTOSTR_BUF_SIZE, "%d", zoom );
349
350         gint len = 0;
351         if ( priv->url_format_code )
352                 len = strlen ( priv->url_format_code );
353         if ( len > MAX_NUMBER_CODES )
354                 len = MAX_NUMBER_CODES;
355
356         gchar* values[MAX_NUMBER_CODES];
357         int i;
358         for ( i = 0; i < MAX_NUMBER_CODES; i++ ) {
359                 values[i] = g_strdup ( "" );
360         }
361
362         for ( i = 0; i < len; i++ ) {
363                 switch ( g_ascii_toupper ( priv->url_format_code[i] ) ) {
364                 case 'L': values[i] = g_strdup ( sminlon ); break;
365                 case 'R': values[i] = g_strdup ( smaxlon ); break;
366                 case 'B': values[i] = g_strdup ( sminlat ); break;
367                 case 'T': values[i] = g_strdup ( smaxlat ); break;
368                 case 'A': values[i] = g_strdup ( scenterlat ); break;
369                 case 'O': values[i] = g_strdup ( scenterlon ); break;
370                 case 'Z': values[i] = g_strdup ( szoom ); break;
371                 default: break;
372                 }
373         }
374
375         gchar *url = g_strdup_printf ( priv->url, values[0], values[1], values[2], values[3], values[4], values[5], values[6] );
376
377         for ( i = 0; i < MAX_NUMBER_CODES; i++ ) {
378                 g_free ( values[i] );
379         }
380         
381         return url;
382 }