+2005-11-25
+ * Created "data sources" structure to easily add new data sources via GPS babel.
+ It's ugly now and there's a lot to be done, but I think 79-line datasources_google.c
+ shows the power of the approach.
+
2005-11-23 Guilhem BONNEFILLE <guilhem.bonnefille@gmail.com>
* src/gpx.c (gpx_dtostr): add better GPX export
Evan Battaglia <gtoevan@gmx.net>:
acquire crashes, sometimes (???)
google maps download stops (try auto-download), extra processes in background doing nothing
GPSBABEL!!!
- * Google (address -> WP and directions -> track)
- * Geotoad
+ * Smooth over rough edges / ugliness / crashes
+ * Google address -> WP
+ * handling of special characters (both to wget/HTTP and shell) -- don't allow backdoor tricks
+ * ADD to a layer instead of make a new layer (maybe right click layer -> new track from Google or something)
* Filter a TRW layer: simplify paths, get out waypoints inside a path, etc.
+ * Geotoad
FEATURES:
Paste GPX files into Viking -> TRW Layer
gpx.c gpx.h \
garminsymbols.c garminsymbols.h \
acquire.c acquire.h \
- babel.c babel.h
+ babel.c babel.h \
+ datasource_gps.c \
+ datasource_google.c \
+ datasources.h
INCLUDES = @GTK_CFLAGS@
LDADD = @GTK_LIBS@
#include "viking.h"
#include "babel.h"
#include "gpx.h"
+#include "acquire.h"
-/*********************************************************
- * Definitions and routines for acquiring data from GPS
- *********************************************************/
-
-/* global data structure used to expose the progress dialog to the worker thread */
+/* passed along to worker thread */
typedef struct {
- VikWindow *vw;
- VikLayersPanel *vlp;
- VikViewport *vvp;
- GtkWidget *dialog;
- GtkWidget *status;
- GtkWidget *gps_label;
- GtkWidget *ver_label;
- GtkWidget *id_label;
- GtkWidget *wp_label;
- GtkWidget *trk_label;
- GtkWidget *progress_label;
- gboolean ok;
-} acq_dialog_widgets_t;
-
-acq_dialog_widgets_t *w = NULL;
-int total_count = -1;
-int count;
-
-static void set_total_count(gint cnt)
-{
- gchar s[128];
- gdk_threads_enter();
- if (w->ok) {
- g_sprintf(s, "Downloading %d %s...", cnt, (w->progress_label == w->wp_label) ? "waypoints" : "trackpoints");
- gtk_label_set_text ( GTK_LABEL(w->progress_label), s );
- gtk_widget_show ( w->progress_label );
- total_count = cnt;
- }
- gdk_threads_leave();
-}
-
-static void set_current_count(gint cnt)
-{
- gchar s[128];
- gdk_threads_enter();
- if (w->ok) {
- if (cnt < total_count) {
- g_sprintf(s, "Downloaded %d out of %d %s...", cnt, total_count, (w->progress_label == w->wp_label) ? "waypoints" : "trackpoints");
- } else {
- g_sprintf(s, "Downloaded %d %s.", cnt, (w->progress_label == w->wp_label) ? "waypoints" : "trackpoints");
- }
- gtk_label_set_text ( GTK_LABEL(w->progress_label), s );
- }
- gdk_threads_leave();
-}
+ acq_dialog_widgets_t *w;
+ VikDataSourceInterface *interface;
+ gchar *cmd;
+ gchar *extra;
+} w_and_interface_t;
-static void set_gps_info(const gchar *info)
-{
- gchar s[256];
- gdk_threads_enter();
- if (w->ok) {
- g_sprintf(s, "GPS Device: %s", info);
- gtk_label_set_text ( GTK_LABEL(w->gps_label), s );
- }
- gdk_threads_leave();
-}
+extern VikDataSourceInterface vik_datasource_gps_interface;
+extern VikDataSourceInterface vik_datasource_google_interface;
-/*
- * This routine relies on gpsbabel's diagnostic output to display the progress information.
- * These outputs differ when different GPS devices are used, so we will need to test
- * them on several and add the corresponding support.
- */
-static void progress_func ( BabelProgressCode c, gpointer data )
-{
- gchar *line;
-
- switch(c) {
- case BABEL_DIAG_OUTPUT:
- line = (gchar *)data;
-
- /* tells us how many items there will be */
- if (strstr(line, "Xfer Wpt")) {
- w->progress_label = w->wp_label;
- }
- if (strstr(line, "Xfer Trk")) {
- w->progress_label = w->trk_label;
- }
- if (strstr(line, "PRDDAT")) {
- gchar **tokens = g_strsplit(line, " ", 0);
- gchar info[128];
- int ilen = 0;
- int i;
-
- for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
- guint ch;
- sscanf(tokens[i], "%x", &ch);
- info[ilen++] = ch;
- }
- info[ilen++] = 0;
- set_gps_info(info);
- }
- if (strstr(line, "RECORD")) {
- int lsb, msb, cnt;
-
- sscanf(line+17, "%x", &lsb);
- sscanf(line+20, "%x", &msb);
- cnt = lsb + msb * 256;
- set_total_count(cnt);
- count = 0;
- }
- if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
- count++;
- set_current_count(count);
- }
- break;
- case BABEL_DONE:
- break;
- default:
- break;
- }
-}
+/*********************************************************
+ * Definitions and routines for acquiring data from GPS
+ *********************************************************/
/* this routine is the worker thread. there is only one simultaneous download allowed */
-static void get_from_gps ( gpointer data )
+static void get_from_anything ( w_and_interface_t *wi )
{
VikTrwLayer *vtl;
-
- if ( w ) {
- /* simultaneous downloads are not allowed, so we return. */
- g_free(data);
- g_thread_exit ( NULL );
- return;
- }
- w = data;
+ gchar *cmd = wi->cmd;
+ gchar *extra = wi->extra;
+ gboolean result;
+
+ acq_dialog_widgets_t *w = wi->w;
+ VikDataSourceInterface *interface = wi->interface;
+ g_free ( wi );
gdk_threads_enter();
vtl = VIK_TRW_LAYER ( vik_layer_create ( VIK_LAYER_TRW, w->vvp, NULL, FALSE ) );
- vik_layer_rename ( VIK_LAYER ( vtl ), "Acquired from GPS" );
+ vik_layer_rename ( VIK_LAYER ( vtl ), interface->layer_title );
gtk_label_set_text ( GTK_LABEL(w->status), "Working..." );
gdk_threads_leave();
- if (!a_babel_convert_from (vtl, "-D 9 -t -w -i garmin", progress_func, "/dev/ttyS0")) {
-// if (!a_babel_convert_from (vtl, "-D 9 -t -w -i garmin", progress_func, "/dev/ttyS1")) {
-// if (!a_babel_convert_from_shellcommand (vtl, "(wget -O - \"http://maps.google.com/maps?q=91214 to 94704&output=xml\" 2>/dev/null) | cat ~/vik/tools/temp.ggl | head -3 | tail -1 | sed 's/.*<page>\\(.*\\)<\\/page>.*/<page>\\1<\\/page>/'", "google", progress_func)) {
+ if ( interface->type == VIK_DATASOURCE_GPSBABEL_DIRECT )
+ result = a_babel_convert_from (vtl, cmd, (BabelStatusFunc) interface->progress_func, extra, w);
+ else
+ result = a_babel_convert_from_shellcommand ( vtl, cmd, extra, (BabelStatusFunc) interface->progress_func, w);
+
+ g_free ( cmd );
+ g_free ( extra );
+
+ if (!result) {
gdk_threads_enter();
gtk_label_set_text ( GTK_LABEL(w->status), "Error: couldn't find gpsbabel." );
gdk_threads_leave();
gtk_dialog_set_response_sensitive ( GTK_DIALOG(w->dialog), GTK_RESPONSE_ACCEPT, TRUE );
gtk_dialog_set_response_sensitive ( GTK_DIALOG(w->dialog), GTK_RESPONSE_REJECT, FALSE );
} else {
+ /* canceled */
g_object_unref(vtl);
}
- g_free ( w );
- w = NULL;
+
+ if ( interface->cleanup_func )
+ interface->cleanup_func ( w->specific_data );
+
+ if ( w->ok ) {
+ w->ok = FALSE;
+ } else {
+ g_free ( w );
+ }
+
gdk_threads_leave();
g_thread_exit ( NULL );
}
-void a_acquire_from_gps ( VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp )
+
+void a_acquire ( VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp, VikDataSourceInterface *interface )
{
- GtkWidget *status, *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
GtkWidget *dialog = NULL;
- acq_dialog_widgets_t *w = g_malloc(sizeof(*w));
+ GtkWidget *status;
+ gchar *cmd, *extra;
+ acq_dialog_widgets_t *w;
+
+ w_and_interface_t *wi;
+
+ if ( interface->add_widgets_func ) {
+ gpointer first_dialog_data;
+ dialog = gtk_dialog_new_with_buttons ( "", NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
+ first_dialog_data = interface->add_widgets_func(dialog);
+ if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
+ interface->first_cleanup_func(first_dialog_data);
+ gtk_widget_destroy(dialog);
+ return;
+ }
+ interface->get_cmd_string_func ( first_dialog_data, &cmd, &extra );
+ interface->first_cleanup_func(first_dialog_data);
+ gtk_widget_destroy(dialog);
+ dialog = NULL;
+ } else
+ interface->get_cmd_string_func ( NULL, &cmd, &extra );
+
+ if ( ! cmd )
+ return;
+
+ w = g_malloc(sizeof(*w));
+ wi = g_malloc(sizeof(*wi));
+ wi->w = w;
+ wi->interface = interface;
+ wi->cmd = cmd;
+ wi->extra = extra;
dialog = gtk_dialog_new_with_buttons ( "", NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
gtk_dialog_set_response_sensitive ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT, FALSE );
- status = gtk_label_new ("Status: detecting gpsbabel");
- gpslabel = gtk_label_new ("GPS device: N/A");
- verlabel = gtk_label_new ("Version: N/A");
- idlabel = gtk_label_new ("ID: N/A");
- wplabel = gtk_label_new ("WP");
- trklabel = gtk_label_new ("TRK");
-
- gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), status, FALSE, FALSE, 5 );
- gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gpslabel, FALSE, FALSE, 5 );
- gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), wplabel, FALSE, FALSE, 5 );
- gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), trklabel, FALSE, FALSE, 5 );
-
- gtk_window_set_title ( GTK_WINDOW(dialog), "Acquire data from GPS" );
-
- gtk_widget_show ( status );
- gtk_widget_show ( gpslabel );
- gtk_widget_show ( dialog );
w->dialog = dialog;
+ w->ok = TRUE;
+
+ status = gtk_label_new ("Status: detecting gpsbabel");
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), status, FALSE, FALSE, 5 );
+ gtk_widget_show_all(status);
w->status = status;
- w->gps_label = gpslabel;
- w->id_label = idlabel;
- w->ver_label = verlabel;
- w->progress_label = w->wp_label = wplabel;
- w->trk_label = trklabel;
+
w->vw = vw;
w->vlp = vlp;
w->vvp = vvp;
- w->ok = TRUE;
- g_thread_create((GThreadFunc)get_from_gps, w, FALSE, NULL );
+ if ( interface->add_progress_widgets_func )
+ w->specific_data = interface->add_progress_widgets_func ( dialog );
+ else
+ w->specific_data = NULL;
+
+ g_thread_create((GThreadFunc)get_from_anything, wi, FALSE, NULL );
gtk_dialog_run ( GTK_DIALOG(dialog) );
- w->ok = FALSE;
+ if ( w->ok )
+ w->ok = FALSE; /* tell thread to stop. TODO: add mutex */
+ else {
+ g_free ( w ); /* thread has finished; free w */
+ }
gtk_widget_destroy ( dialog );
}
+
#ifndef _VIKING_ACQUIRE_H
#define _VIKING_ACQUIRE_H
-void a_acquire_from_gps ( VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp );
+/* global data structure used to expose the progress dialog to the worker thread */
+typedef struct {
+ GtkWidget *status;
+ VikWindow *vw;
+ VikLayersPanel *vlp;
+ VikViewport *vvp;
+ GtkWidget *dialog;
+ gboolean ok; /* if OK is false when we exit, we MUST free w */
+ gpointer specific_data;
+} acq_dialog_widgets_t;
+
+typedef enum { VIK_DATASOURCE_GPSBABEL_DIRECT, VIK_DATASOURCE_SHELL_CMD } vik_datasource_type_t;
+
+typedef gpointer (*VikDataSourceAddWidgetsFunc) ( GtkWidget *dialog );
+
+/* if VIK_DATASOURCE_GPSBABEL_DIRECT, babelargs and inputfile.
+ if VIK_DATASOURCE_SHELL_CMD, shellcmd and inputtype.
+ set both to NULL to signal refusal (ie already downloading) */
+typedef void (*VikDataSourceGetCmdStringFunc) ( gpointer widgets_data, gchar **babelargs_or_shellcmd, gchar **inputfile_or_inputtype );
+typedef void (*VikDataSourceFirstCleanupFunc) ( gpointer widgets_data );
+typedef void (*VikDataSourceProgressFunc) (gpointer c, gpointer data, acq_dialog_widgets_t *w);
+typedef gpointer (*VikDataSourceAddProgressWidgetsFunc) ( GtkWidget *dialog );
+typedef void (*VikDataSourceCleanupFunc) ( gpointer progress_widgets_data );
+
+typedef struct {
+ const gchar *layer_title;
+ vik_datasource_type_t type;
+
+ VikDataSourceAddWidgetsFunc add_widgets_func; /* NULL if no first dialog */
+ VikDataSourceGetCmdStringFunc get_cmd_string_func; /* passed rv from above */
+ VikDataSourceFirstCleanupFunc first_cleanup_func; /* frees rv from addwidgets */
+
+ VikDataSourceProgressFunc progress_func;
+ VikDataSourceAddProgressWidgetsFunc add_progress_widgets_func;
+ VikDataSourceCleanupFunc cleanup_func;
+} VikDataSourceInterface;
+
+
+void a_acquire ( VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp, VikDataSourceInterface *interface );
#endif
/* in the future we could have support for other shells (change command strings), or not use a shell at all */
#define BASH_LOCATION "/bin/bash"
-gboolean a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb )
+gboolean a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, gpointer user_data )
{
int fd_src;
FILE *f;
f = fdopen(fd_src, "w");
a_gpx_write_file(vt, f);
fclose(f);
- ret = a_babel_convert_from ( vt, bargs, cb, name_src );
+ ret = a_babel_convert_from ( vt, bargs, cb, name_src, user_data );
}
g_free(bargs);
return ret;
}
-gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst )
+gboolean babel_general_convert_from( VikTrwLayer *vt, BabelStatusFunc cb, gchar **args, const gchar *name_dst, gpointer user_data )
{
gboolean ret;
GPid pid;
setvbuf(diag, NULL, _IONBF, 0);
while (fgets(line, sizeof(line), diag)) {
- cb(BABEL_DIAG_OUTPUT, line);
+ if ( cb )
+ cb(BABEL_DIAG_OUTPUT, line, user_data);
}
- cb(BABEL_DONE, NULL);
+ if ( cb )
+ cb(BABEL_DONE, NULL, user_data);
fclose(diag);
waitpid(pid, NULL, 0);
g_spawn_close_pid(pid);
return ret;
}
-gboolean a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *from )
+gboolean a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *from, gpointer user_data )
{
int fd_dst;
gchar *name_dst;
g_strlcat(cmd, name_dst, sizeof(cmd));
args = g_strsplit(cmd, " ", 0);
- ret = babel_general_convert_from ( vt, cb, args, name_dst );
+ ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
g_strfreev(args);
}
return ret;
}
-gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_type, BabelStatusFunc cb )
+gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_type, BabelStatusFunc cb, gpointer user_data )
{
int fd_dst;
gchar *name_dst;
args[2] = shell_command;
args[3] = NULL;
- ret = babel_general_convert_from ( vt, cb, args, name_dst );
+ ret = babel_general_convert_from ( vt, cb, args, name_dst, user_data );
g_free ( args );
g_free ( shell_command );
}
BABEL_DONE,
} BabelProgressCode;
-typedef void (*BabelStatusFunc)(BabelProgressCode, gpointer);
+typedef void (*BabelStatusFunc)(BabelProgressCode, gpointer, gpointer);
/*
* a_babel_convert modifies data in a trw layer using gpsbabel filters. This routine is synchronous;
* BABEL_DIAG_DONE: gpsbabel finished,
* or NULL if no callback is needed.
*/
-int a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb );
+int a_babel_convert( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, gpointer user_data );
/*
* a_babel_convert_from loads data into a trw layer from a file, using gpsbabel. This routine is synchronous;
*
* cb Optional callback function. Same usage as in a_babel_convert.
*/
-int a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *file );
-gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_type, BabelStatusFunc cb );
+int a_babel_convert_from( VikTrwLayer *vt, const char *babelargs, BabelStatusFunc cb, const char *file, gpointer user_data );
+gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_cmd, const char *input_type, BabelStatusFunc cb, gpointer user_data );
#endif
--- /dev/null
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <string.h>
+#include <glib/gprintf.h>
+
+#include "viking.h"
+#include "babel.h"
+#include "gpx.h"
+#include "acquire.h"
+
+#define GOOGLE_DIRECTIONS_STRING "(wget -O - \"http://maps.google.com/maps?q=%s to %s&output=xml\" 2>/dev/null) | head -3 | tail -1 | sed 's/.*<page>\\(.*\\)<\\/page>.*/<page>\\1<\\/page>/'"
+
+typedef struct {
+ GtkWidget *from_entry, *to_entry;
+} datasource_google_widgets_t;
+
+
+gpointer datasource_google_add_widgets ( GtkWidget *dialog );
+static void datasource_google_get_cmd_string ( datasource_google_widgets_t *widgets, gchar **cmd, gchar **input_type );
+static void datasource_google_first_cleanup ( gpointer data );
+
+VikDataSourceInterface vik_datasource_google_interface = {
+ "Acquire from Google",
+ VIK_DATASOURCE_SHELL_CMD,
+ (VikDataSourceAddWidgetsFunc) datasource_google_add_widgets,
+ (VikDataSourceGetCmdStringFunc) datasource_google_get_cmd_string,
+ (VikDataSourceFirstCleanupFunc) datasource_google_first_cleanup,
+ (VikDataSourceProgressFunc) NULL,
+ (VikDataSourceAddProgressWidgetsFunc) NULL,
+ (VikDataSourceCleanupFunc) NULL
+};
+
+
+gpointer datasource_google_add_widgets ( GtkWidget *dialog )
+{
+ datasource_google_widgets_t *widgets = g_malloc(sizeof(*widgets));
+ GtkWidget *from_label, *to_label;
+ from_label = gtk_label_new ("From:");
+ widgets->from_entry = gtk_entry_new();
+ to_label = gtk_label_new ("To:");
+ widgets->to_entry = gtk_entry_new();
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), from_label, FALSE, FALSE, 5 );
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), widgets->from_entry, FALSE, FALSE, 5 );
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), to_label, FALSE, FALSE, 5 );
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), widgets->to_entry, FALSE, FALSE, 5 );
+ gtk_widget_show_all(dialog);
+ return widgets;
+}
+
+static void datasource_google_get_cmd_string ( datasource_google_widgets_t *widgets, gchar **cmd, gchar **input_type )
+{
+ /* TODO: special characters handling!!! */
+ *cmd = g_strdup_printf( GOOGLE_DIRECTIONS_STRING, gtk_entry_get_text ( GTK_ENTRY(widgets->from_entry) ), gtk_entry_get_text ( GTK_ENTRY(widgets->to_entry) ) );
+ *input_type = g_strdup("google");
+
+}
+
+static void datasource_google_first_cleanup ( gpointer data )
+{
+ g_free ( data );
+}
--- /dev/null
+/*
+ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
+ *
+ * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <string.h>
+#include <glib/gprintf.h>
+
+#include "viking.h"
+#include "babel.h"
+#include "gpx.h"
+#include "acquire.h"
+
+static gboolean gps_acquire_in_progress = FALSE;
+
+static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file );
+static void datasource_gps_cleanup ( gpointer data );
+static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w );
+gpointer datasource_gps_add_progress_widgets ( GtkWidget *dialog );
+
+VikDataSourceInterface vik_datasource_gps_interface = {
+ "Acquire from GPS",
+ VIK_DATASOURCE_GPSBABEL_DIRECT,
+ (VikDataSourceAddWidgetsFunc) NULL,
+ (VikDataSourceGetCmdStringFunc) datasource_gps_get_cmd_string,
+ (VikDataSourceFirstCleanupFunc) NULL,
+ (VikDataSourceProgressFunc) datasource_gps_progress,
+ (VikDataSourceAddProgressWidgetsFunc) datasource_gps_add_progress_widgets,
+ (VikDataSourceCleanupFunc) datasource_gps_cleanup
+};
+
+/*********************************************************
+ * Definitions and routines for acquiring data from GPS
+ *********************************************************/
+
+/* widgets in progress dialog specific to GPS */
+/* also counts needed for progress */
+typedef struct {
+ GtkWidget *gps_label;
+ GtkWidget *ver_label;
+ GtkWidget *id_label;
+ GtkWidget *wp_label;
+ GtkWidget *trk_label;
+ GtkWidget *progress_label;
+ int total_count;
+ int count;
+} gps_acq_dialog_widgets_t;
+
+static void datasource_gps_get_cmd_string ( gpointer add_widgets_data_not_used, gchar **babelargs, gchar **input_file )
+{
+ if (gps_acquire_in_progress) {
+ *babelargs = *input_file = NULL;
+ }
+
+ gps_acquire_in_progress = TRUE;
+ *babelargs = g_strdup_printf("%s", "-D 9 -t -w -i garmin");
+ *input_file = g_strdup_printf("%s", "/dev/ttyS1" );
+}
+
+static void datasource_gps_cleanup ( gpointer data )
+{
+ g_free ( data );
+ gps_acquire_in_progress = FALSE;
+}
+
+static void set_total_count(gint cnt, acq_dialog_widgets_t *w)
+{
+ gchar s[128];
+ gdk_threads_enter();
+ if (w->ok) {
+ gps_acq_dialog_widgets_t *gps_data = (gps_acq_dialog_widgets_t *)w->specific_data;
+ g_sprintf(s, "Downloading %d %s...", cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
+ gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
+ gtk_widget_show ( gps_data->progress_label );
+ gps_data->total_count = cnt;
+ }
+ gdk_threads_leave();
+}
+
+static void set_current_count(gint cnt, acq_dialog_widgets_t *w)
+{
+ gchar s[128];
+ gdk_threads_enter();
+ if (w->ok) {
+ gps_acq_dialog_widgets_t *gps_data = (gps_acq_dialog_widgets_t *)w->specific_data;
+
+ if (cnt < gps_data->total_count) {
+ g_sprintf(s, "Downloaded %d out of %d %s...", cnt, gps_data->total_count, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
+ } else {
+ g_sprintf(s, "Downloaded %d %s.", cnt, (gps_data->progress_label == gps_data->wp_label) ? "waypoints" : "trackpoints");
+ }
+ gtk_label_set_text ( GTK_LABEL(gps_data->progress_label), s );
+ }
+ gdk_threads_leave();
+}
+
+static void set_gps_info(const gchar *info, acq_dialog_widgets_t *w)
+{
+ gchar s[256];
+ gdk_threads_enter();
+ if (w->ok) {
+ g_sprintf(s, "GPS Device: %s", info);
+ gtk_label_set_text ( GTK_LABEL(((gps_acq_dialog_widgets_t *)w->specific_data)->gps_label), s );
+ }
+ gdk_threads_leave();
+}
+
+/*
+ * This routine relies on gpsbabel's diagnostic output to display the progress information.
+ * These outputs differ when different GPS devices are used, so we will need to test
+ * them on several and add the corresponding support.
+ */
+static void datasource_gps_progress ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
+{
+ gchar *line;
+ gps_acq_dialog_widgets_t *gps_data = (gps_acq_dialog_widgets_t *)w->specific_data;
+
+ /* TODO: move to datasource.c */
+ gdk_threads_enter ();
+ if (!w->ok) {
+ g_free ( w );
+ w = NULL;
+ gps_acquire_in_progress = FALSE;
+ gdk_threads_leave();
+ g_thread_exit ( NULL );
+ }
+ gdk_threads_leave ();
+
+ switch(c) {
+ case BABEL_DIAG_OUTPUT:
+ line = (gchar *)data;
+
+ /* tells us how many items there will be */
+ if (strstr(line, "Xfer Wpt")) {
+ gps_data->progress_label = gps_data->wp_label;
+ }
+ if (strstr(line, "Xfer Trk")) {
+ gps_data->progress_label = gps_data->trk_label;
+ }
+ if (strstr(line, "PRDDAT")) {
+ gchar **tokens = g_strsplit(line, " ", 0);
+ gchar info[128];
+ int ilen = 0;
+ int i;
+
+ for (i=8; tokens[i] && ilen < sizeof(info)-2 && strcmp(tokens[i], "00"); i++) {
+ guint ch;
+ sscanf(tokens[i], "%x", &ch);
+ info[ilen++] = ch;
+ }
+ info[ilen++] = 0;
+ set_gps_info(info, w);
+ }
+ if (strstr(line, "RECORD")) {
+ int lsb, msb, cnt;
+
+ sscanf(line+17, "%x", &lsb);
+ sscanf(line+20, "%x", &msb);
+ cnt = lsb + msb * 256;
+ set_total_count(cnt, w);
+ gps_data->count = 0;
+ }
+ if ( strstr(line, "WPTDAT") || strstr(line, "TRKHDR") || strstr(line, "TRKDAT") ) {
+ gps_data->count++;
+ set_current_count(gps_data->count, w);
+ }
+ break;
+ case BABEL_DONE:
+ break;
+ default:
+ break;
+ }
+}
+
+gpointer datasource_gps_add_progress_widgets ( GtkWidget *dialog )
+{
+ GtkWidget *gpslabel, *verlabel, *idlabel, *wplabel, *trklabel;
+
+ gps_acq_dialog_widgets_t *w_gps = g_malloc(sizeof(*w_gps));
+
+ gpslabel = gtk_label_new ("GPS device: N/A");
+ verlabel = gtk_label_new ("");
+ idlabel = gtk_label_new ("");
+ wplabel = gtk_label_new ("");
+ trklabel = gtk_label_new ("");
+
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gpslabel, FALSE, FALSE, 5 );
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), wplabel, FALSE, FALSE, 5 );
+ gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), trklabel, FALSE, FALSE, 5 );
+
+ gtk_window_set_title ( GTK_WINDOW(dialog), "Acquire data from GPS" );
+
+ gtk_widget_show_all ( dialog );
+
+ w_gps->gps_label = gpslabel;
+ w_gps->id_label = idlabel;
+ w_gps->ver_label = verlabel;
+ w_gps->progress_label = w_gps->wp_label = wplabel;
+ w_gps->trk_label = trklabel;
+ w_gps->total_count = -1;
+ return w_gps;
+}
--- /dev/null
+#ifndef __VIK_DATASOURCES_H
+#define __VIK_DATASOURCES_H
+extern VikDataSourceInterface vik_datasource_gps_interface;
+extern VikDataSourceInterface vik_datasource_google_interface;
+#endif
" <menuitem action='New'/>"
" <menuitem action='Open'/>"
" <menuitem action='Append'/>"
- " <menuitem action='Acquire'/>"
" <menuitem action='Save'/>"
" <menuitem action='SaveAs'/>"
" <separator/>"
+ " <menu action='Acquire'>"
+ " <menuitem action='AcquireGPS'/>"
+ " <menuitem action='AcquireGoogle'/>"
+ " </menu>"
+ " <separator/>"
" <menuitem action='GenImg'/>"
" <menuitem action='GenImgDir'/>"
" <separator/>"
#include "viking.h"
#include "background.h"
#include "acquire.h"
+#include "datasources.h"
#define VIKING_TITLE " - Viking " VIKING_VERSION " " VIKING_VERSION_NAME " " VIKING_URL
static void acquire_from_gps ( GtkAction *a, VikWindow *vw )
{
- a_acquire_from_gps(vw, vw->viking_vlp, vw->viking_vvp );
+ a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface );
+}
+
+static void acquire_from_google ( GtkAction *a, VikWindow *vw )
+{
+ a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_google_interface );
}
static void clear_cb ( GtkAction *a, VikWindow *vw )
{ "New", GTK_STOCK_NEW, "_New", "<control>N", "New file", (GCallback)newwindow_cb },
{ "Open", GTK_STOCK_OPEN, "_Open", "<control>O", "Open a file", (GCallback)load_file },
{ "Append", GTK_STOCK_ADD, "A_ppend File", NULL, "Append data from a different file", (GCallback)load_file },
- { "Acquire", NULL, "A_cquire from GPS", NULL, "Transfer data from a GPS device", (GCallback)acquire_from_gps },
+ { "Acquire", NULL, "A_cquire", 0, 0, 0 },
+ { "AcquireGPS", NULL, "From _GPS", NULL, "Transfer data from a GPS device", (GCallback)acquire_from_gps },
+ { "AcquireGoogle", NULL, "Google _Directions", NULL, "Get driving directions from Google", (GCallback)acquire_from_google },
{ "Save", GTK_STOCK_SAVE, "_Save", "<control>S", "Save the file", (GCallback)save_file },
{ "SaveAs", GTK_STOCK_SAVE_AS, "Save _As", NULL, "Save the file under different name", (GCallback)save_file_as },
{ "GenImg", GTK_STOCK_CLEAR, "_Generate Image File", NULL, "Save a snapshot of the workspace into a file", (GCallback)draw_to_image_file_cb },