]> git.street.me.uk Git - andy/viking.git/blame - src/datasource_osm_my_traces.c
[DOC] Update the TODO file to say that it's old and superseded by the wiki.
[andy/viking.git] / src / datasource_osm_my_traces.c
CommitLineData
3cc57413
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) 2012, 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#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25#include <string.h>
26#include <limits.h>
27
28#include <glib/gprintf.h>
29#include <glib/gi18n.h>
30#include <glib/gstdio.h>
31
32#include <expat.h>
33
34#include "viking.h"
35#include "gpx.h"
36#include "acquire.h"
37#include "osm-traces.h"
38#include "preferences.h"
39#include "curl_download.h"
40#include "datasource_gps.h"
6ef14d6b 41#include "bbox.h"
3cc57413
RN
42
43/**
44 * See http://wiki.openstreetmap.org/wiki/API_v0.6#GPS_Traces
45 */
46#define DS_OSM_TRACES_GPX_URL_FMT "api.openstreetmap.org/api/0.6/gpx/%d/data"
47#define DS_OSM_TRACES_GPX_FILES "api.openstreetmap.org/api/0.6/user/gpx_files"
48
49typedef struct {
50 GtkWidget *user_entry;
51 GtkWidget *password_entry;
52 // NB actual user and password values are stored in oms-traces.c
6ef14d6b 53 VikViewport *vvp;
3cc57413
RN
54} datasource_osm_my_traces_t;
55
56static gpointer datasource_osm_my_traces_init( );
57static void datasource_osm_my_traces_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
58static void datasource_osm_my_traces_get_cmd_string ( gpointer user_data, gchar **args, gchar **extra, DownloadMapOptions *options );
59static gboolean datasource_osm_my_traces_process ( VikTrwLayer *vtl, const gchar *cmd, const gchar *extra, BabelStatusFunc status_cb, acq_dialog_widgets_t *adw, DownloadMapOptions *options_unused );
60static void datasource_osm_my_traces_cleanup ( gpointer data );
61
62VikDataSourceInterface vik_datasource_osm_my_traces_interface = {
63 N_("OSM My Traces"),
64 N_("OSM My Traces"),
65 VIK_DATASOURCE_MANUAL_LAYER_MANAGEMENT, // we'll do this ourselves
66 VIK_DATASOURCE_INPUTTYPE_NONE,
67 TRUE,
68 TRUE,
69 FALSE, // Don't use thread method
70 (VikDataSourceInitFunc) datasource_osm_my_traces_init,
71 (VikDataSourceCheckExistenceFunc) NULL,
72 (VikDataSourceAddSetupWidgetsFunc)datasource_osm_my_traces_add_setup_widgets,
73 (VikDataSourceGetCmdStringFunc) datasource_osm_my_traces_get_cmd_string,
74 (VikDataSourceProcessFunc) datasource_osm_my_traces_process,
75 (VikDataSourceProgressFunc) NULL,
76 (VikDataSourceAddProgressWidgetsFunc) NULL,
77 (VikDataSourceCleanupFunc) datasource_osm_my_traces_cleanup,
78 (VikDataSourceOffFunc) NULL,
79
80 NULL,
81 0,
82 NULL,
83 NULL,
84 0
85};
86
87static gpointer datasource_osm_my_traces_init ( )
88{
89 datasource_osm_my_traces_t *data = g_malloc(sizeof(*data));
90 // Reuse GPS functions
91 // Haven't been able to get the thread method to work reliably (or get progress feedback)
92 // So thread version is disabled ATM
93 /*
94 if ( vik_datasource_osm_my_traces_interface.is_thread ) {
95 vik_datasource_osm_my_traces_interface.progress_func = datasource_gps_progress;
96 vik_datasource_osm_my_traces_interface.add_progress_widgets_func = datasource_gps_add_progress_widgets;
97 }
98 */
99 return data;
100}
101
102static void datasource_osm_my_traces_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
103{
104 datasource_osm_my_traces_t *data = (datasource_osm_my_traces_t *)user_data;
105
106 GtkWidget *user_label;
107 GtkWidget *password_label;
108 user_label = gtk_label_new(_("Username:"));
109 data->user_entry = gtk_entry_new();
110
111 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), user_label, FALSE, FALSE, 0 );
112 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), data->user_entry, FALSE, FALSE, 0 );
113 gtk_widget_set_tooltip_markup ( GTK_WIDGET(data->user_entry), _("The email or username used to login to OSM") );
114
115 password_label = gtk_label_new ( _("Password:") );
116 data->password_entry = gtk_entry_new ();
117
118 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), password_label, FALSE, FALSE, 0 );
119 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), data->password_entry, FALSE, FALSE, 0 );
120 gtk_widget_set_tooltip_markup ( GTK_WIDGET(data->password_entry), _("The password used to login to OSM") );
121
122 osm_login_widgets (data->user_entry, data->password_entry);
123 gtk_widget_show_all ( dialog );
6ef14d6b
RN
124
125 /* Keep reference to viewport */
126 data->vvp = vvp;
3cc57413
RN
127}
128
129static void datasource_osm_my_traces_get_cmd_string ( gpointer user_data, gchar **args, gchar **extra, DownloadMapOptions *options )
130{
131 datasource_osm_my_traces_t *data = (datasource_osm_my_traces_t*) user_data;
132
133 /* overwrite authentication info */
134 osm_set_login ( gtk_entry_get_text ( GTK_ENTRY(data->user_entry) ),
135 gtk_entry_get_text ( GTK_ENTRY(data->password_entry) ) );
136
137 // If going to use the values passed back into the process function parameters then these need to be set.
138 // But ATM we aren't
139 *args = NULL;
140 *extra = NULL;
141 options = NULL;
142}
143
144typedef enum {
145 tt_unknown = 0,
146 tt_osm,
147 tt_gpx_file,
148 tt_gpx_file_desc,
149 tt_gpx_file_tag,
150} xtag_type;
151
152typedef struct {
153 xtag_type tag_type; /* enum from above for this tag */
154 const char *tag_name; /* xpath-ish tag name */
155} xtag_mapping;
156
157typedef struct {
158 guint id;
159 gchar *name;
160 gchar *vis;
161 gchar *desc;
162 struct LatLon ll;
6ef14d6b
RN
163 gboolean in_current_view; // Is the track LatLon start within the current viewport
164 // This is useful in deciding whether to download a track or not
3cc57413
RN
165 // ATM Only used for display - may want to convert to a time_t for other usage
166 gchar *timestamp;
167 // user made up tags - not being used yet - would be nice to sort/select on these but display will get complicated
168 // GList *tag_list;
169} gpx_meta_data_t;
170
171static gpx_meta_data_t *new_gpx_meta_data_t()
172{
173 gpx_meta_data_t *ret;
174
175 ret = (gpx_meta_data_t *)g_malloc(sizeof(gpx_meta_data_t));
176 ret->id = 0;
177 ret->name = NULL;
178 ret->vis = NULL;
179 ret->desc = NULL;
180 ret->ll.lat = 0.0;
181 ret->ll.lon = 0.0;
6ef14d6b 182 ret->in_current_view = FALSE;
3cc57413
RN
183 ret->timestamp = NULL;
184
185 return ret;
186}
187
188static void free_gpx_meta_data ( gpx_meta_data_t *data, gpointer userdata )
189{
190 g_free(data->name);
191 g_free(data->vis);
192 g_free(data->desc);
193 g_free(data->timestamp);
194}
195
196static void free_gpx_meta_data_list (GList *list)
197{
198 g_list_foreach (list, (GFunc)free_gpx_meta_data, NULL);
199 g_list_free (list);
200}
201
202static gpx_meta_data_t *copy_gpx_meta_data_t (gpx_meta_data_t *src)
203{
204 gpx_meta_data_t *dest = new_gpx_meta_data_t();
205
206 dest->id = src->id;
207 dest->name = g_strdup(src->name);
208 dest->vis = g_strdup(src->vis);
209 dest->desc = g_strdup(src->desc);
210 dest->ll.lat = src->ll.lat;
211 dest->ll.lon = src->ll.lon;
6ef14d6b 212 dest->in_current_view = src->in_current_view;
3cc57413
RN
213 dest->timestamp = g_strdup(src->timestamp);
214
215 return dest;
216}
217
218typedef struct {
219 //GString *xpath;
220 GString *c_cdata;
221 xtag_type current_tag;
222 gpx_meta_data_t *current_gpx_meta_data;
223 GList *list_of_gpx_meta_data;
224} xml_data;
225
226// Same as the gpx.c function
227static const char *get_attr ( const char **attr, const char *key )
228{
229 while ( *attr ) {
230 if ( strcmp(*attr,key) == 0 )
231 return *(attr + 1);
232 attr += 2;
233 }
234 return NULL;
235}
236
237// ATM don't care about actual path as tags are all unique
238static xtag_mapping xtag_path_map[] = {
239 { tt_osm, "osm" },
240 { tt_gpx_file, "gpx_file" },
241 { tt_gpx_file_desc, "description" },
242 { tt_gpx_file_tag, "tag" },
243};
244
245static xtag_type get_tag ( const char *t )
246{
247 xtag_mapping *tm;
248 for (tm = xtag_path_map; tm->tag_type != 0; tm++)
249 if (0 == strcmp(tm->tag_name, t))
250 return tm->tag_type;
251 return tt_unknown;
252}
253
254static void gpx_meta_data_start ( xml_data *xd, const char *el, const char **attr )
255{
256 const gchar *tmp;
257 gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
258 buf[0] = '\0';
259
260 // Don't need to build a path - we can use the tag directly
261 //g_string_append_c ( xd->xpath, '/' );
262 //g_string_append ( xd->xpath, el );
263 //xd->current_tag = get_tag ( xd->xpath->str );
264 xd->current_tag = get_tag ( el );
265 switch ( xd->current_tag ) {
266 case tt_gpx_file:
267 if ( xd->current_gpx_meta_data )
268 free_gpx_meta_data ( xd->current_gpx_meta_data, NULL );
269 xd->current_gpx_meta_data = new_gpx_meta_data_t();
270
271 if ( ( tmp = get_attr ( attr, "id" ) ) )
272 xd->current_gpx_meta_data->id = atoi ( tmp );
273
274 if ( ( tmp = get_attr ( attr, "name" ) ) )
275 xd->current_gpx_meta_data->name = g_strdup ( tmp );
276
277 if ( ( tmp = get_attr ( attr, "lat" ) ) ) {
278 g_snprintf (buf, sizeof (buf), tmp);
279 xd->current_gpx_meta_data->ll.lat = g_ascii_strtod ( buf, NULL );
280 }
281
282 if ( ( tmp = get_attr ( attr, "lon" ) ) ) {
283 g_snprintf (buf, sizeof (buf), tmp);
284 xd->current_gpx_meta_data->ll.lon = g_ascii_strtod ( buf, NULL );
285 }
286
287 if ( ( tmp = get_attr ( attr, "visibility" ) ) )
288 xd->current_gpx_meta_data->vis = g_strdup ( tmp );
289
290 if ( ( tmp = get_attr ( attr, "timestamp" ) ) )
291 xd->current_gpx_meta_data->timestamp = g_strdup ( tmp );
292
293 g_string_erase ( xd->c_cdata, 0, -1 ); // clear the cdata buffer
294 break;
295 case tt_gpx_file_desc:
296 case tt_gpx_file_tag:
297 g_string_erase ( xd->c_cdata, 0, -1 ); // clear the cdata buffer
298 break;
299 default:
300 g_string_erase ( xd->c_cdata, 0, -1 ); // clear the cdata buffer
301 break;
302 }
303}
304
305static void gpx_meta_data_end ( xml_data *xd, const char *el )
306{
307 //g_string_truncate ( xd->xpath, xd->xpath->len - strlen(el) - 1 );
308 //switch ( xd->current_tag ) {
309 switch ( get_tag ( el ) ) {
310 case tt_gpx_file: {
311 // End of the individual file metadata, thus save what we have read in to the list
312 // Copy it so we can reference it
313 gpx_meta_data_t *current = copy_gpx_meta_data_t ( xd->current_gpx_meta_data );
314 // Stick in the list
315 xd->list_of_gpx_meta_data = g_list_prepend(xd->list_of_gpx_meta_data, current);
316 g_string_erase ( xd->c_cdata, 0, -1 );
317 break;
318 }
319 case tt_gpx_file_desc:
320 // Store the description:
321 if ( xd->current_gpx_meta_data ) {
322 // NB Limit description size as it's displayed on a single line
323 // Hopefully this will prevent the dialog getting too wide...
324 xd->current_gpx_meta_data->desc = g_strndup ( xd->c_cdata->str, 63 );
325 }
326 g_string_erase ( xd->c_cdata, 0, -1 );
327 break;
328 case tt_gpx_file_tag:
329 // One day do something with this...
330 g_string_erase ( xd->c_cdata, 0, -1 );
331 break;
332 default:
333 break;
334 }
335}
336
337static void gpx_meta_data_cdata ( xml_data *xd, const XML_Char *s, int len )
338{
339 switch ( xd->current_tag ) {
340 case tt_gpx_file_desc:
341 case tt_gpx_file_tag:
342 g_string_append_len ( xd->c_cdata, s, len );
343 break;
344 default: break; // ignore cdata from other things
345 }
346}
347
348static gboolean read_gpx_files_metadata_xml ( gchar *tmpname, xml_data *xd )
349{
350 FILE *ff = g_fopen (tmpname, "r");
351 if ( !ff )
352 return FALSE;
353
354 XML_Parser parser = XML_ParserCreate(NULL);
355 enum XML_Status status = XML_STATUS_ERROR;
356
357 XML_SetElementHandler(parser, (XML_StartElementHandler) gpx_meta_data_start, (XML_EndElementHandler) gpx_meta_data_end);
358 XML_SetUserData(parser, xd);
359 XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler) gpx_meta_data_cdata);
360
361 gchar buf[4096];
362
363 int done=0, len;
364 while (!done) {
365 len = fread(buf, 1, sizeof(buf)-7, ff);
366 done = feof(ff) || !len;
367 status = XML_Parse(parser, buf, len, done);
368 }
369
370 XML_ParserFree (parser);
371
372 fclose ( ff );
373
374 return status != XML_STATUS_ERROR;
375}
376
377static GList *select_from_list (GtkWindow *parent, GList *list, const gchar *title, const gchar *msg )
378{
379 GtkTreeIter iter;
380 GtkCellRenderer *renderer;
381 GtkWidget *view;
382 gchar *latlon_string;
383 int column_runner;
384
385 GtkWidget *dialog = gtk_dialog_new_with_buttons (title,
386 parent,
387 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
388 GTK_STOCK_CANCEL,
389 GTK_RESPONSE_REJECT,
390 GTK_STOCK_OK,
391 GTK_RESPONSE_ACCEPT,
392 NULL);
393 /* When something is selected then OK */
394 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
395 GtkWidget *response_w = NULL;
396#if GTK_CHECK_VERSION (2, 20, 0)
397 /* Default to not apply - as initially nothing is selected! */
398 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
399#endif
400 GtkWidget *label = gtk_label_new ( msg );
6ef14d6b 401 GtkTreeStore *store = gtk_tree_store_new ( 6, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN );
3cc57413
RN
402 GList *list_runner = list;
403 while (list_runner) {
404 gpx_meta_data_t *gpx_meta_data = (gpx_meta_data_t *)list_runner->data;
405 // To keep display compact three digits of precision for lat/lon should be plenty
406 latlon_string = g_strdup_printf("(%.3f,%.3f)", gpx_meta_data->ll.lat, gpx_meta_data->ll.lon);
407 gtk_tree_store_append(store, &iter, NULL);
408 gtk_tree_store_set ( store, &iter,
409 0, gpx_meta_data->name,
410 1, gpx_meta_data->desc,
411 2, gpx_meta_data->timestamp,
412 3, latlon_string,
413 4, gpx_meta_data->vis,
6ef14d6b 414 5, gpx_meta_data->in_current_view,
3cc57413
RN
415 -1 );
416 list_runner = g_list_next ( list_runner );
417 g_free ( latlon_string );
418 }
419
420 view = gtk_tree_view_new();
421 renderer = gtk_cell_renderer_text_new();
422 column_runner = 0;
423 GtkTreeViewColumn *column;
424
425 column = gtk_tree_view_column_new_with_attributes ( _("Name"), renderer, "text", column_runner, NULL);
426 gtk_tree_view_column_set_sort_column_id (column, column_runner);
427 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
428
429 column_runner++;
430 column = gtk_tree_view_column_new_with_attributes ( _("Description"), renderer, "text", column_runner, NULL);
431 gtk_tree_view_column_set_sort_column_id (column, column_runner);
432 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
433
434 column_runner++;
435 column = gtk_tree_view_column_new_with_attributes ( _("Time"), renderer, "text", column_runner, NULL);
436 gtk_tree_view_column_set_sort_column_id (column, column_runner);
437 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
438
439 column_runner++;
440 column = gtk_tree_view_column_new_with_attributes ( _("Lat/Lon"), renderer, "text", column_runner, NULL);
441 gtk_tree_view_column_set_sort_column_id (column, column_runner);
442 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
443
444 column_runner++;
445 column = gtk_tree_view_column_new_with_attributes ( _("Privacy"), renderer, "text", column_runner, NULL); // AKA Visibility
446 gtk_tree_view_column_set_sort_column_id (column, column_runner);
447 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
448
6ef14d6b
RN
449 GtkCellRenderer *renderer_toggle = gtk_cell_renderer_toggle_new ();
450 g_object_set (G_OBJECT (renderer_toggle), "activatable", FALSE, NULL); // No user action - value is just for display
451 column_runner++;
452 column = gtk_tree_view_column_new_with_attributes ( _("Within Current View"), renderer_toggle, "active", column_runner, NULL);
453 gtk_tree_view_column_set_sort_column_id (column, column_runner);
454 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
455
3cc57413
RN
456 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
457 gtk_tree_selection_set_mode( gtk_tree_view_get_selection(GTK_TREE_VIEW(view)), GTK_SELECTION_MULTIPLE );
458 g_object_unref(store);
459
460 GtkWidget *scrolledwindow = gtk_scrolled_window_new ( NULL, NULL );
461 gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
462 gtk_container_add ( GTK_CONTAINER(scrolledwindow), view );
463
464 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), label, FALSE, FALSE, 0);
465 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), scrolledwindow, TRUE, TRUE, 0);
466
467 // Ensure a reasonable number of items are shown, but let the width be automatically sized
468 gtk_widget_set_size_request ( dialog, -1, 400) ;
469 gtk_widget_show_all ( dialog );
470
471 if ( response_w )
472 gtk_widget_grab_focus ( response_w );
473
474 while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT ) {
475
476 // Possibily not the fastest method but we don't have thousands of entries to process...
477 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
478 GList *selected = NULL;
479
480 // because we don't store the full data in the gtk model, we have to scan & look it up
481 if ( gtk_tree_model_get_iter_first( GTK_TREE_MODEL(store), &iter) ) {
482 do {
483 if ( gtk_tree_selection_iter_is_selected ( selection, &iter ) ) {
484 // For every selected item,
485 // compare the name from the displayed view to every gpx entry to find the gpx this selection represents
486 gchar* name;
487 gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, 0, &name, -1 );
488 // I believe the name of these items to be always unique
489 list_runner = list;
490 while (list_runner) {
491 if ( !strcmp ( ((gpx_meta_data_t*)list_runner->data)->name, name ) ) {
492 gpx_meta_data_t *copied = copy_gpx_meta_data_t (list_runner->data);
493 selected = g_list_prepend (selected, copied);
494 break;
495 }
496 list_runner = g_list_next ( list_runner );
497 }
498 }
499 }
500 while ( gtk_tree_model_iter_next ( GTK_TREE_MODEL(store), &iter ) );
501 }
502
503 if ( selected ) {
504 gtk_widget_destroy ( dialog );
505 return selected;
506 }
507 a_dialog_error_msg(parent, _("Nothing was selected"));
508 }
509 gtk_widget_destroy ( dialog );
510 return NULL;
511}
512
513static void none_found ( GtkWindow *gw )
514{
515 GtkWidget *dialog = NULL;
516
517 dialog = gtk_dialog_new_with_buttons ( "", gw, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL );
518 gtk_window_set_title(GTK_WINDOW(dialog), _("GPS Traces"));
519
520 GtkWidget *search_label = gtk_label_new(_("None found!"));
521 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), search_label, FALSE, FALSE, 5 );
522 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
523 gtk_widget_show_all(dialog);
524
525 gtk_dialog_run ( GTK_DIALOG(dialog) );
526 gtk_widget_destroy(dialog);
527}
528
6ef14d6b
RN
529/**
530 * For each track - mark whether the start is in within the viewport
531 */
532static void set_in_current_view_property ( VikTrwLayer *vtl, datasource_osm_my_traces_t *data, GList *gl )
533{
534 gdouble min_lat, max_lat, min_lon, max_lon;
535 /* get Viewport bounding box */
536 vik_viewport_get_min_max_lat_lon ( data->vvp, &min_lat, &max_lat, &min_lon, &max_lon );
537
538 LatLonBBox bbox;
539 bbox.north = max_lat;
540 bbox.east = max_lon;
541 bbox.south = min_lat;
542 bbox.west = min_lon;
543
544 GList *iterator = gl;
545 while ( iterator ) {
546 gpx_meta_data_t* gmd = (gpx_meta_data_t*)iterator->data;
547 // Convert point position into a 'fake' bounding box
548 // TODO - probably should have function to see if point is within bounding box
549 // rather than constructing this fake bounding box for the test
550 LatLonBBox gmd_bbox;
551 gmd_bbox.north = gmd->ll.lat;
552 gmd_bbox.east = gmd->ll.lon;
553 gmd_bbox.south = gmd->ll.lat;
554 gmd_bbox.west = gmd->ll.lon;
555
556 if ( BBOX_INTERSECT ( bbox, gmd_bbox ) )
557 gmd->in_current_view = TRUE;
558
559 iterator = g_list_next ( iterator );
560 }
561}
562
3cc57413
RN
563static gboolean datasource_osm_my_traces_process ( VikTrwLayer *vtl, const gchar *cmd, const gchar *extra, BabelStatusFunc status_cb, acq_dialog_widgets_t *adw, DownloadMapOptions *options_unused )
564{
565 //datasource_osm_my_traces_t *data = (datasource_osm_my_traces_t *)adw->user_data;
566
567 gboolean result;
568
569 gchar *user_pass = osm_get_login();
570
571 DownloadMapOptions options = { FALSE, FALSE, NULL, 2, NULL, user_pass }; // Allow a couple of redirects
572
573 xml_data *xd = g_malloc ( sizeof (xml_data) );
574 //xd->xpath = g_string_new ( "" );
575 xd->c_cdata = g_string_new ( "" );
576 xd->current_tag = tt_unknown;
577 xd->current_gpx_meta_data = new_gpx_meta_data_t();
578 xd->list_of_gpx_meta_data = NULL;
579
580 gchar *tmpname = a_download_uri_to_tmp_file ( DS_OSM_TRACES_GPX_FILES, &options );
581 result = read_gpx_files_metadata_xml ( tmpname, xd );
582 // Test already downloaded metadata file: eg:
6ef14d6b 583 //result = read_gpx_files_metadata_xml ( "/tmp/viking-download.GI47PW", xd );
3cc57413
RN
584
585 if ( tmpname ) {
586 g_remove ( tmpname );
587 g_free ( tmpname );
588 }
589
590 if ( ! result )
591 return FALSE;
592
593 if ( g_list_length ( xd->list_of_gpx_meta_data ) == 0 ) {
594 if (!vik_datasource_osm_my_traces_interface.is_thread)
595 none_found ( GTK_WINDOW(adw->vw) );
596 return FALSE;
597 }
598
599 xd->list_of_gpx_meta_data = g_list_reverse ( xd->list_of_gpx_meta_data );
600
6ef14d6b
RN
601 set_in_current_view_property ( vtl, adw->user_data, xd->list_of_gpx_meta_data );
602
3cc57413
RN
603 if (vik_datasource_osm_my_traces_interface.is_thread) gdk_threads_enter();
604 GList *selected = select_from_list ( GTK_WINDOW(adw->vw), xd->list_of_gpx_meta_data, "Select GPS Traces", "Select the GPS traces you want to add." );
605 if (vik_datasource_osm_my_traces_interface.is_thread) gdk_threads_leave();
606
607 // If passed in on an existing layer - we will create everything into that.
608 // thus with many differing gpx's - this will combine all waypoints into this single layer!
609 // Hence the preference is to create multiple layers
610 // and so this creation of the layers must be managed here
611
612 gboolean create_new_layer = ( !vtl );
613
614 // Only update the screen on the last layer acquired
615 VikTrwLayer *vtl_last = vtl;
616 gboolean got_something = FALSE;
617
618 GList *selected_iterator = selected;
619 while ( selected_iterator ) {
620
621 VikTrwLayer *vtlX = vtl;
622
623 if ( create_new_layer ) {
624 // Have data but no layer - so create one
625 vtlX = VIK_TRW_LAYER ( vik_layer_create ( VIK_LAYER_TRW, vik_window_viewport(adw->vw), NULL, FALSE ) );
626 if ( ((gpx_meta_data_t*)selected_iterator->data)->name )
627 vik_layer_rename ( VIK_LAYER ( vtlX ), ((gpx_meta_data_t*)selected_iterator->data)->name );
628 else
629 vik_layer_rename ( VIK_LAYER ( vtlX ), _("My OSM Traces") );
630 vik_aggregate_layer_add_layer ( vik_layers_panel_get_top_layer (adw->vlp), VIK_LAYER(vtlX) );
631 }
632
633 result = FALSE;
634 gint gpx_id = ((gpx_meta_data_t*)selected_iterator->data)->id;
635 if ( gpx_id ) {
636 gchar *url = g_strdup_printf ( DS_OSM_TRACES_GPX_URL_FMT, gpx_id );
637
638 result = a_babel_convert_from_url ( vtlX, url, "gpx", status_cb, adw, &options );
639 // TODO investigate using a progress bar:
640 // http://developer.gnome.org/gtk/2.24/GtkProgressBar.html
641
642 got_something = got_something || result;
643 // TODO feedback to UI to inform which traces failed
644 if ( !result )
645 g_warning ( _("Unable to get trace: %s"), url );
646 }
647
648 if ( result ) {
649 // Move to area of the track
650 vik_trw_layer_auto_set_view ( vtlX, vik_window_viewport(adw->vw) );
651 vik_layer_post_read ( VIK_LAYER(vtlX), vik_window_viewport(adw->vw), TRUE );
652 vtl_last = vtlX;
653 }
654 else if ( create_new_layer ) {
655 // Layer not needed as no data has been acquired
656 g_object_unref ( vtlX );
657 }
658
659 selected_iterator = g_list_next ( selected_iterator );
660 }
661
662 // Free memory
663 if ( xd->current_gpx_meta_data )
664 free_gpx_meta_data ( xd->current_gpx_meta_data, NULL );
665 g_free ( xd->current_gpx_meta_data );
666 free_gpx_meta_data_list ( xd->list_of_gpx_meta_data );
667 free_gpx_meta_data_list ( selected );
668 g_free ( xd );
669 g_free ( user_pass );
670
671 // Would prefer to keep the update in acquire.c,
672 // however since we may create the layer - need to do the update here
673 if ( got_something )
674 vik_layer_emit_update ( VIK_LAYER(vtl_last) );
675
676 // ATM The user is only informed if all getting *all* of the traces failed
677 if ( selected )
678 result = got_something;
679 else
680 // Process was cancelled but need to return that it proceeded as expected
681 result = TRUE;
682
683 return result;
684}
685
686static void datasource_osm_my_traces_cleanup ( gpointer data )
687{
688 g_free ( data );
689}