]> err.no Git - mapper/blob - src/path-mapper.c
Mapper: More integration fixes
[mapper] / src / path-mapper.c
1 /*
2  * This file is part of Mapper
3  *
4  * Copyright (C) 2007-2008 Kaj-Michael Lang
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 /**
22  * Contains extra path functions, specific to mapper. 
23  */
24
25 #include <config.h>
26
27 #include <libgnomevfs/gnome-vfs.h>
28
29 #include "utils.h"
30 #include "gps.h"
31 #include "settings.h"
32 #include "help.h"
33 #include "mapper-types.h"
34 #include "ui-common.h"
35 #include "dialogs.h"
36 #include "file.h"
37 #include "latlon.h"
38 #include "path.h"
39 #include "path-mapper.h"
40
41 typedef struct _OriginToggleInfo OriginToggleInfo;
42 struct _OriginToggleInfo {
43         GtkWidget *rad_use_gps;
44         GtkWidget *rad_use_route;
45         GtkWidget *rad_use_text;
46         GtkWidget *chk_auto;
47         GtkWidget *txt_from;
48         GtkWidget *txt_to;
49         Path *path;
50 };
51
52 static gboolean route_auto_dl_idle_cb();
53 static void route_cancel_autoroute(Path *route, gboolean temporary);
54
55 /**
56  * path_clear_ask:
57  * @path
58  * @msg
59  *
60  * Ask confirmation to clear given path, using msg as the question.
61  *
62  * Returns: TRUE if path was cleared.
63  */
64 gboolean
65 path_clear_ask(Path *path, const gchar *msg)
66 {
67 GtkWidget *confirm;
68 gboolean res=FALSE;
69
70 g_return_val_if_fail(path, FALSE);
71
72 confirm=hildon_note_new_confirmation(GTK_WINDOW(_window), msg);
73 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
74         path_clear(path);
75         res=TRUE;
76 }
77 gtk_widget_destroy(confirm);
78 return res;
79 }
80
81 /**
82  * path_show_distance_from:
83  *
84  */
85 void 
86 path_show_distance_from(Path *path, Point *point)
87 {
88 gchar buffer[80];
89 gdouble dist;
90
91 if (path && path_has_points(path)) {
92         dist=path_calculate_distance_from(path, point);
93         g_snprintf(buffer, sizeof(buffer), "%s: %.02f %s", _("Distance"), dist * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
94         MACRO_BANNER_SHOW_INFO(_window, buffer);
95 } else {
96         MACRO_BANNER_SHOW_INFO(_window, _("The current path is empty."));
97 }
98 }
99
100 /**
101  * path_show_distance_from_last:
102  *
103  */
104 void 
105 path_show_distance_from_last(Path *path)
106 {
107 Point *point;
108
109 g_return_if_fail(path);
110
111 point=path_find_last_point(path);
112 g_return_if_fail(point);
113
114 path_show_distance_from(path, point);
115 }
116
117 /**
118  * path_show_distance_from_first:
119  *
120  */
121 void 
122 path_show_distance_from_first(Path *path)
123 {
124 g_return_if_fail(path);
125
126 path_show_distance_from(path, path->head);
127 }
128
129 /**
130  * path_show_distance_to: 
131  *
132  * Show the distance from the current GPS location to the given point,
133  * following the route. If point is NULL, then the distance is shown to the
134  * next waypoint.
135  */
136 gboolean 
137 path_show_distance_to(Path *route, Point *point)
138 {
139 gchar buffer[80];
140 gdouble lat, lon;
141 gdouble sum;
142
143 g_return_val_if_fail(route, FALSE);
144
145 unit2latlon(point->unitx, point->unity, &lat, &lon);
146 sum=path_get_distance_to(route, point, lat, lon);
147 g_snprintf(buffer, sizeof(buffer), "%s: %.02f %s", _("Distance"), sum * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
148 MACRO_BANNER_SHOW_INFO(_window, buffer);
149
150 return TRUE;
151 }
152
153 /**
154  * path_show_distance_to_next_waypoint:
155  *
156  * Display distance to next waypoint in given route
157  *
158  */
159 void 
160 path_show_distance_to_next_waypoint(Path *route)
161 {
162 g_return_if_fail(route);
163
164 if (!path_show_distance_to(route, NULL))
165         MACRO_BANNER_SHOW_INFO(_window, _("There is no next waypoint."));
166 }
167
168 /**
169  * path_show_distance_to_last:
170  *
171  * Show distance to last point in given route
172  *
173  */
174 void 
175 path_show_distance_to_last(Path *route)
176 {
177 g_return_if_fail(route);
178
179 if (route->head != route->tail) {
180         path_show_distance_to(route, path_find_last_point(route));
181 } else {
182         MACRO_BANNER_SHOW_INFO(_window, _("The current route is empty."));
183 }
184 }
185
186 /**
187  * route_autoroute_check:
188  *
189  * Check if we should re-calculate route
190  */
191 void
192 route_autoroute_check(Path *path)
193 {
194 g_return_if_fail(path);
195
196 if (_autoroute_data.enabled && !_autoroute_data.in_progress && path->near_point_dist_squared > 400) {
197         _autoroute_data.in_progress = TRUE;
198         g_idle_add((GSourceFunc)route_auto_dl_idle_cb, NULL);
199         MACRO_BANNER_SHOW_INFO(_window, _("Recalculating directions..."));
200 }
201
202 }
203
204 gboolean
205 path_open(Path *track)
206 {
207 gchar *buffer;
208 gint size;
209 gboolean r = FALSE;
210
211 if (file_open_get_contents(&_track_file_uri, &buffer, &size)) {
212         if (path_gpx_parse(track, buffer, size, GPX_PATH_NEW)) {
213                 MACRO_BANNER_SHOW_INFO(_window, _("Track Opened"));
214                 r = TRUE;
215         } else {
216                 popup_error(_window, _("Error parsing track GPX file."));
217         }
218         g_free(buffer);
219 }
220 return r;
221 }
222
223 gboolean
224 path_save(Path *track)
225 {
226 GnomeVFSHandle *handle;
227 gboolean r = FALSE;
228
229 if (file_save(&_track_file_uri, &_track_file_uri, &handle)) {
230         if (path_gpx_write(track, handle, NULL)) {
231                 MACRO_BANNER_SHOW_INFO(_window, _("Track Saved"));
232                 r = TRUE;
233                 path_clear_ask(track, _("Clear track ?"));
234         } else {
235                 popup_error(_window, _("Error writing track GPX file."));
236         }
237         gnome_vfs_close(handle);
238 }
239 return r;
240 }
241
242 /**
243  * route_open_file:
244  * @route
245  *
246  * Open a route GPX file
247  *
248  */
249 gboolean 
250 route_open_file(Path *route)
251 {
252 gchar *buffer;
253 gint size;
254
255 g_return_val_if_fail(route, FALSE);
256
257 if (file_open_get_contents(&_route_dir_uri, &buffer, &size)) {
258         /* If auto is enabled, append the route, otherwise replace it. */
259         if (path_gpx_parse(route, buffer, size, _autoroute_data.enabled ? GPX_PATH_APPEND : GPX_PATH_NEW)) {
260                 route_cancel_autoroute(route, FALSE);
261
262                 MACRO_BANNER_SHOW_INFO(_window, _("Route Opened"));
263                 /* Find the nearest route point, if we're connected. */
264                 path_find_nearest_point(route, _gps->data.lat, _gps->data.lon);
265                 path_set_destination_from_last(route, &_dest);
266                 return TRUE;
267         } else {
268                 popup_error(_window, _("Error parsing route GPX file."));
269                 g_free(buffer);
270                 return FALSE;
271         }
272 }
273 return FALSE;
274 }
275
276 /**
277  * route_save:
278  *
279  * Ask user to save route to GPX file.
280  *
281  */
282 gboolean
283 route_save(Path *route)
284 {
285 GnomeVFSHandle *handle;
286
287 g_return_val_if_fail(route, FALSE);
288
289 if (route->head==route->tail) {
290         MACRO_BANNER_SHOW_INFO(_window, _("No route exist."));
291         return FALSE;
292 }
293
294 if (file_save(&_route_dir_uri, &_route_dir_uri, &handle)) {
295         if (path_gpx_write(route, handle, NULL)) {
296                 MACRO_BANNER_SHOW_INFO(_window, _("Route Saved"));
297         } else {
298                 popup_error(_window, _("Error writing route GPX file."));
299         }
300         gnome_vfs_close(handle);
301         return TRUE;
302 }
303 return FALSE;
304 }
305
306 static gboolean 
307 route_origin_type_selected_cb(GtkWidget *toggle, OriginToggleInfo *oti)
308 {
309 gchar buffer[80];
310 gchar strlat[32];
311 gchar strlon[32];
312
313 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) {
314         if (toggle == oti->rad_use_gps) {
315                 g_ascii_formatd(strlat, 32, "%.06f", _gps->data.lat);
316                 g_ascii_formatd(strlon, 32, "%.06f", _gps->data.lon);
317                 g_snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
318                 gtk_entry_set_text(GTK_ENTRY(oti->txt_from), buffer);
319         } else if (toggle == oti->rad_use_route) {
320                 gdouble lat, lon;
321                 Point *p;
322
323                 p=path_find_last_point(oti->path);
324                 if (p) {
325                         unit2latlon(p->unitx, p->unity, &lat, &lon);
326                         g_ascii_formatd(strlat, 32, "%.06f", lat);
327                         g_ascii_formatd(strlon, 32, "%.06f", lon);
328                         g_snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
329                         gtk_entry_set_text(GTK_ENTRY(oti->txt_from), buffer);
330                 }
331         }
332         gtk_widget_set_sensitive(oti->txt_from, toggle == oti->rad_use_text);
333         gtk_widget_set_sensitive(oti->chk_auto, toggle == oti->rad_use_gps);
334 }
335 return TRUE;
336 }
337
338 /**
339  * route_cancel_autoroute:
340  *
341  * Cancel the current auto-route.
342  */
343 static void 
344 route_cancel_autoroute(Path *route, gboolean temporary)
345 {
346 if (_autoroute_data.enabled) {
347         if (!temporary) {
348                 _autoroute_data.enabled=FALSE;
349
350                 g_free(_autoroute_data.dest);
351                 _autoroute_data.dest=NULL;
352
353                 g_free(_autoroute_data.src_str);
354                 _autoroute_data.src_str=NULL;
355         }
356
357         if (_autoroute_data.curl_easy) {
358                 if (_autoroute_data.curl_multi)
359                         curl_multi_remove_handle(_autoroute_data.curl_multi, _autoroute_data.curl_easy);
360                 curl_easy_cleanup(_autoroute_data.curl_easy);
361                 curl_multi_cleanup(_autoroute_data.curl_multi);
362                 _autoroute_data.curl_easy=NULL;
363                 _autoroute_data.curl_multi=NULL;
364         }
365
366         g_free(_autoroute_data.rdl_data.bytes);
367         _autoroute_data.rdl_data.bytes=NULL;
368         _autoroute_data.rdl_data.bytes_read=0;
369         _autoroute_data.in_progress=FALSE;
370 }
371 }
372
373 static gboolean 
374 route_auto_download_timeout()
375 {
376 CURLMsg *msg;
377 gint num_msgs = 0;
378
379 if (!_autoroute_data.curl_multi) {
380         route_cancel_autoroute(_route, TRUE);
381         return FALSE;
382 }
383
384 while (_autoroute_data.curl_multi && (msg = curl_multi_info_read(_autoroute_data.curl_multi, &num_msgs))) {
385         if (msg->msg == CURLMSG_DONE) {
386                 /* Now, parse the autoroute and update the display. */
387                 if (_autoroute_data.enabled && path_gpx_parse(_route, _autoroute_data.rdl_data.bytes, _autoroute_data.rdl_data.bytes_read, 0)) {
388                         /* Find the nearest route point, if we're connected. */
389                         path_find_nearest_point(_route, _gps->data.lat, _gps->data.lon);
390                 }
391                 route_cancel_autoroute(_route, TRUE);   /* We're done. Clean up. */
392                 return FALSE;
393         }
394 }
395 return TRUE;
396 }
397
398 /**
399  * Read the data provided by the given handle as GPX data, updating the
400  * auto-route with that data.
401  */
402 static size_t
403 route_auto_dl_read_cb(void *ptr, size_t size, size_t nmemb, RouteDownloadData * rdl_data)
404 {
405 size_t old_size = rdl_data->bytes_read;
406
407 rdl_data->bytes_read += size * nmemb;
408 rdl_data->bytes = g_renew(gchar, rdl_data->bytes, rdl_data->bytes_read);
409 g_memmove(rdl_data->bytes + old_size, ptr, size * nmemb);
410
411 return (size * nmemb);
412 }
413
414 static gboolean
415 route_auto_dl_idle_cb()
416 {
417 gchar latstr[32], lonstr[32], *latlonstr;
418
419 g_ascii_dtostr(latstr, 32, _gps->data.lat);
420 g_ascii_dtostr(lonstr, 32, _gps->data.lon);
421 latlonstr = g_strdup_printf("%s,%s", latstr, lonstr);
422 _autoroute_data.src_str = g_strdup_printf(_route_dl_url, latlonstr, _autoroute_data.dest);
423 g_free(latlonstr);
424
425 MACRO_CURL_EASY_INIT(_autoroute_data.curl_easy);
426 curl_easy_setopt(_autoroute_data.curl_easy, CURLOPT_URL, _autoroute_data.src_str);
427 curl_easy_setopt(_autoroute_data.curl_easy, CURLOPT_WRITEFUNCTION, route_auto_dl_read_cb);
428 curl_easy_setopt(_autoroute_data.curl_easy, CURLOPT_WRITEDATA, &_autoroute_data.rdl_data);
429 _autoroute_data.curl_multi=curl_multi_init();
430 curl_multi_add_handle(_autoroute_data.curl_multi, _autoroute_data.curl_easy);
431
432 if (iap_is_connected() && !_autoroute_data.curl_sid)
433         _autoroute_data.curl_sid=g_timeout_add(250, (GSourceFunc)route_auto_download_timeout, NULL);
434
435 _autoroute_data.in_progress=TRUE;
436
437 return FALSE;
438 }
439
440 /**
441  * Display a dialog box to the user asking them to download a route.  The
442  * "From" and "To" textfields may be initialized using the first two
443  * parameters.  The third parameter, if set to TRUE, will cause the "Use GPS
444  * Location" checkbox to be enabled, which automatically sets the "From" to the
445  * current GPS position (this overrides any value that may have been passed as
446  * the "To" initializer).
447  * None of the passed strings are freed - that is left to the caller, and it is
448  * safe to free either string as soon as this function returns.
449  */
450 gboolean 
451 route_download_dialog(Path *route, gchar *to)
452 {
453 GtkWidget *dialog;
454 GtkWidget *table;
455 GtkWidget *label;
456 GtkWidget *txt_source_url;
457 GtkWidget *hbox;
458 OriginToggleInfo oti;
459 GtkEntryCompletion *from_comp;
460 GtkEntryCompletion *to_comp;
461 gboolean r=FALSE;
462
463 oti.path=route;
464
465 memset(&_autoroute_data, 0, sizeof(_autoroute_data));
466
467 dialog = gtk_dialog_new_with_buttons(_("Download Route"),
468                              GTK_WINDOW(_window),
469                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
470                              GTK_RESPONSE_ACCEPT,
471                              GTK_STOCK_CANCEL,
472                              GTK_RESPONSE_REJECT, NULL);
473
474 help_dialog_help_enable(GTK_DIALOG(dialog), HELP_ID_DOWNROUTE);
475 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table = gtk_table_new(2, 5, FALSE), TRUE, TRUE, 0);
476
477 from_comp = gtk_entry_completion_new();
478 gtk_entry_completion_set_model(from_comp, GTK_TREE_MODEL(_loc_model));
479 gtk_entry_completion_set_text_column(from_comp, 0);
480 to_comp = gtk_entry_completion_new();
481 gtk_entry_completion_set_model(to_comp, GTK_TREE_MODEL(_loc_model));
482 gtk_entry_completion_set_text_column(to_comp, 0);
483
484 /* Source URL. */
485 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Source URL")), 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
486 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
487 gtk_table_attach(GTK_TABLE(table), txt_source_url = gtk_entry_new(), 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
488 gtk_entry_set_width_chars(GTK_ENTRY(txt_source_url), 25);
489
490 /* Auto. */
491 gtk_table_attach(GTK_TABLE(table), hbox = gtk_hbox_new(FALSE, 6), 0, 2, 1, 2, GTK_FILL, 0, 2, 4);
492 gtk_box_pack_start(GTK_BOX(hbox), oti.rad_use_gps = gtk_radio_button_new_with_label(NULL, _("Use GPS Location")), TRUE, TRUE, 0);
493 gtk_box_pack_start(GTK_BOX(hbox), oti.chk_auto = gtk_check_button_new_with_label(_("Auto-Update")), TRUE, TRUE, 0);
494 gtk_widget_set_sensitive(oti.chk_auto, FALSE);
495
496 /* Use End of Route. */
497 gtk_table_attach(GTK_TABLE(table), hbox = gtk_hbox_new(FALSE, 6), 0, 2, 2, 3, GTK_FILL, 0, 2, 4);
498 gtk_box_pack_start(GTK_BOX(hbox), oti.rad_use_route = gtk_radio_button_new_with_label_from_widget
499                    (GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")), TRUE, TRUE, 0);
500 gtk_widget_set_sensitive(oti.rad_use_route, route->head != route->tail);
501
502 /* Origin. */
503 gtk_table_attach(GTK_TABLE(table), oti.rad_use_text = gtk_radio_button_new_with_label_from_widget
504                  (GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")), 0, 1, 3, 4, GTK_FILL, 0, 2, 4);
505 gtk_table_attach(GTK_TABLE(table), oti.txt_from = gtk_entry_new(), 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
506 gtk_entry_set_completion(GTK_ENTRY(oti.txt_from), from_comp);
507 gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_from), 25);
508
509 /* Destination. */
510 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Destination")), 0, 1, 4, 5, GTK_FILL, 0, 2, 4);
511 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
512 gtk_table_attach(GTK_TABLE(table), oti.txt_to = gtk_entry_new(), 1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
513 gtk_entry_set_completion(GTK_ENTRY(oti.txt_to), to_comp);
514 gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_to), 25);
515
516 g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled", G_CALLBACK(route_origin_type_selected_cb), &oti);
517 g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled", G_CALLBACK(route_origin_type_selected_cb), &oti);
518 g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled", G_CALLBACK(route_origin_type_selected_cb), &oti);
519
520 #if defined (WITH_HILDON) && defined (HILDON_AUTOCAP)
521 g_object_set(G_OBJECT(oti.txt_from), HILDON_AUTOCAP, FALSE, NULL);
522 g_object_set(G_OBJECT(oti.txt_to), HILDON_AUTOCAP, FALSE, NULL);
523 #endif
524
525 /* Initialize fields. */
526 gtk_entry_set_text(GTK_ENTRY(txt_source_url), _route_dl_url);
527 gtk_entry_set_text(GTK_ENTRY(oti.txt_to), (to ? to : ""));
528
529 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
530
531 if (path_has_points(route)) {
532         /* Use "End of Route" by default if they have a route. */
533         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
534         gtk_widget_grab_focus(oti.rad_use_route);
535 } else if (_enable_gps) {
536         /* Else use "GPS Location" if they have GPS enabled. */
537         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
538         gtk_widget_grab_focus(oti.rad_use_gps);
539 } else {
540         /* Else use text. */
541         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
542         gtk_widget_grab_focus(oti.txt_from);
543 }
544
545 gtk_widget_show_all(dialog);
546
547 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
548         CURL *curl_easy;
549         RouteDownloadData rdl_data = { 0, 0 };
550         gchar buffer[BUFFER_SIZE];
551         const gchar *source_url, *from, *to;
552         gchar *from_escaped, *to_escaped;
553
554         source_url = gtk_entry_get_text(GTK_ENTRY(txt_source_url));
555         if (!strlen(source_url)) {
556                 popup_error(dialog, _("Please specify a source URL."));
557                 continue;
558         } else {
559                 g_free(_route_dl_url);
560                 _route_dl_url = g_strdup(source_url);
561         }
562
563         from = gtk_entry_get_text(GTK_ENTRY(oti.txt_from));
564         if (!strlen(from)) {
565                 popup_error(dialog, _("Please specify a start location."));
566                 continue;
567         }
568
569         to = gtk_entry_get_text(GTK_ENTRY(oti.txt_to));
570         if (!strlen(to)) {
571                 popup_error(dialog, _("Please specify an end location."));
572                 continue;
573         }
574
575         from_escaped = gnome_vfs_escape_string(from);
576         to_escaped = gnome_vfs_escape_string(to);
577         g_snprintf(buffer, sizeof(buffer), source_url, from_escaped, to_escaped);
578         g_free(from_escaped);
579         g_free(to_escaped);
580
581         iap_connect();
582
583         /* Attempt to download the route from the server. */
584         MACRO_CURL_EASY_INIT(curl_easy);
585         curl_easy_setopt(curl_easy, CURLOPT_URL, buffer);
586         curl_easy_setopt(curl_easy, CURLOPT_WRITEFUNCTION, route_auto_dl_read_cb);
587         curl_easy_setopt(curl_easy, CURLOPT_WRITEDATA, &rdl_data);
588         if (CURLE_OK != curl_easy_perform(curl_easy)) {
589                 popup_error(dialog, _("Failed to connect to GPX Directions server"));
590                 curl_easy_cleanup(curl_easy);
591                 g_free(rdl_data.bytes);
592                 /* Let them try again */
593                 continue;
594         }
595         curl_easy_cleanup(curl_easy);
596
597         if (strncmp(rdl_data.bytes, "<?xml", strlen("<?xml"))) {
598                 /* Not an XML document - must be bad locations. */
599                 popup_error(dialog, _("Could not generate directions. Make sure your source and destination are valid."));
600                 g_free(rdl_data.bytes);
601                 /* Let them try again. */
602         }
603         /* Else, if GPS is enabled, replace the route, otherwise append it. */
604         else if (path_gpx_parse(route, rdl_data.bytes, rdl_data.bytes_read,
605                         (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)) ? GPX_PATH_NEW : GPX_PATH_APPEND))) {
606                 GtkTreeIter iter;
607
608                 /* Find the nearest route point, if we're connected. */
609                 path_find_nearest_point(route, _gps->data.lat, _gps->data.lon);
610
611                 /* Cancel any autoroute that might be occurring. */
612                 route_cancel_autoroute(route, FALSE);
613
614                 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.chk_auto))) {
615                         /* Kick off a timeout to start the first update. */
616                         _autoroute_data.dest = gnome_vfs_escape_string(to);
617                         _autoroute_data.enabled = TRUE;
618                 }
619
620                 /* Save Origin in Route Locations list if not from GPS. */
621                 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)) && !g_slist_find_custom(_loc_list, from, (GCompareFunc) strcmp)) {
622                         _loc_list = g_slist_prepend(_loc_list, g_strdup(from));
623                         gtk_list_store_insert_with_values(_loc_model, &iter, INT_MAX, 0, from, -1);
624                 }
625
626                 /* Save Destination in Route Locations list. */
627                 if (!g_slist_find_custom(_loc_list, to, (GCompareFunc) strcmp)) {
628                         _loc_list = g_slist_prepend(_loc_list, g_strdup(to));
629                         gtk_list_store_insert_with_values(_loc_model, &iter, INT_MAX, 0, to, -1);
630                 }
631
632                 g_free(rdl_data.bytes);
633                 path_set_destination_from_last(route, &_dest);
634
635                 MACRO_BANNER_SHOW_INFO(_window, _("Route Downloaded"));
636
637                 /* Success! Get out of the while loop. */
638                 r=TRUE;
639                 break;
640         } else {
641                 popup_error(dialog, _("Error parsing route GPX data."));
642                 g_free(rdl_data.bytes);
643                 /* Let them try again. */
644         }
645 }
646
647 gtk_widget_hide(dialog);        /* Destroying causes a crash (!?!?!??!) */
648
649 return r;
650 }
651
652 /**
653  * Ask for a text description for the current point
654  *
655  */
656 gboolean
657 path_insert_mark_ask(Path *track)
658 {
659 gchar tmp1[16], tmp2[16], *p_latlon;
660 GtkWidget *dialog;
661 GtkWidget *table;
662 GtkWidget *label;
663 GtkWidget *txt_scroll;
664 GtkWidget *txt_desc;
665 gboolean ret;
666
667 dialog = gtk_dialog_new_with_buttons(_("Insert Mark"),
668                                 GTK_WINDOW(_window), GTK_DIALOG_MODAL, 
669                                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
670                                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, 
671                                 NULL);
672
673 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table = gtk_table_new(2, 2, FALSE), TRUE, TRUE, 0);
674
675 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Near Lat, Lon")), 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
676 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
677
678 lat_format(_degformat, _gps->data.lat, tmp1);
679 lon_format(_degformat, _gps->data.lon, tmp2);
680 p_latlon=g_strdup_printf("%s, %s", tmp1, tmp2);
681 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(p_latlon), 1, 2, 0, 1, GTK_FILL, 0, 2, 4);
682 gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
683 g_free(p_latlon);
684
685 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Description")), 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
686 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
687
688 txt_scroll=gtk_scrolled_window_new(NULL, NULL);
689 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll), GTK_SHADOW_IN);
690 gtk_table_attach(GTK_TABLE(table), txt_scroll, 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
691
692 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
693
694 txt_desc=gtk_text_view_new();
695 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
696
697 gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
698 gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 450, 100);
699
700 gtk_widget_show_all(dialog);
701
702 ret=FALSE;
703 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
704         GtkTextBuffer *tbuf;
705         GtkTextIter ti1, ti2;
706
707         tbuf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
708         gtk_text_buffer_get_iter_at_offset(tbuf, &ti1, 0);
709         gtk_text_buffer_get_end_iter(tbuf, &ti2);
710
711         if (gtk_text_buffer_get_char_count(tbuf)>0) {
712                 path_insert_mark_text(track, gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE));
713         } else {
714                 popup_error(dialog, _("Please provide a description for the mark."));
715                 continue;
716         }
717
718         ret=TRUE;
719         break;
720 }
721 gtk_widget_destroy(dialog);
722 return ret;
723 }