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