X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/01423b939fe263b830e979b5b7091a5a9296d5b1..123f1312ae4a18ec504e6542cbc90cbcedbef789:/src/vikgoto.c?ds=inline diff --git a/src/vikgoto.c b/src/vikgoto.c index 407883a9..7293162d 100644 --- a/src/vikgoto.c +++ b/src/vikgoto.c @@ -2,6 +2,7 @@ * viking -- GPS Data and Topo Analyzer, Explorer, and Manager * * Copyright (C) 2003-2005, Evan Battaglia + * Copyright (C) 2009, Guilhem Bonnefille * * 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 * - * Created by Quy Tonthat */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -32,9 +32,13 @@ #include "viking.h" #include "util.h" -#include "curl_download.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; @@ -42,13 +46,13 @@ static gchar *last_successful_goto_str = 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 ) { - 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 () @@ -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_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 ) @@ -100,7 +105,42 @@ static gboolean prompt_try_again(VikWindow *vw) 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; @@ -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:")); - 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); - gtk_combo_box_append_text ( GTK_COMBO_BOX( tool_list ), label); + vik_combo_box_text_append ( tool_list, label ); 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); - 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); + // 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; } - 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) ) ); @@ -153,7 +203,27 @@ static gchar * a_prompt_for_goto_string(VikWindow *vw) 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; @@ -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); - vik_layers_panel_emit_update(vlp); 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); } + +#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; +}