]> git.street.me.uk Git - andy/viking.git/blame - src/vikwebtool_datasource.c
Add a new webtool datasource to allow acquiring data from URLs that return a file.
[andy/viking.git] / src / vikwebtool_datasource.c
CommitLineData
82993cc7
RN
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
38static GObjectClass *parent_class;
39
40static void webtool_datasource_finalize ( GObject *gob );
41
42static gchar *webtool_datasource_get_url ( VikWebtool *self, VikWindow *vw );
43
44typedef struct _VikWebtoolDatasourcePrivate VikWebtoolDatasourcePrivate;
45
46struct _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
57G_DEFINE_TYPE (VikWebtoolDatasource, vik_webtool_datasource, VIK_WEBTOOL_TYPE)
58
59enum
60{
61 PROP_0,
62 PROP_URL,
63 PROP_URL_FORMAT_CODE,
64 PROP_FILE_TYPE,
65};
66
67static 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
101static 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
122typedef struct {
123 VikExtTool *self;
124 VikWindow *vw;
125 VikViewport *vvp;
126} datasource_t;
127
128static 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
137static 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
168static 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
177static void cleanup ( gpointer data )
178{
179 g_free ( data );
180}
181
182static 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
218static 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
269VikWebtoolDatasource *vik_webtool_datasource_new ()
270{
271 return VIK_WEBTOOL_DATASOURCE ( g_object_new ( VIK_WEBTOOL_DATASOURCE_TYPE, NULL ) );
272}
273
274VikWebtoolDatasource *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
289static 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
297static 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 */
312static 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}