]> git.street.me.uk Git - andy/viking.git/blob - src/datasource_gps.c
Open files in selected layer
[andy/viking.git] / src / datasource_gps.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2006, Alex Foobarian <foobarian@gmail.com>
6  * Copyright (C) 2012-2015, Rob Norris <rw_norris@hotmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include <glib/gstdio.h>
32 #include <glib/gprintf.h>
33 #include <glib/gi18n.h>
34
35 #include "datasource_gps.h"
36 #include "viking.h"
37 #include "babel.h"
38 #include "gpx.h"
39 #include "acquire.h"
40
41 static gboolean gps_acquire_in_progress = FALSE;
42
43 static gint last_active = -1;
44
45 static gpointer datasource_gps_init_func ( acq_vik_t *avt );
46 static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 );
47 static void datasource_gps_cleanup ( gpointer user_data );
48 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
49 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data );
50 static void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data );
51 static void datasource_gps_off ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
52
53 VikDataSourceInterface vik_datasource_gps_interface = {
54   N_("Acquire from GPS"),
55   N_("Acquired from GPS"),
56   VIK_DATASOURCE_AUTO_LAYER_MANAGEMENT,
57   VIK_DATASOURCE_INPUTTYPE_NONE,
58   TRUE,
59   TRUE,
60   TRUE,
61   (VikDataSourceInitFunc)               datasource_gps_init_func,
62   (VikDataSourceCheckExistenceFunc)     NULL,
63   (VikDataSourceAddSetupWidgetsFunc)    datasource_gps_add_setup_widgets,
64   (VikDataSourceGetProcessOptionsFunc)  datasource_gps_get_process_options,
65   (VikDataSourceProcessFunc)            a_babel_convert_from,
66   (VikDataSourceProgressFunc)           datasource_gps_progress,
67   (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
68   (VikDataSourceCleanupFunc)            datasource_gps_cleanup,
69   (VikDataSourceOffFunc)                datasource_gps_off,
70
71   NULL,
72   0,
73   NULL,
74   NULL,
75   0
76 };
77
78 /*********************************************************
79  * Definitions and routines for acquiring data from GPS
80  *********************************************************/
81
82 /* widgets in setup dialog specific to GPS */
83 /* widgets in progress dialog specific to GPS */
84 /* also counts needed for progress */
85 typedef struct {
86   /* setup dialog */
87   GtkWidget *proto_l;
88   GtkWidget *proto_b;
89   GtkWidget *ser_l;
90   GtkWidget *ser_b;
91   GtkWidget *off_request_l;
92   GtkCheckButton *off_request_b;
93   GtkWidget *get_tracks_l;
94   GtkCheckButton *get_tracks_b;
95   GtkWidget *get_routes_l;
96   GtkCheckButton *get_routes_b;
97   GtkWidget *get_waypoints_l;
98   GtkCheckButton *get_waypoints_b;
99
100   /* progress dialog */
101   GtkWidget *gps_label;
102   GtkWidget *ver_label;
103   GtkWidget *id_label;
104   GtkWidget *wp_label;
105   GtkWidget *trk_label;
106   GtkWidget *rte_label;
107   GtkWidget *progress_label;
108   vik_gps_xfer_type progress_type;
109
110   /* state */
111   int total_count;
112   int count;
113   // Know which way xfer is so xfer setting types are only stored for download
114   vik_gps_dir direction;
115 } gps_user_data_t;
116
117 #define VIK_SETTINGS_GPS_GET_TRACKS "gps_download_tracks"
118 #define VIK_SETTINGS_GPS_GET_ROUTES "gps_download_routes"
119 #define VIK_SETTINGS_GPS_GET_WAYPOINTS "gps_download_waypoints"
120 #define VIK_SETTINGS_GPS_PROTOCOL "gps_protocol"
121 #define VIK_SETTINGS_GPS_PORT "gps_port"
122 #define VIK_SETTINGS_GPS_POWER_OFF "gps_power_off"
123
124 static gpointer datasource_gps_init_func ( acq_vik_t *avt )
125 {
126   gps_user_data_t *gps_ud = g_malloc (sizeof(gps_user_data_t));
127   gps_ud->direction = GPS_DOWN;
128   return gps_ud;
129 }
130
131 /**
132  * datasource_gps_get_protocol:
133  *
134  * Method to get the communication protocol of the GPS device from the widget structure
135  */
136 gchar* datasource_gps_get_protocol ( gpointer user_data )
137 {
138   // Uses the list of supported devices
139   gps_user_data_t *w = (gps_user_data_t *)user_data;
140   last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
141   if (a_babel_device_list) {
142     gchar *protocol = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
143     a_settings_set_string ( VIK_SETTINGS_GPS_PROTOCOL, protocol );
144     return protocol;
145   }
146
147   return NULL;
148 }
149
150 /**
151  * datasource_gps_get_descriptor:
152  *
153  * Method to get the descriptor from the widget structure
154  * "Everything is a file"
155  * Could actually be normal file or a serial port
156  */
157 gchar* datasource_gps_get_descriptor ( gpointer user_data )
158 {
159   gps_user_data_t *w = (gps_user_data_t *)user_data;
160
161 #if GTK_CHECK_VERSION (2, 24, 0)
162   gchar *descriptor = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
163 #else
164   gchar *descriptor = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
165 #endif
166   a_settings_set_string ( VIK_SETTINGS_GPS_PORT, descriptor );
167   return descriptor;
168 }
169
170 /**
171  * datasource_gps_get_do_tracks:
172  *
173  * Method to get the track handling behaviour from the widget structure
174  */
175 gboolean datasource_gps_get_do_tracks ( gpointer user_data )
176 {
177   gps_user_data_t *w = (gps_user_data_t *)user_data;
178   gboolean get_tracks = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_tracks_b));
179   if ( w->direction == GPS_DOWN )
180     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, get_tracks );
181   return get_tracks;
182 }
183
184 /**
185  * datasource_gps_get_do_routes:
186  *
187  * Method to get the route handling behaviour from the widget structure
188  */
189 gboolean datasource_gps_get_do_routes ( gpointer user_data )
190 {
191   gps_user_data_t *w = (gps_user_data_t *)user_data;
192   gboolean get_routes = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_routes_b));
193   if ( w->direction == GPS_DOWN )
194     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, get_routes );
195   return get_routes;
196 }
197
198 /**
199  * datasource_gps_get_do_waypoints:
200  *
201  * Method to get the waypoint handling behaviour from the widget structure
202  */
203 gboolean datasource_gps_get_do_waypoints ( gpointer user_data )
204 {
205   gps_user_data_t *w = (gps_user_data_t *)user_data;
206   gboolean get_waypoints = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b));
207   if ( w->direction == GPS_DOWN )
208     a_settings_set_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, get_waypoints );
209   return get_waypoints;
210 }
211
212 static void datasource_gps_get_process_options ( gpointer user_data, ProcessOptions *po, gpointer not_used, const gchar *not_used2, const gchar *not_used3 )
213 {
214   char *device = NULL;
215   char *tracks = NULL;
216   char *routes = NULL;
217   char *waypoints = NULL;
218
219   if (gps_acquire_in_progress) {
220     po->babelargs = po->filename = NULL;
221   }
222   
223   gps_acquire_in_progress = TRUE;
224
225   device = datasource_gps_get_protocol ( user_data );
226
227   if ( datasource_gps_get_do_tracks ( user_data ) )
228     tracks = "-t";
229   else
230     tracks = "";
231
232   if ( datasource_gps_get_do_routes ( user_data ) )
233     routes = "-r";
234   else
235     routes = "";
236
237   if ( datasource_gps_get_do_waypoints ( user_data ) )
238     waypoints = "-w";
239   else
240     waypoints = "";
241
242   po->babelargs = g_strdup_printf("-D 9 %s %s %s -i %s", tracks, routes, waypoints, device);
243   /* device points to static content => no free */
244   device = NULL;
245   tracks = NULL;
246   routes = NULL;
247   waypoints = NULL;
248
249   po->filename = g_strdup(datasource_gps_get_descriptor(user_data));
250
251   g_debug(_("using cmd '%s' and file '%s'\n"), po->babelargs, po->filename);
252 }
253
254 /**
255  * datasource_gps_get_off:
256  *
257  * Method to get the off behaviour from the widget structure
258  */
259 gboolean datasource_gps_get_off ( gpointer user_data )
260 {
261   gps_user_data_t *w = (gps_user_data_t *)user_data;
262   gboolean power_off = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w->off_request_b));
263   a_settings_set_boolean ( VIK_SETTINGS_GPS_POWER_OFF, power_off );
264   return power_off;
265 }
266
267 static void datasource_gps_off ( gpointer user_data, gchar **babelargs, gchar **file_descriptor )
268 {
269   char *ser = NULL;
270   char *device = NULL;
271   gps_user_data_t *w = (gps_user_data_t *)user_data;
272
273   if (gps_acquire_in_progress) {
274     *babelargs = *file_descriptor = NULL;
275   }
276
277   /* See if we should turn off the device */
278   if (!datasource_gps_get_off ( user_data )){
279     return;
280   }
281   
282   if (!a_babel_device_list)
283     return;
284   last_active = gtk_combo_box_get_active(GTK_COMBO_BOX(w->proto_b));
285   device = ((BabelDevice*)g_list_nth_data(a_babel_device_list, last_active))->name;
286   if (!strcmp(device, "garmin")) {
287     device = "garmin,power_off";
288   }
289   else if (!strcmp(device, "navilink")) {
290     device = "navilink,power_off";
291   }
292   else {
293     return;
294   }
295
296   *babelargs = g_strdup_printf("-i %s", device);
297   /* device points to static content => no free */
298   device = NULL;
299   
300 #if GTK_CHECK_VERSION (2, 24, 0)
301   ser = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(w->ser_b));
302 #else
303   ser = gtk_combo_box_get_active_text(GTK_COMBO_BOX(w->ser_b));
304 #endif
305   *file_descriptor = g_strdup(ser);
306 }
307
308
309 static void datasource_gps_cleanup ( gpointer user_data )
310 {
311   g_free ( user_data );
312   gps_acquire_in_progress = FALSE;
313 }
314
315 /**
316  * datasource_gps_clean_up:
317  *
318  * External method to tidy up
319  */
320 void datasource_gps_clean_up ( gpointer user_data )
321 {
322   datasource_gps_cleanup ( user_data );
323 }
324
325 static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
326 {
327   gchar *s = NULL;
328   gdk_threads_enter();
329   if (w->running) {
330     gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
331     const gchar *tmp_str;
332     switch (gps_data->progress_type) {
333     case WPT: tmp_str = ngettext("Downloading %d waypoint...", "Downloading %d waypoints...", cnt); gps_data->total_count = cnt; break;
334     case TRK: tmp_str = ngettext("Downloading %d trackpoint...", "Downloading %d trackpoints...", cnt); gps_data->total_count = cnt; break;
335     default:
336       {
337         // Maybe a gpsbabel bug/feature (upto at least v1.4.3 or maybe my Garmin device) but the count always seems x2 too many for routepoints
338         gint mycnt = (cnt / 2) + 1;
339         tmp_str = ngettext("Downloading %d routepoint...", "Downloading %d routepoints...", mycnt);
340         gps_data->total_count = mycnt;
341         break;
342       }
343     }
344     s = g_strdup_printf(tmp_str, cnt);
345     gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
346     gtk_widget_show ( gps_data->progress_label );
347   }
348   g_free(s); s = NULL;
349   gdk_threads_leave();
350 }
351
352 static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
353 {
354   gchar *s = NULL;
355   gdk_threads_enter();
356   if (w->running) {
357     gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
358
359     if (cnt < gps_data->total_count) {
360       switch (gps_data->progress_type) {
361       case WPT: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "waypoints"); break;
362       case TRK: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "trackpoints"); break;
363       default: s = g_strdup_printf(_("Downloaded %d out of %d %s..."), cnt, gps_data->total_count, "routepoints"); break;
364       }
365     } else {
366       switch (gps_data->progress_type) {
367       case WPT: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "waypoints"); break;
368       case TRK: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "trackpoints"); break;
369       default: s = g_strdup_printf(_("Downloaded %d %s."), cnt, "routepoints"); break;
370       }
371     }
372     gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
373   }
374   g_free(s); s = NULL;
375   gdk_threads_leave();
376 }
377
378 static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
379 {
380   gchar *s = NULL;
381   gdk_threads_enter();
382   if (w->running) {
383     s = g_strdup_printf(_("GPS Device: %s"), info);
384     gtk_label_set_text ( GTK_LABEL(((gps_user_data_t *)w->user_data)->gps_label), s );
385   }
386   g_free(s); s = NULL;
387   gdk_threads_leave();
388 }
389
390 /* 
391  * This routine relies on gpsbabel's diagnostic output to display the progress information. 
392  * These outputs differ when different GPS devices are used, so we will need to test
393  * them on several and add the corresponding support.
394  */
395 static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
396 {
397   gchar *line;
398   gps_user_data_t *gps_data = (gps_user_data_t *)w->user_data;
399
400   switch(c) {
401   case BABEL_DIAG_OUTPUT:
402     line = (gchar *)data;
403
404     gdk_threads_enter();
405     if (w->running) {
406       gtk_label_set_text ( GTK_LABEL(w->status), _("Status: Working...") );
407     }
408     gdk_threads_leave();
409
410     /* tells us the type of items that will follow */
411     if (strstr(line, "Xfer Wpt")) {
412       gps_data->progress_label = gps_data->wp_label;
413       gps_data->progress_type = WPT;
414     }
415     if (strstr(line, "Xfer Trk")) {
416       gps_data->progress_label = gps_data->trk_label;
417       gps_data->progress_type = TRK;
418     }
419     if (strstr(line, "Xfer Rte")) {
420       gps_data->progress_label = gps_data->rte_label;
421       gps_data->progress_type = RTE;
422     }
423
424     if (strstr(line, "PRDDAT")) {
425       gchar **tokens = g_strsplit(line, " ", 0);
426       gchar info[128];
427       int ilen = 0;
428       int i;
429       int n_tokens = 0;
430
431       while (tokens[n_tokens])
432         n_tokens++;
433
434       if (n_tokens > 8) {
435         for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
436           guint ch;
437           sscanf(tokens[i], "%x", &ch);
438           info[ilen++] = ch;
439         }
440         info[ilen++] = 0;
441         set_gps_info(info, w);
442       }
443       g_strfreev(tokens);
444     }
445     /* eg: "Unit:\teTrex Legend HCx Software Version 2.90\n" */
446     if (strstr(line, "Unit:")) {
447       gchar **tokens = g_strsplit(line, "\t", 0);
448       int n_tokens = 0;
449       while (tokens[n_tokens])
450         n_tokens++;
451
452       if (n_tokens > 1) {
453         set_gps_info(tokens[1], w);
454       }
455       g_strfreev(tokens);
456     }
457     /* tells us how many items there will be */
458     if (strstr(line, "RECORD")) {
459       int lsb, msb, cnt;
460
461       if (strlen(line) > 20) {
462        sscanf(line+17, "%x", &lsb); 
463        sscanf(line+20, "%x", &msb);
464        cnt = lsb + msb * 256;
465        set_total_count(cnt, w);
466        gps_data->count = 0;
467       }
468     }
469     if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") || strstr(line, "RTEHDR") || strstr(line, "RTEWPT") ) {
470       gps_data->count++;
471       set_current_count(gps_data->count, w);
472     }
473     break;
474   case BABEL_DONE:
475     break;
476   default:
477     break;
478   }
479 }
480
481 void append_element (gpointer elem, gpointer user_data)
482 {
483   const gchar *text = ((BabelDevice*)elem)->label;
484   vik_combo_box_text_append (GTK_WIDGET(user_data), text);
485 }
486
487 static gint find_entry = -1;
488 static gint wanted_entry = -1;
489
490 static void find_protocol (gpointer elem, gpointer user_data)
491 {
492   const gchar *name = ((BabelDevice*)elem)->name;
493   const gchar *protocol = user_data;
494   find_entry++;
495   if (!strcmp(name, protocol)) {
496     wanted_entry = find_entry;
497   }
498 }
499
500 static void datasource_gps_add_setup_widgets ( GtkWidget *dialog, VikViewport *vvp, gpointer user_data )
501 {
502   gps_user_data_t *w = (gps_user_data_t *)user_data;
503   GtkTable *box, *data_type_box;
504
505   w->proto_l = gtk_label_new (_("GPS Protocol:"));
506   w->proto_b = vik_combo_box_text_new ();
507   g_list_foreach (a_babel_device_list, append_element, w->proto_b);
508
509   if ( last_active < 0 ) {
510     find_entry = -1;
511     wanted_entry = -1;
512     gchar *protocol = NULL;
513     if ( a_settings_get_string ( VIK_SETTINGS_GPS_PROTOCOL, &protocol ) ) {
514       // Use setting
515       if ( protocol )
516         g_list_foreach (a_babel_device_list, find_protocol, protocol);
517     }
518     else {
519       // Attempt to maintain default to Garmin devices (assumed most popular/numerous device)
520       g_list_foreach (a_babel_device_list, find_protocol, "garmin");
521     }
522     // If not found set it to the first entry, otherwise use the entry
523     last_active = ( wanted_entry < 0 ) ? 0 : wanted_entry;
524   }
525
526   gtk_combo_box_set_active (GTK_COMBO_BOX(w->proto_b), last_active);
527   g_object_ref(w->proto_b);
528
529   w->ser_l = gtk_label_new (_("Serial Port:"));
530 #if GTK_CHECK_VERSION (2, 24, 0)
531   w->ser_b = gtk_combo_box_text_new_with_entry ();
532 #else
533   w->ser_b = gtk_combo_box_entry_new_text ();
534 #endif
535   // Value from the settings is promoted to the top
536   gchar *gps_port = NULL;
537   if ( a_settings_get_string ( VIK_SETTINGS_GPS_PORT, &gps_port ) ) {
538     // Use setting if available
539     if ( gps_port ) {
540 #ifndef WINDOWS
541       if ( !strncmp (gps_port, "/dev/tty", 6) ) {
542         if (g_access (gps_port, R_OK) == 0) {
543           vik_combo_box_text_append (w->ser_b, gps_port);
544         }
545       }
546       else
547 #endif
548         vik_combo_box_text_append (w->ser_b, gps_port);
549     }
550   }
551
552   // Note avoid appending the port selected from the settings
553 #ifdef WINDOWS
554   if ( gps_port && strcmp (gps_port, "com1") )
555     vik_combo_box_text_append (w->ser_b, "com1");
556 #else
557   /* Here just try to see if the device is available which gets passed onto gpsbabel
558      List USB devices first as these will generally only be present if autogenerated by udev or similar
559      User is still able to set their own free text entry */
560   if ( gps_port && strcmp (gps_port, "/dev/ttyUSB0") )
561     if (g_access ("/dev/ttyUSB0", R_OK) == 0)
562       vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB0");
563   if ( gps_port && strcmp (gps_port, "/dev/ttyUSB1") )
564     if (g_access ("/dev/ttyUSB1", R_OK) == 0)
565       vik_combo_box_text_append (w->ser_b, "/dev/ttyUSB1");
566   if ( gps_port && strcmp (gps_port, "/dev/ttyS0") )
567     if (g_access ("/dev/ttyS0", R_OK) == 0)
568       vik_combo_box_text_append (w->ser_b, "/dev/ttyS0");
569   if ( gps_port && strcmp (gps_port, "/dev/ttyS1") )
570     if (g_access ("/dev/ttyS1", R_OK) == 0)
571       vik_combo_box_text_append (w->ser_b, "/dev/ttyS1");
572 #endif
573   if ( gps_port && strcmp (gps_port, "usb:") )
574     vik_combo_box_text_append (w->ser_b, "usb:");
575
576   gtk_combo_box_set_active (GTK_COMBO_BOX(w->ser_b), 0);
577   g_object_ref(w->ser_b);
578
579   w->off_request_l = gtk_label_new (_("Turn Off After Transfer\n(Garmin/NAViLink Only)"));
580   w->off_request_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
581   gboolean power_off;
582   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_POWER_OFF, &power_off ) )
583     power_off = FALSE;
584   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->off_request_b), power_off);
585
586   w->get_tracks_l = gtk_label_new (_("Tracks:"));
587   w->get_tracks_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
588   gboolean get_tracks;
589   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_TRACKS, &get_tracks ) )
590     get_tracks = TRUE;
591   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_tracks_b), get_tracks);
592
593   w->get_routes_l = gtk_label_new (_("Routes:"));
594   w->get_routes_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
595   gboolean get_routes;
596   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_ROUTES, &get_routes ) )
597     get_routes = FALSE;
598   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_routes_b), get_routes);
599
600   w->get_waypoints_l = gtk_label_new (_("Waypoints:"));
601   w->get_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () );
602   gboolean get_waypoints;
603   if ( ! a_settings_get_boolean ( VIK_SETTINGS_GPS_GET_WAYPOINTS, &get_waypoints ) )
604     get_waypoints = TRUE;
605   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w->get_waypoints_b), get_waypoints);
606
607   box = GTK_TABLE(gtk_table_new(2, 4, FALSE));
608   data_type_box = GTK_TABLE(gtk_table_new(4, 1, FALSE));
609
610   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_l), 0, 1, 0, 1);
611   gtk_table_attach_defaults(box, GTK_WIDGET(w->proto_b), 1, 2, 0, 1);
612   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_l), 0, 1, 1, 2);
613   gtk_table_attach_defaults(box, GTK_WIDGET(w->ser_b), 1, 2, 1, 2);
614   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_l), 0, 1, 0, 1);
615   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_tracks_b), 1, 2, 0, 1);
616   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_l), 2, 3, 0, 1);
617   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_routes_b), 3, 4, 0, 1);
618   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_l), 4, 5, 0, 1);
619   gtk_table_attach_defaults(data_type_box, GTK_WIDGET(w->get_waypoints_b), 5, 6, 0, 1);
620   gtk_table_attach_defaults(box, GTK_WIDGET(data_type_box), 0, 2, 2, 3);
621   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_l), 0, 1, 3, 4);
622   gtk_table_attach_defaults(box, GTK_WIDGET(w->off_request_b), 1, 3, 3, 4);
623   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
624
625   gtk_widget_show_all ( dialog );
626 }
627
628 /**
629  * datasource_gps_setup:
630  * @dialog: The GTK dialog. The caller is responsible for managing the dialog creation/deletion
631  * @xfer: The default type of items enabled for transfer, others disabled.
632  * @xfer_all: When specified all items are enabled for transfer.
633  *
634  * Returns: A gpointer to the private structure for GPS progress/information widgets
635  *          Pass this pointer back into the other exposed datasource_gps_X functions
636  */
637 gpointer datasource_gps_setup ( GtkWidget *dialog, vik_gps_xfer_type xfer, gboolean xfer_all )
638 {
639   gps_user_data_t *w_gps = (gps_user_data_t *)datasource_gps_init_func ( NULL );
640   w_gps->direction = GPS_UP;
641   datasource_gps_add_setup_widgets ( dialog, NULL, w_gps );
642
643   gboolean way = xfer_all;
644   gboolean trk = xfer_all;
645   gboolean rte = xfer_all;
646
647   // Selectively turn bits on
648   if ( !xfer_all ) {
649     switch (xfer) {
650     case WPT: way = TRUE; break;
651     case RTE: rte = TRUE; break;
652     default: trk = TRUE; break;
653     }
654   }
655
656   // Apply
657   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_tracks_b), trk );
658   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_l), trk );
659   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_tracks_b), trk );
660
661   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_routes_b), rte );
662   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_l), rte );
663   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_routes_b), rte );
664
665   gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(w_gps->get_waypoints_b), way );
666   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_l), way );
667   gtk_widget_set_sensitive ( GTK_WIDGET(w_gps->get_waypoints_b), way );
668
669   return (gpointer)w_gps;
670 }
671
672 void datasource_gps_add_progress_widgets ( GtkWidget *dialog, gpointer user_data )
673 {
674   GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel, *rtelabel;
675
676   gps_user_data_t *w_gps = (gps_user_data_t *)user_data;
677
678   gpslabel = gtk_label_new (_("GPS device: N/A"));
679   verlabel = gtk_label_new ("");
680   idlabel = gtk_label_new ("");
681   wplabel = gtk_label_new ("");
682   trklabel = gtk_label_new ("");
683   rtelabel = gtk_label_new ("");
684
685   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), gpslabel, FALSE, FALSE, 5 );
686   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), wplabel, FALSE, FALSE, 5 );
687   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), trklabel, FALSE, FALSE, 5 );
688   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), rtelabel, FALSE, FALSE, 5 );
689
690   gtk_widget_show_all ( dialog );
691
692   w_gps->gps_label = gpslabel;
693   w_gps->id_label = idlabel;
694   w_gps->ver_label = verlabel;
695   w_gps->progress_label = w_gps->wp_label = wplabel;
696   w_gps->trk_label = trklabel;
697   w_gps->rte_label = rtelabel;
698   w_gps->total_count = -1;
699 }