]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikgoto.c
Add Track list output from aggregate layers.
[andy/viking.git] / src / vikgoto.c
index 407883a91ccc6e78d616c6e8990ec1be607270b2..7293162d9a125b71a969b3a4c13d9946d6b068e0 100644 (file)
@@ -2,6 +2,7 @@
  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
  *
  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
  *
  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
+ * Copyright (C) 2009, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
  *
  * 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
  *
  * 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
@@ -17,7 +18,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Created by Quy Tonthat <qtonthat@gmail.com>
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 
 #include "viking.h"
 #include "util.h"
 
 #include "viking.h"
 #include "util.h"
-#include "curl_download.h"
-
 #include "vikgototool.h"
 #include "vikgototool.h"
+#include "vikgoto.h"
+
+/* Compatibility */
+#if ! GLIB_CHECK_VERSION(2,22,0)
+#define g_mapped_file_unref g_mapped_file_free
+#endif
 
 static gchar *last_goto_str = NULL;
 static VikCoord *last_coord = NULL;
 
 static gchar *last_goto_str = NULL;
 static VikCoord *last_coord = NULL;
@@ -42,13 +46,13 @@ static gchar *last_successful_goto_str = NULL;
 
 static GList *goto_tools_list = NULL;
 
 
 static GList *goto_tools_list = NULL;
 
-int last_goto_tool = 0;
+#define VIK_SETTINGS_GOTO_PROVIDER "goto_provider"
+int last_goto_tool = -1;
 
 void vik_goto_register ( VikGotoTool *tool )
 {
 
 void vik_goto_register ( VikGotoTool *tool )
 {
-  IS_VIK_GOTO_TOOL( tool );
-
-  goto_tools_list = g_list_append ( goto_tools_list, g_object_ref ( tool ) );
+  if ( IS_VIK_GOTO_TOOL( tool ) )
+    goto_tools_list = g_list_append ( goto_tools_list, g_object_ref ( tool ) );
 }
 
 void vik_goto_unregister_all ()
 }
 
 void vik_goto_unregister_all ()
@@ -90,7 +94,8 @@ static gboolean prompt_try_again(VikWindow *vw)
   gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
 
   GtkWidget *goto_label = gtk_label_new(_("I don't know that place. Do you want another goto?"));
   gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
 
   GtkWidget *goto_label = gtk_label_new(_("I don't know that place. Do you want another goto?"));
-  gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), goto_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_label, FALSE, FALSE, 5 );
+  gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
   gtk_widget_show_all(dialog);
 
   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT )
   gtk_widget_show_all(dialog);
 
   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT )
@@ -100,7 +105,42 @@ static gboolean prompt_try_again(VikWindow *vw)
   return ret;
 }
 
   return ret;
 }
 
-static gchar *  a_prompt_for_goto_string(VikWindow *vw)
+static gint find_entry = -1;
+static gint wanted_entry = -1;
+
+static void find_provider (gpointer elem, gpointer user_data)
+{
+  const gchar *name = vik_goto_tool_get_label (elem);
+  const gchar *provider = user_data;
+  find_entry++;
+  if (!strcmp(name, provider)) {
+    wanted_entry = find_entry;
+  }
+}
+
+/**
+ * Setup last_goto_tool value
+ */
+static void get_provider ()
+{
+  // Use setting for the provider if available
+  if ( last_goto_tool < 0 ) {
+    find_entry = -1;
+    wanted_entry = -1;
+    gchar *provider = NULL;
+    if ( a_settings_get_string ( VIK_SETTINGS_GOTO_PROVIDER, &provider ) ) {
+      // Use setting
+      if ( provider )
+        g_list_foreach (goto_tools_list, find_provider, provider);
+      // If not found set it to the first entry, otherwise use the entry
+      last_goto_tool = ( wanted_entry < 0 ) ? 0 : wanted_entry;
+    }
+    else
+      last_goto_tool = 0;
+  }
+}
+
+static gchar *a_prompt_for_goto_string(VikWindow *vw)
 {
   GtkWidget *dialog = NULL;
 
 {
   GtkWidget *dialog = NULL;
 
@@ -108,37 +148,47 @@ static gchar *  a_prompt_for_goto_string(VikWindow *vw)
   gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
 
   GtkWidget *tool_label = gtk_label_new(_("goto provider:"));
   gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
 
   GtkWidget *tool_label = gtk_label_new(_("goto provider:"));
-  GtkWidget *tool_list = gtk_combo_box_new_text ();
-
+  GtkWidget *tool_list = vik_combo_box_text_new ();
   GList *current = g_list_first (goto_tools_list);
   while (current != NULL)
   {
     char *label = NULL;
     VikGotoTool *tool = current->data;
     label = vik_goto_tool_get_label (tool);
   GList *current = g_list_first (goto_tools_list);
   while (current != NULL)
   {
     char *label = NULL;
     VikGotoTool *tool = current->data;
     label = vik_goto_tool_get_label (tool);
-    gtk_combo_box_append_text ( GTK_COMBO_BOX( tool_list ), label);
+    vik_combo_box_text_append ( tool_list, label );
     current = g_list_next (current);
   }
     current = g_list_next (current);
   }
-  /* Set the previously selected provider as default */
-  gtk_combo_box_set_active ( GTK_COMBO_BOX( tool_list ), last_goto_tool);
+
+  get_provider ();
+  gtk_combo_box_set_active ( GTK_COMBO_BOX( tool_list ), last_goto_tool );
 
   GtkWidget *goto_label = gtk_label_new(_("Enter address or place name:"));
   GtkWidget *goto_entry = gtk_entry_new();
   if (last_goto_str)
     gtk_entry_set_text(GTK_ENTRY(goto_entry), last_goto_str);
 
 
   GtkWidget *goto_label = gtk_label_new(_("Enter address or place name:"));
   GtkWidget *goto_entry = gtk_entry_new();
   if (last_goto_str)
     gtk_entry_set_text(GTK_ENTRY(goto_entry), last_goto_str);
 
-  gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), tool_label, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), tool_list, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), goto_label, FALSE, FALSE, 5 );
-  gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), goto_entry, FALSE, FALSE, 5 );
+  // 'ok' when press return in the entry
+  g_signal_connect_swapped (goto_entry, "activate", G_CALLBACK(a_dialog_response_accept), dialog);
+
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tool_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tool_list, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_label, FALSE, FALSE, 5 );
+  gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_entry, FALSE, FALSE, 5 );
+  gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
   gtk_widget_show_all(dialog);
 
   gtk_widget_show_all(dialog);
 
+  // Ensure the text field has focus so we can start typing straight away
+  gtk_widget_grab_focus ( goto_entry );
+
   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
     gtk_widget_destroy(dialog);
     return NULL;
   }
   
   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
     gtk_widget_destroy(dialog);
     return NULL;
   }
   
-  last_goto_tool = gtk_combo_box_get_active ( GTK_COMBO_BOX (tool_list) );
+  // TODO check if list is empty
+  last_goto_tool = gtk_combo_box_get_active ( GTK_COMBO_BOX(tool_list) );
+  gchar *provider = vik_goto_tool_get_label ( g_list_nth_data (goto_tools_list, last_goto_tool) );
+  a_settings_set_string ( VIK_SETTINGS_GOTO_PROVIDER, provider );
 
   gchar *goto_str = g_strdup ( gtk_entry_get_text ( GTK_ENTRY(goto_entry) ) );
 
 
   gchar *goto_str = g_strdup ( gtk_entry_get_text ( GTK_ENTRY(goto_entry) ) );
 
@@ -153,7 +203,27 @@ static gchar *  a_prompt_for_goto_string(VikWindow *vw)
   return(goto_str);   /* goto_str needs to be freed by caller */
 }
 
   return(goto_str);   /* goto_str needs to be freed by caller */
 }
 
-void a_vik_goto(VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp)
+/**
+ * Goto a place when we already have a string to search on
+ *
+ * Returns: %TRUE if a successful lookup
+ */
+static gboolean vik_goto_place ( VikWindow *vw, VikViewport *vvp, gchar* name, VikCoord *vcoord )
+{
+  // Ensure last_goto_tool is given a value
+  get_provider ();
+
+  if ( goto_tools_list ) {
+    VikGotoTool *gototool = g_list_nth_data ( goto_tools_list, last_goto_tool );
+    if ( gototool ) {
+      if ( vik_goto_tool_get_coord ( gototool, vw, vvp, name, vcoord ) == 0 )
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+void a_vik_goto(VikWindow *vw, VikViewport *vvp)
 {
   VikCoord new_center;
   gchar *s_str;
 {
   VikCoord new_center;
   gchar *s_str;
@@ -181,7 +251,6 @@ void a_vik_goto(VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp)
         g_free(last_successful_goto_str);
       last_successful_goto_str = g_strdup(last_goto_str);
       vik_viewport_set_center_coord(vvp, &new_center);
         g_free(last_successful_goto_str);
       last_successful_goto_str = g_strdup(last_goto_str);
       vik_viewport_set_center_coord(vvp, &new_center);
-      vik_layers_panel_emit_update(vlp);
       more = FALSE;
     }
     else if (!prompt_try_again(vw))
       more = FALSE;
     }
     else if (!prompt_try_again(vw))
@@ -189,3 +258,153 @@ void a_vik_goto(VikWindow *vw, VikLayersPanel *vlp, VikViewport *vvp)
     g_free(s_str);
   } while (more);
 }
     g_free(s_str);
   } while (more);
 }
+
+#define HOSTIP_LATITUDE_PATTERN "\"lat\":\""
+#define HOSTIP_LONGITUDE_PATTERN "\"lng\":\""
+#define HOSTIP_CITY_PATTERN "\"city\":\""
+#define HOSTIP_COUNTRY_PATTERN "\"country_name\":\""
+
+/**
+ * Automatic attempt to find out where you are using:
+ *   1. http://www.hostip.info ++
+ *   2. if not specific enough fallback to using the default goto tool with a country name
+ * ++ Using returned JSON information
+ *  c.f. with googlesearch.c - similar implementation is used here
+ *
+ * returns:
+ *   0 if failed to locate anything
+ *   1 if exact latitude/longitude found
+ *   2 if position only as precise as a city
+ *   3 if position only as precise as a country
+ * @name: Contains the name of place found. Free this string after use.
+ */
+gint a_vik_goto_where_am_i ( VikViewport *vvp, struct LatLon *ll, gchar **name )
+{
+  gint result = 0;
+  *name = NULL;
+
+  gchar *tmpname = a_download_uri_to_tmp_file ( "http://api.hostip.info/get_json.php?position=true", NULL );
+  //gchar *tmpname = g_strdup ("../test/hostip2.json");
+  if (!tmpname) {
+    return result;
+  }
+
+  ll->lat = 0.0;
+  ll->lon = 0.0;
+
+  gchar *pat;
+  GMappedFile *mf;
+  gchar *ss;
+  gint fragment_len;
+
+  gchar lat_buf[32], lon_buf[32];
+  lat_buf[0] = lon_buf[0] = '\0';
+  gchar *country = NULL;
+  gchar *city = NULL;
+
+  if ((mf = g_mapped_file_new(tmpname, FALSE, NULL)) == NULL) {
+    g_critical(_("couldn't map temp file"));
+    goto tidy;
+  }
+
+  gsize len = g_mapped_file_get_length(mf);
+  gchar *text = g_mapped_file_get_contents(mf);
+
+  if ((pat = g_strstr_len(text, len, HOSTIP_COUNTRY_PATTERN))) {
+    pat += strlen(HOSTIP_COUNTRY_PATTERN);
+    fragment_len = 0;
+    ss = pat;
+    while (*pat != '"') {
+      fragment_len++;
+      pat++;
+    }
+    country = g_strndup(ss, fragment_len);
+  }
+
+  if ((pat = g_strstr_len(text, len, HOSTIP_CITY_PATTERN))) {
+    pat += strlen(HOSTIP_CITY_PATTERN);
+    fragment_len = 0;
+    ss = pat;
+    while (*pat != '"') {
+      fragment_len++;
+      pat++;
+    }
+    city = g_strndup(ss, fragment_len);
+  }
+
+  if ((pat = g_strstr_len(text, len, HOSTIP_LATITUDE_PATTERN))) {
+    pat += strlen(HOSTIP_LATITUDE_PATTERN);
+    ss = lat_buf;
+    if (*pat == '-')
+      *ss++ = *pat++;
+    while ((ss < (lat_buf + sizeof(lat_buf))) && (pat < (text + len)) &&
+          (g_ascii_isdigit(*pat) || (*pat == '.')))
+      *ss++ = *pat++;
+    *ss = '\0';
+    ll->lat = g_ascii_strtod(lat_buf, NULL);
+  }
+
+  if ((pat = g_strstr_len(text, len, HOSTIP_LONGITUDE_PATTERN))) {
+    pat += strlen(HOSTIP_LONGITUDE_PATTERN);
+    ss = lon_buf;
+    if (*pat == '-')
+      *ss++ = *pat++;
+    while ((ss < (lon_buf + sizeof(lon_buf))) && (pat < (text + len)) &&
+          (g_ascii_isdigit(*pat) || (*pat == '.')))
+      *ss++ = *pat++;
+    *ss = '\0';
+    ll->lon = g_ascii_strtod(lon_buf, NULL);
+  }
+
+  if ( ll->lat != 0.0 && ll->lon != 0.0 ) {
+    if ( ll->lat > -90.0 && ll->lat < 90.0 && ll->lon > -180.0 && ll->lon < 180.0 ) {
+      // Found a 'sensible' & 'precise' location
+      result = 1;
+      *name = g_strdup ( _("Locality") ); //Albeit maybe not known by an actual name!
+    }
+  }
+  else {
+    // Hopefully city name is unique enough to lookup position on
+    // Maybe for American places where hostip appends the State code on the end
+    // But if the country code is not appended if could easily get confused
+    //  e.g. 'Portsmouth' could be at least
+    //   Portsmouth, Hampshire, UK or
+    //   Portsmouth, Viginia, USA.
+
+    // Try city name lookup
+    if ( city ) {
+      g_debug ( "%s: found city %s", __FUNCTION__, city );
+      if ( strcmp ( city, "(Unknown city)" ) != 0 ) {
+        VikCoord new_center;
+        if ( vik_goto_place ( NULL, vvp, city, &new_center ) ) {
+          // Got something
+          vik_coord_to_latlon ( &new_center, ll );
+          result = 2;
+          *name = city;
+          goto tidy;
+        }
+      }
+    }
+
+    // Try country name lookup
+    if ( country ) {
+      g_debug ( "%s: found country %s", __FUNCTION__, country );
+      if ( strcmp ( country, "(Unknown Country)" ) != 0 ) {
+        VikCoord new_center;
+        if ( vik_goto_place ( NULL, vvp, country, &new_center ) ) {
+          // Finally got something
+          vik_coord_to_latlon ( &new_center, ll );
+          result = 3;
+          *name = country;
+          goto tidy;
+        }
+      }
+    }
+  }
+  
+ tidy:
+  g_mapped_file_unref ( mf );
+  g_remove ( tmpname );
+  g_free ( tmpname );
+  return result;
+}