1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3
* viking -- GPS Data and Topo Analyzer, Explorer, and Manager
5
* Copyright (C) 2013-2015, Rob Norris <rw_norris@hotmail.com>
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.
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.
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
27
#include "vikwebtool_datasource.h"
32
#include <glib/gi18n.h>
39
static GObjectClass *parent_class;
40
static GHashTable *last_user_strings = NULL;
42
static void webtool_datasource_finalize ( GObject *gob );
44
static gchar *webtool_datasource_get_url ( VikWebtool *self, VikWindow *vw );
46
static gboolean webtool_needs_user_string ( VikWebtool *self );
48
typedef struct _VikWebtoolDatasourcePrivate VikWebtoolDatasourcePrivate;
50
struct _VikWebtoolDatasourcePrivate
53
gchar *url_format_code;
55
gchar *babel_filter_args;
60
#define WEBTOOL_DATASOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
61
VIK_WEBTOOL_DATASOURCE_TYPE, \
62
VikWebtoolDatasourcePrivate))
64
G_DEFINE_TYPE (VikWebtoolDatasource, vik_webtool_datasource, VIK_WEBTOOL_TYPE)
72
PROP_BABEL_FILTER_ARGS,
76
static void webtool_datasource_set_property (GObject *object,
81
VikWebtoolDatasource *self = VIK_WEBTOOL_DATASOURCE ( object );
82
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
84
switch ( property_id ) {
88
priv->url = g_value_dup_string ( value );
89
g_debug ( "VikWebtoolDatasource.url: %s", priv->url );
92
case PROP_URL_FORMAT_CODE:
93
g_free ( priv->url_format_code );
94
priv->url_format_code = g_value_dup_string ( value );
95
g_debug ( "VikWebtoolDatasource.url_format_code: %s", priv->url_format_code );
99
g_free ( priv->file_type );
100
priv->file_type = g_value_dup_string ( value );
101
g_debug ( "VikWebtoolDatasource.file_type: %s", priv->url_format_code );
104
case PROP_BABEL_FILTER_ARGS:
105
g_free ( priv->babel_filter_args );
106
priv->babel_filter_args = g_value_dup_string ( value );
107
g_debug ( "VikWebtoolDatasource.babel_filter_args: %s", priv->babel_filter_args );
110
case PROP_INPUT_LABEL:
111
g_free ( priv->input_label );
112
priv->input_label = g_value_dup_string ( value );
113
g_debug ( "VikWebtoolDatasource.input_label: %s", priv->input_label );
117
/* We don't have any other property... */
118
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, property_id, pspec );
123
static void webtool_datasource_get_property (GObject *object,
128
VikWebtoolDatasource *self = VIK_WEBTOOL_DATASOURCE ( object );
129
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
131
switch ( property_id ) {
133
case PROP_URL: g_value_set_string ( value, priv->url ); break;
134
case PROP_URL_FORMAT_CODE: g_value_set_string ( value, priv->url_format_code ); break;
135
case PROP_FILE_TYPE: g_value_set_string ( value, priv->url ); break;
136
case PROP_BABEL_FILTER_ARGS: g_value_set_string ( value, priv->babel_filter_args ); break;
137
case PROP_INPUT_LABEL: g_value_set_string ( value, priv->input_label ); break;
140
/* We don't have any other property... */
141
G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, property_id, pspec );
150
GtkWidget *user_string;
154
static void ensure_last_user_strings_hash() {
155
if ( last_user_strings == NULL ) {
156
last_user_strings = g_hash_table_new_full ( g_str_hash,
164
static gchar *get_last_user_string ( const datasource_t *source ) {
165
ensure_last_user_strings_hash();
166
gchar *label = vik_ext_tool_get_label ( source->self );
167
gchar *last_str = g_hash_table_lookup ( last_user_strings, label );
173
static void set_last_user_string ( const datasource_t *source, const gchar *s ) {
174
ensure_last_user_strings_hash();
175
g_hash_table_insert ( last_user_strings,
176
vik_ext_tool_get_label ( source->self ),
180
static gpointer datasource_init ( acq_vik_t *avt )
182
datasource_t *data = g_malloc(sizeof(*data));
183
data->self = avt->userdata;
185
data->vvp = avt->vvp;
186
data->user_string = NULL;
190
static void datasource_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
192
datasource_t *widgets = (datasource_t *)user_data;
193
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( widgets->self );
194
GtkWidget *user_string_label;
195
gchar *label = g_strdup_printf( "%s:", priv->input_label );
196
user_string_label = gtk_label_new ( label );
197
widgets->user_string = gtk_entry_new ( );
199
gchar *last_str = get_last_user_string ( widgets );
201
gtk_entry_set_text( GTK_ENTRY( widgets->user_string ), last_str );
203
// 'ok' when press return in the entry
204
g_signal_connect_swapped (widgets->user_string, "activate", G_CALLBACK(a_dialog_response_accept), dialog);
206
/* Packing all widgets */
207
GtkBox *box = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog)));
208
gtk_box_pack_start ( box, user_string_label, FALSE, FALSE, 5 );
209
gtk_box_pack_start ( box, widgets->user_string, FALSE, FALSE, 5 );
210
gtk_widget_show_all ( dialog );
211
gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
212
// NB presently the focus is overridden later on by the acquire.c code.
213
gtk_widget_grab_focus ( widgets->user_string );
220
static void datasource_get_process_options ( gpointer user_data, ProcessOptions *po, DownloadFileOptions *options, const gchar *notused1, const gchar *notused2 )
222
datasource_t *data = (datasource_t*) user_data;
224
VikWebtool *vwd = VIK_WEBTOOL ( data->self );
225
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( data->self );
227
if ( webtool_needs_user_string ( vwd ) ) {
228
priv->user_string = g_strdup ( gtk_entry_get_text ( GTK_ENTRY ( data->user_string ) ) );
230
if ( priv->user_string[0] != '\0' ) {
231
set_last_user_string ( data, priv->user_string );
235
gchar *url = vik_webtool_get_url ( vwd, data->vw );
236
g_debug ("%s: %s", __FUNCTION__, url );
238
po->url = g_strdup ( url );
240
// Only use first section of the file_type string
241
// One can't use values like 'kml -x transform,rte=wpt' in order to do fancy things
242
// since it won't be in the right order for the overall GPSBabel command
243
// So prevent any potentially dangerous behaviour
244
gchar **parts = NULL;
245
if ( priv->file_type )
246
parts = g_strsplit ( priv->file_type, " ", 0);
248
po->input_file_type = g_strdup ( parts[0] );
250
po->input_file_type = NULL;
251
g_strfreev ( parts );
254
po->babel_filters = priv->babel_filter_args;
257
static void cleanup ( gpointer data )
262
static void webtool_datasource_open ( VikExtTool *self, VikWindow *vw )
264
gboolean search = webtool_needs_user_string ( VIK_WEBTOOL ( self ) );
266
// Use VikDataSourceInterface to give thready goodness controls of downloading stuff (i.e. can cancel the request)
268
// Can now create a 'VikDataSourceInterface' on the fly...
269
VikDataSourceInterface *vik_datasource_interface = g_malloc(sizeof(VikDataSourceInterface));
271
// An 'easy' way of assigning values
272
VikDataSourceInterface data = {
273
vik_ext_tool_get_label (self),
274
vik_ext_tool_get_label (self),
275
VIK_DATASOURCE_ADDTOLAYER,
276
VIK_DATASOURCE_INPUTTYPE_NONE,
277
FALSE, // Maintain current view - rather than setting it to the acquired points
280
(VikDataSourceInitFunc) datasource_init,
281
(VikDataSourceCheckExistenceFunc) NULL,
282
(VikDataSourceAddSetupWidgetsFunc) (search ? datasource_add_setup_widgets : NULL),
283
(VikDataSourceGetProcessOptionsFunc) datasource_get_process_options,
284
(VikDataSourceProcessFunc) a_babel_convert_from,
285
(VikDataSourceProgressFunc) NULL,
286
(VikDataSourceAddProgressWidgetsFunc) NULL,
287
(VikDataSourceCleanupFunc) cleanup,
288
(VikDataSourceOffFunc) NULL,
295
memcpy ( vik_datasource_interface, &data, sizeof(VikDataSourceInterface) );
297
a_acquire ( vw, vik_window_layers_panel(vw), vik_window_viewport (vw), data.mode, vik_datasource_interface, self, cleanup );
300
static void vik_webtool_datasource_class_init ( VikWebtoolDatasourceClass *klass )
302
GObjectClass *gobject_class;
303
VikWebtoolClass *base_class;
306
gobject_class = G_OBJECT_CLASS (klass);
308
gobject_class->finalize = webtool_datasource_finalize;
309
gobject_class->set_property = webtool_datasource_set_property;
310
gobject_class->get_property = webtool_datasource_get_property;
312
pspec = g_param_spec_string ("url",
314
"Set the template URL",
315
VIKING_URL /* default value */,
316
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
317
g_object_class_install_property (gobject_class,
321
pspec = g_param_spec_string ("url_format_code",
322
"Template URL Format Code",
323
"Set the template URL format code",
324
"LRBT", // default value
325
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
326
g_object_class_install_property (gobject_class,
327
PROP_URL_FORMAT_CODE,
330
pspec = g_param_spec_string ("file_type",
331
"The file type expected",
333
NULL, // default value ~ equates to internal GPX reading
334
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
335
g_object_class_install_property (gobject_class,
339
pspec = g_param_spec_string ("babel_filter_args",
340
"The command line filter options to pass to gpsbabel",
341
"Set the command line filter options for gpsbabel",
342
NULL, // default value
343
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
344
g_object_class_install_property (gobject_class,
345
PROP_BABEL_FILTER_ARGS,
348
pspec = g_param_spec_string ("input_label",
349
"The label for the user input box if input is required.",
350
"Set the label to be shown next to the user input box if an input term is required",
352
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
353
g_object_class_install_property (gobject_class,
357
parent_class = g_type_class_peek_parent (klass);
359
base_class = VIK_WEBTOOL_CLASS ( klass );
360
base_class->get_url = webtool_datasource_get_url;
362
// Override default open function here:
363
VikExtToolClass *ext_tool_class = VIK_EXT_TOOL_CLASS ( klass );
364
ext_tool_class->open = webtool_datasource_open;
366
g_type_class_add_private (klass, sizeof (VikWebtoolDatasourcePrivate));
369
VikWebtoolDatasource *vik_webtool_datasource_new ()
371
return VIK_WEBTOOL_DATASOURCE ( g_object_new ( VIK_WEBTOOL_DATASOURCE_TYPE, NULL ) );
374
VikWebtoolDatasource *vik_webtool_datasource_new_with_members ( const gchar *label,
376
const gchar *url_format_code,
377
const gchar *file_type,
378
const gchar *babel_filter_args,
379
const gchar *input_label )
381
VikWebtoolDatasource *result = VIK_WEBTOOL_DATASOURCE ( g_object_new ( VIK_WEBTOOL_DATASOURCE_TYPE,
384
"url_format_code", url_format_code,
385
"file_type", file_type,
386
"babel_filter_args", babel_filter_args,
387
"input_label", input_label,
393
static void vik_webtool_datasource_init ( VikWebtoolDatasource *self )
395
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE (self);
397
priv->url_format_code = NULL;
398
priv->file_type = NULL;
399
priv->babel_filter_args = NULL;
400
priv->input_label = NULL;
401
priv->user_string = NULL;
404
static void webtool_datasource_finalize ( GObject *gob )
406
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( gob );
407
g_free ( priv->url ); priv->url = NULL;
408
g_free ( priv->url_format_code ); priv->url_format_code = NULL;
409
g_free ( priv->file_type ); priv->file_type = NULL;
410
g_free ( priv->babel_filter_args ); priv->babel_filter_args = NULL;
411
g_free ( priv->input_label ); priv->input_label = NULL;
412
g_free ( priv->user_string); priv->user_string = NULL;
413
G_OBJECT_CLASS(parent_class)->finalize(gob);
416
#define MAX_NUMBER_CODES 7
419
* Calculate individual elements (similarly to the VikWebtool Bounds & Center) for *all* potential values
420
* Then only values specified by the URL format are used in parameterizing the URL
422
static gchar *webtool_datasource_get_url ( VikWebtool *self, VikWindow *vw )
424
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
425
VikViewport *viewport = vik_window_viewport ( vw );
427
// Get top left and bottom right lat/lon pairs from the viewport
428
gdouble min_lat, max_lat, min_lon, max_lon;
429
gchar sminlon[G_ASCII_DTOSTR_BUF_SIZE];
430
gchar smaxlon[G_ASCII_DTOSTR_BUF_SIZE];
431
gchar sminlat[G_ASCII_DTOSTR_BUF_SIZE];
432
gchar smaxlat[G_ASCII_DTOSTR_BUF_SIZE];
433
vik_viewport_get_min_max_lat_lon ( viewport, &min_lat, &max_lat, &min_lon, &max_lon );
435
// Cannot simply use g_strdup_printf and gdouble due to locale.
436
// As we compute an URL, we have to think in C locale.
437
g_ascii_dtostr (sminlon, G_ASCII_DTOSTR_BUF_SIZE, min_lon);
438
g_ascii_dtostr (smaxlon, G_ASCII_DTOSTR_BUF_SIZE, max_lon);
439
g_ascii_dtostr (sminlat, G_ASCII_DTOSTR_BUF_SIZE, min_lat);
440
g_ascii_dtostr (smaxlat, G_ASCII_DTOSTR_BUF_SIZE, max_lat);
443
const VikCoord *coord = vik_viewport_get_center ( viewport );
445
vik_coord_to_latlon ( coord, &ll );
447
gchar scenterlat[G_ASCII_DTOSTR_BUF_SIZE];
448
gchar scenterlon[G_ASCII_DTOSTR_BUF_SIZE];
449
g_ascii_dtostr (scenterlat, G_ASCII_DTOSTR_BUF_SIZE, ll.lat);
450
g_ascii_dtostr (scenterlon, G_ASCII_DTOSTR_BUF_SIZE, ll.lon);
452
guint8 zoom = 17; // A zoomed in default
453
// zoom - ideally x & y factors need to be the same otherwise use the default
454
if ( vik_viewport_get_xmpp ( viewport ) == vik_viewport_get_ympp ( viewport ) )
455
zoom = map_utils_mpp_to_zoom_level ( vik_viewport_get_zoom ( viewport ) );
457
gchar szoom[G_ASCII_DTOSTR_BUF_SIZE];
458
g_snprintf ( szoom, G_ASCII_DTOSTR_BUF_SIZE, "%d", zoom );
461
if ( priv->url_format_code )
462
len = strlen ( priv->url_format_code );
463
if ( len > MAX_NUMBER_CODES )
464
len = MAX_NUMBER_CODES;
466
gchar* values[MAX_NUMBER_CODES];
468
for ( i = 0; i < MAX_NUMBER_CODES; i++ ) {
472
for ( i = 0; i < len; i++ ) {
473
switch ( g_ascii_toupper ( priv->url_format_code[i] ) ) {
474
case 'L': values[i] = g_strdup ( sminlon ); break;
475
case 'R': values[i] = g_strdup ( smaxlon ); break;
476
case 'B': values[i] = g_strdup ( sminlat ); break;
477
case 'T': values[i] = g_strdup ( smaxlat ); break;
478
case 'A': values[i] = g_strdup ( scenterlat ); break;
479
case 'O': values[i] = g_strdup ( scenterlon ); break;
480
case 'Z': values[i] = g_strdup ( szoom ); break;
481
case 'S': values[i] = g_strdup ( priv->user_string ); break;
486
gchar *url = g_strdup_printf ( priv->url, values[0], values[1], values[2], values[3], values[4], values[5], values[6] );
488
for ( i = 0; i < MAX_NUMBER_CODES; i++ ) {
489
g_free ( values[i] );
495
// NB Only works for ascii strings
496
char* strcasestr2(const char *dst, const char *src)
504
int len = strlen(src) - 1;
505
char sc = tolower(src[0]);
506
for(char dc = *dst; (dc = *dst); dst++) {
508
if(sc == dc && (len == 0 || !strncasecmp(dst+1, src+1, len)))
516
* Returns true if the URL format contains 'S' -- that is, a search term entry
517
* box needs to be displayed
519
static gboolean webtool_needs_user_string ( VikWebtool *self )
521
VikWebtoolDatasourcePrivate *priv = WEBTOOL_DATASOURCE_GET_PRIVATE ( self );
522
// For some reason (my) Windows build gets built with -D_GNU_SOURCE
523
#if (_GNU_SOURCE && !WINDOWS)
524
return (strcasestr(priv->url_format_code, "S") != NULL);
526
return (strcasestr2(priv->url_format_code, "S") != NULL);