]> git.street.me.uk Git - andy/viking.git/blobdiff - src/acquire.c
Fix intermittent problem of map redraw.
[andy/viking.git] / src / acquire.c
index 1da404c96fdd9c03afd73869c162002fcc48e489..1c47a151333d16bcc10a8685e28d58f643a6f30f 100644 (file)
 #include "viking.h"
 #include "babel.h"
 #include "gpx.h"
+#include "acquire.h"
+
+/* passed along to worker thread */
+typedef struct {
+  acq_dialog_widgets_t *w;
+  gchar *cmd;
+  gchar *extra;
+} w_and_interface_t;
+
+extern VikDataSourceInterface vik_datasource_gps_interface;
+extern VikDataSourceInterface vik_datasource_google_interface;
 
 /*********************************************************
- * Definitions and routines for acquiring data from GPS
+ * Definitions and routines for acquiring data from Data Sources in general
  *********************************************************/
 
-/* global data structure used to expose the progress dialog to the 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)
+static void progress_func ( BabelProgressCode c, gpointer data, acq_dialog_widgets_t *w )
 {
-  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_enter ();
+  if (!w->ok) {
+    if ( w->interface->cleanup_func )
+      w->interface->cleanup_func( w->user_data );
+    g_free ( w );
+    gdk_threads_leave();
+    g_thread_exit ( NULL );
   }
-  gdk_threads_leave();
-}
+  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();
+  if ( w->interface->progress_func )
+    w->interface->progress_func ( (gpointer) c, data, w );
 }
 
-static void set_gps_info(const gchar *info)
+/* this routine is the worker thread.  there is only one simultaneous download allowed */
+static void get_from_anything ( w_and_interface_t *wi )
 {
-  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();
-}
+  gchar *cmd = wi->cmd;
+  gchar *extra = wi->extra;
+  gboolean result;
+  VikTrwLayer *vtl;
 
-/* 
- * 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;
+  gboolean creating_new_layer = TRUE;
 
-  switch(c) {
-  case BABEL_DIAG_OUTPUT:
-    line = (gchar *)data;
+  acq_dialog_widgets_t *w = wi->w;
+  VikDataSourceInterface *interface = wi->w->interface;
+  g_free ( wi );
 
-    /* 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);
+  gdk_threads_enter();
+  if (interface->mode == VIK_DATASOURCE_ADDTOLAYER) {
+    VikLayer *current_selected = vik_layers_panel_get_selected ( w->vlp );
+    if ( IS_VIK_TRW_LAYER(current_selected) ) {
+      vtl = VIK_TRW_LAYER(current_selected);
+      creating_new_layer = FALSE;
     }
-    break;
-  case BABEL_DONE:
-    break;
-  default:
-    break;
   }
-}
-
-/* this routine is the worker thread.  there is only one simultaneous download allowed */
-static void get_from_gps ( gpointer data )
-{
-  VikTrwLayer *vtl;
-       
-  if ( w ) {
-    /* simultaneous downloads are not allowed, so we return.  */
-    g_free(data);
-    g_thread_exit ( NULL );
-    return;
+  if ( creating_new_layer ) {
+    vtl = VIK_TRW_LAYER ( vik_layer_create ( VIK_LAYER_TRW, w->vvp, NULL, FALSE ) );
+    vik_layer_rename ( VIK_LAYER ( vtl ), interface->layer_title );
+    gtk_label_set_text ( GTK_LABEL(w->status), "Working..." );
   }
+  gdk_threads_leave();
 
-  w = data;
+  if ( interface->type == VIK_DATASOURCE_GPSBABEL_DIRECT )
+    result = a_babel_convert_from (vtl, cmd, (BabelStatusFunc) progress_func, extra, w);
+  else
+    result = a_babel_convert_from_shellcommand ( vtl, cmd, extra, (BabelStatusFunc) progress_func, w);
 
-  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" );
-  gtk_label_set_text ( GTK_LABEL(w->status), "Working..." );
-  gdk_threads_leave();
+  g_free ( cmd );
+  g_free ( extra );
 
-  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 (!result) {
     gdk_threads_enter();
     gtk_label_set_text ( GTK_LABEL(w->status), "Error: couldn't find gpsbabel." );
+    if ( creating_new_layer )
+      g_object_unref ( G_OBJECT ( vtl ) );
     gdk_threads_leave();
   } 
+  else {
+    gdk_threads_enter();
+    if (w->ok) {
+      gtk_label_set_text ( GTK_LABEL(w->status), "Done." );
+      if ( creating_new_layer )
+       vik_aggregate_layer_add_layer( vik_layers_panel_get_top_layer(w->vlp), VIK_LAYER(vtl));
+      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 */
+      if ( creating_new_layer )
+       g_object_unref(vtl);
+    }
+  }
+  if ( interface->cleanup_func )
+    interface->cleanup_func ( w->user_data );
 
-  gdk_threads_enter();
-  if (w->ok) {
-    gtk_label_set_text ( GTK_LABEL(w->status), "Done." );
-    vik_aggregate_layer_add_layer( vik_layers_panel_get_top_layer(w->vlp), VIK_LAYER(vtl));
-    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 );
+  if ( w->ok ) {
+    w->ok = FALSE;
   } else {
-    g_object_unref(vtl);
+    g_free ( w );
   }
-  g_free ( w );
-  w = NULL;
+
   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;
+  gpointer user_data;
+
+  w_and_interface_t *wi;
+
+  g_assert(interface->init_func);
+  user_data = interface->init_func();
+  
+  if ( interface->check_existence_func ) {
+    gchar *error_str = interface->check_existence_func();
+    if ( error_str ) {
+      a_dialog_error_msg ( GTK_WINDOW(vw), error_str );
+      g_free ( error_str );
+      return;
+    }
+  }    
 
-  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 );
+  if ( interface->add_setup_widgets_func ) {
+    dialog = gtk_dialog_new_with_buttons ( "", GTK_WINDOW(vw), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
 
-  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");
+    interface->add_setup_widgets_func(dialog, vvp, user_data);
+    gtk_window_set_title ( GTK_WINDOW(dialog), interface->window_title );
 
-  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 );
+    if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
+      interface->cleanup_func(user_data);
+      gtk_widget_destroy(dialog);
+      return;
+    }
+    interface->get_cmd_string_func ( user_data, &cmd, &extra );
+    gtk_widget_destroy(dialog);
+    dialog = NULL;
+  } else
+    interface->get_cmd_string_func ( user_data, &cmd, &extra );
+
+  if ( ! cmd )
+    return;
 
-  gtk_window_set_title ( GTK_WINDOW(dialog), "Acquire data from GPS" );
+  w = g_malloc(sizeof(*w));
+  wi = g_malloc(sizeof(*wi));
+  wi->w = w;
+  wi->w->interface = interface;
+  wi->cmd = cmd;
+  wi->extra = extra;
+
+  dialog = gtk_dialog_new_with_buttons ( "", GTK_WINDOW(vw), 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 );
+  gtk_window_set_title ( GTK_WINDOW(dialog), interface->window_title );
 
-  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 ) {
+    interface->add_progress_widgets_func ( dialog, user_data );
+  }
+  w->user_data = user_data;
+
+
+  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 );
 }
+