]> git.street.me.uk Git - andy/viking.git/blame - src/vikgoto.c
Make more text translatable
[andy/viking.git] / src / vikgoto.c
CommitLineData
6571a7de
GB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
bfecd26e 5 * Copyright (C) 2009, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6571a7de
GB
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
6571a7de
GB
21 */
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25#include <stdlib.h>
26#include <stdio.h>
27#include <string.h>
28#include <glib.h>
29#include <glib/gstdio.h>
30#include <glib/gprintf.h>
31#include <glib/gi18n.h>
32
33#include "viking.h"
34e71b99 34#include "vikgototool.h"
3d2c0c26 35#include "vikgoto.h"
9e4fdfe4 36#include "ui_util.h"
6571a7de 37
a14f46cf
RN
38/* Compatibility */
39#if ! GLIB_CHECK_VERSION(2,22,0)
40#define g_mapped_file_unref g_mapped_file_free
41#endif
42
34e71b99 43static gchar *last_goto_str = NULL;
6571a7de 44static VikCoord *last_coord = NULL;
34e71b99 45static gchar *last_successful_goto_str = NULL;
6571a7de 46
34e71b99 47static GList *goto_tools_list = NULL;
6571a7de 48
d7c8636c
RN
49#define VIK_SETTINGS_GOTO_PROVIDER "goto_provider"
50int last_goto_tool = -1;
6571a7de 51
34e71b99 52void vik_goto_register ( VikGotoTool *tool )
6571a7de 53{
619a68f3
RN
54 if ( IS_VIK_GOTO_TOOL( tool ) )
55 goto_tools_list = g_list_append ( goto_tools_list, g_object_ref ( tool ) );
6571a7de
GB
56}
57
34e71b99 58void vik_goto_unregister_all ()
6571a7de 59{
34e71b99 60 g_list_foreach ( goto_tools_list, (GFunc) g_object_unref, NULL );
6571a7de
GB
61}
62
34e71b99 63gchar * a_vik_goto_get_search_string_for_this_place(VikWindow *vw)
6571a7de
GB
64{
65 if (!last_coord)
66 return NULL;
67
68 VikViewport *vvp = vik_window_viewport(vw);
69 const VikCoord *cur_center = vik_viewport_get_center(vvp);
70 if (vik_coord_equals(cur_center, last_coord)) {
34e71b99 71 return(last_successful_goto_str);
6571a7de
GB
72 }
73 else
74 return NULL;
75}
76
77static void display_no_tool(VikWindow *vw)
78{
79 GtkWidget *dialog = NULL;
80
34e71b99 81 dialog = gtk_message_dialog_new ( GTK_WINDOW(vw), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("No goto tool available.") );
6571a7de
GB
82
83 gtk_dialog_run ( GTK_DIALOG(dialog) );
84
85 gtk_widget_destroy(dialog);
86}
87
79f34e27 88static gboolean prompt_try_again(VikWindow *vw, const gchar *msg)
6571a7de
GB
89{
90 GtkWidget *dialog = NULL;
91 gboolean ret = TRUE;
92
93 dialog = gtk_dialog_new_with_buttons ( "", GTK_WINDOW(vw), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
34e71b99 94 gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
6571a7de 95
79f34e27 96 GtkWidget *goto_label = gtk_label_new(msg);
9b082b39 97 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_label, FALSE, FALSE, 5 );
5b7d7928 98 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
6571a7de
GB
99 gtk_widget_show_all(dialog);
100
101 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT )
102 ret = FALSE;
103
104 gtk_widget_destroy(dialog);
105 return ret;
106}
107
d7c8636c
RN
108static gint find_entry = -1;
109static gint wanted_entry = -1;
110
111static void find_provider (gpointer elem, gpointer user_data)
112{
113 const gchar *name = vik_goto_tool_get_label (elem);
114 const gchar *provider = user_data;
115 find_entry++;
116 if (!strcmp(name, provider)) {
117 wanted_entry = find_entry;
118 }
119}
120
a14f46cf
RN
121/**
122 * Setup last_goto_tool value
123 */
124static void get_provider ()
125{
126 // Use setting for the provider if available
127 if ( last_goto_tool < 0 ) {
128 find_entry = -1;
129 wanted_entry = -1;
130 gchar *provider = NULL;
131 if ( a_settings_get_string ( VIK_SETTINGS_GOTO_PROVIDER, &provider ) ) {
132 // Use setting
133 if ( provider )
134 g_list_foreach (goto_tools_list, find_provider, provider);
135 // If not found set it to the first entry, otherwise use the entry
136 last_goto_tool = ( wanted_entry < 0 ) ? 0 : wanted_entry;
137 }
138 else
139 last_goto_tool = 0;
140 }
141}
142
b538d0e9
RN
143static void
144text_changed_cb (GtkEntry *entry,
145 GParamSpec *pspec,
146 GtkWidget *button)
147{
148 gboolean has_text = gtk_entry_get_text_length(entry) > 0;
149 gtk_entry_set_icon_sensitive ( entry, GTK_ENTRY_ICON_SECONDARY, has_text );
150 gtk_widget_set_sensitive ( button, has_text );
151}
152
d7c8636c 153static gchar *a_prompt_for_goto_string(VikWindow *vw)
6571a7de
GB
154{
155 GtkWidget *dialog = NULL;
156
157 dialog = gtk_dialog_new_with_buttons ( "", GTK_WINDOW(vw), 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
34e71b99 158 gtk_window_set_title(GTK_WINDOW(dialog), _("goto"));
6571a7de 159
34e71b99 160 GtkWidget *tool_label = gtk_label_new(_("goto provider:"));
1bc1c05b 161 GtkWidget *tool_list = vik_combo_box_text_new ();
34e71b99 162 GList *current = g_list_first (goto_tools_list);
6571a7de
GB
163 while (current != NULL)
164 {
165 char *label = NULL;
34e71b99
GB
166 VikGotoTool *tool = current->data;
167 label = vik_goto_tool_get_label (tool);
1bc1c05b 168 vik_combo_box_text_append ( tool_list, label );
6571a7de
GB
169 current = g_list_next (current);
170 }
d7c8636c 171
a14f46cf 172 get_provider ();
d7c8636c 173 gtk_combo_box_set_active ( GTK_COMBO_BOX( tool_list ), last_goto_tool );
6571a7de 174
34e71b99 175 GtkWidget *goto_label = gtk_label_new(_("Enter address or place name:"));
9e4fdfe4 176 GtkWidget *goto_entry = ui_entry_new ( last_goto_str, GTK_ENTRY_ICON_SECONDARY );
6571a7de 177
ae1d3fd1
RN
178 // 'ok' when press return in the entry
179 g_signal_connect_swapped (goto_entry, "activate", G_CALLBACK(a_dialog_response_accept), dialog);
180
b538d0e9
RN
181#if GTK_CHECK_VERSION (2,20,0)
182 GtkWidget *ok_button = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
183 text_changed_cb ( GTK_ENTRY(goto_entry), NULL, ok_button );
184 g_signal_connect ( goto_entry, "notify::text", G_CALLBACK (text_changed_cb), ok_button );
185#endif
9b082b39
RN
186 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tool_label, FALSE, FALSE, 5 );
187 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), tool_list, FALSE, FALSE, 5 );
188 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_label, FALSE, FALSE, 5 );
189 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), goto_entry, FALSE, FALSE, 5 );
5b7d7928 190 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
6571a7de
GB
191 gtk_widget_show_all(dialog);
192
ae1d3fd1
RN
193 // Ensure the text field has focus so we can start typing straight away
194 gtk_widget_grab_focus ( goto_entry );
195
6571a7de
GB
196 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
197 gtk_widget_destroy(dialog);
198 return NULL;
199 }
200
a14f46cf 201 // TODO check if list is empty
d7c8636c
RN
202 last_goto_tool = gtk_combo_box_get_active ( GTK_COMBO_BOX(tool_list) );
203 gchar *provider = vik_goto_tool_get_label ( g_list_nth_data (goto_tools_list, last_goto_tool) );
204 a_settings_set_string ( VIK_SETTINGS_GOTO_PROVIDER, provider );
6571a7de 205
34e71b99 206 gchar *goto_str = g_strdup ( gtk_entry_get_text ( GTK_ENTRY(goto_entry) ) );
6571a7de
GB
207
208 gtk_widget_destroy(dialog);
209
34e71b99
GB
210 if (goto_str[0] != '\0') {
211 if (last_goto_str)
212 g_free(last_goto_str);
213 last_goto_str = g_strdup(goto_str);
6571a7de
GB
214 }
215
34e71b99 216 return(goto_str); /* goto_str needs to be freed by caller */
6571a7de
GB
217}
218
a14f46cf
RN
219/**
220 * Goto a place when we already have a string to search on
221 *
222 * Returns: %TRUE if a successful lookup
223 */
224static gboolean vik_goto_place ( VikWindow *vw, VikViewport *vvp, gchar* name, VikCoord *vcoord )
225{
226 // Ensure last_goto_tool is given a value
227 get_provider ();
228
229 if ( goto_tools_list ) {
230 VikGotoTool *gototool = g_list_nth_data ( goto_tools_list, last_goto_tool );
231 if ( gototool ) {
232 if ( vik_goto_tool_get_coord ( gototool, vw, vvp, name, vcoord ) == 0 )
233 return TRUE;
234 }
235 }
236 return FALSE;
237}
238
c36a079a 239void a_vik_goto(VikWindow *vw, VikViewport *vvp)
6571a7de
GB
240{
241 VikCoord new_center;
242 gchar *s_str;
243 gboolean more = TRUE;
244
34e71b99 245 if (goto_tools_list == NULL)
6571a7de
GB
246 {
247 /* Empty list */
248 display_no_tool(vw);
249 return;
250 }
251
252 do {
34e71b99 253 s_str = a_prompt_for_goto_string(vw);
6571a7de
GB
254 if ((!s_str) || (s_str[0] == 0)) {
255 more = FALSE;
256 }
79f34e27
RN
257 else {
258 int ans = vik_goto_tool_get_coord(g_list_nth_data (goto_tools_list, last_goto_tool), vw, vvp, s_str, &new_center);
259 if ( ans == 0 ) {
260 if (last_coord)
261 g_free(last_coord);
262 last_coord = g_malloc(sizeof(VikCoord));
263 *last_coord = new_center;
264 if (last_successful_goto_str)
265 g_free(last_successful_goto_str);
266 last_successful_goto_str = g_strdup(last_goto_str);
267 vik_viewport_set_center_coord(vvp, &new_center, TRUE);
6571a7de 268 more = FALSE;
79f34e27
RN
269 }
270 else if ( ans == -1 ) {
271 if (!prompt_try_again(vw, _("I don't know that place. Do you want another goto?")))
272 more = FALSE;
273 }
274 else if (!prompt_try_again(vw, _("Service request failure. Do you want another goto?")))
275 more = FALSE;
276 }
6571a7de
GB
277 g_free(s_str);
278 } while (more);
279}
a14f46cf 280
ccab0e9e
RN
281#define JSON_LATITUDE_PATTERN "\"geoplugin_latitude\":\""
282#define JSON_LONGITUDE_PATTERN "\"geoplugin_longitude\":\""
283#define JSON_CITY_PATTERN "\"geoplugin_city\":\""
284#define JSON_COUNTRY_PATTERN "\"geoplugin_countryName\":\""
a14f46cf
RN
285
286/**
287 * Automatic attempt to find out where you are using:
ccab0e9e 288 * 1. http://www.geoplugin.com ++
a14f46cf
RN
289 * 2. if not specific enough fallback to using the default goto tool with a country name
290 * ++ Using returned JSON information
291 * c.f. with googlesearch.c - similar implementation is used here
292 *
293 * returns:
294 * 0 if failed to locate anything
295 * 1 if exact latitude/longitude found
296 * 2 if position only as precise as a city
297 * 3 if position only as precise as a country
298 * @name: Contains the name of place found. Free this string after use.
299 */
300gint a_vik_goto_where_am_i ( VikViewport *vvp, struct LatLon *ll, gchar **name )
301{
302 gint result = 0;
303 *name = NULL;
304
ccab0e9e
RN
305 gchar *tmpname = a_download_uri_to_tmp_file ( "http://www.geoplugin.net/json.gp", NULL );
306 //gchar *tmpname = g_strdup ("../test/www.geoplugin.net-slash-json.gp.result");
a14f46cf
RN
307 if (!tmpname) {
308 return result;
309 }
310
311 ll->lat = 0.0;
312 ll->lon = 0.0;
313
314 gchar *pat;
315 GMappedFile *mf;
316 gchar *ss;
317 gint fragment_len;
318
319 gchar lat_buf[32], lon_buf[32];
320 lat_buf[0] = lon_buf[0] = '\0';
cf087260
RN
321 gchar *country = NULL;
322 gchar *city = NULL;
a14f46cf
RN
323
324 if ((mf = g_mapped_file_new(tmpname, FALSE, NULL)) == NULL) {
325 g_critical(_("couldn't map temp file"));
326 goto tidy;
327 }
328
329 gsize len = g_mapped_file_get_length(mf);
330 gchar *text = g_mapped_file_get_contents(mf);
331
ccab0e9e
RN
332 if ((pat = g_strstr_len(text, len, JSON_COUNTRY_PATTERN))) {
333 pat += strlen(JSON_COUNTRY_PATTERN);
a14f46cf
RN
334 fragment_len = 0;
335 ss = pat;
336 while (*pat != '"') {
337 fragment_len++;
338 pat++;
339 }
340 country = g_strndup(ss, fragment_len);
341 }
342
ccab0e9e
RN
343 if ((pat = g_strstr_len(text, len, JSON_CITY_PATTERN))) {
344 pat += strlen(JSON_CITY_PATTERN);
a14f46cf
RN
345 fragment_len = 0;
346 ss = pat;
347 while (*pat != '"') {
348 fragment_len++;
349 pat++;
350 }
351 city = g_strndup(ss, fragment_len);
352 }
353
ccab0e9e
RN
354 if ((pat = g_strstr_len(text, len, JSON_LATITUDE_PATTERN))) {
355 pat += strlen(JSON_LATITUDE_PATTERN);
a14f46cf
RN
356 ss = lat_buf;
357 if (*pat == '-')
358 *ss++ = *pat++;
359 while ((ss < (lat_buf + sizeof(lat_buf))) && (pat < (text + len)) &&
360 (g_ascii_isdigit(*pat) || (*pat == '.')))
361 *ss++ = *pat++;
362 *ss = '\0';
363 ll->lat = g_ascii_strtod(lat_buf, NULL);
364 }
365
ccab0e9e
RN
366 if ((pat = g_strstr_len(text, len, JSON_LONGITUDE_PATTERN))) {
367 pat += strlen(JSON_LONGITUDE_PATTERN);
a14f46cf
RN
368 ss = lon_buf;
369 if (*pat == '-')
370 *ss++ = *pat++;
371 while ((ss < (lon_buf + sizeof(lon_buf))) && (pat < (text + len)) &&
372 (g_ascii_isdigit(*pat) || (*pat == '.')))
373 *ss++ = *pat++;
374 *ss = '\0';
375 ll->lon = g_ascii_strtod(lon_buf, NULL);
376 }
377
378 if ( ll->lat != 0.0 && ll->lon != 0.0 ) {
379 if ( ll->lat > -90.0 && ll->lat < 90.0 && ll->lon > -180.0 && ll->lon < 180.0 ) {
380 // Found a 'sensible' & 'precise' location
381 result = 1;
382 *name = g_strdup ( _("Locality") ); //Albeit maybe not known by an actual name!
383 }
384 }
385 else {
386 // Hopefully city name is unique enough to lookup position on
ccab0e9e 387 // For American places the service may append the State code on the end
a14f46cf
RN
388 // But if the country code is not appended if could easily get confused
389 // e.g. 'Portsmouth' could be at least
390 // Portsmouth, Hampshire, UK or
391 // Portsmouth, Viginia, USA.
392
393 // Try city name lookup
394 if ( city ) {
395 g_debug ( "%s: found city %s", __FUNCTION__, city );
396 if ( strcmp ( city, "(Unknown city)" ) != 0 ) {
397 VikCoord new_center;
398 if ( vik_goto_place ( NULL, vvp, city, &new_center ) ) {
399 // Got something
400 vik_coord_to_latlon ( &new_center, ll );
401 result = 2;
402 *name = city;
403 goto tidy;
404 }
405 }
406 }
407
408 // Try country name lookup
409 if ( country ) {
410 g_debug ( "%s: found country %s", __FUNCTION__, country );
411 if ( strcmp ( country, "(Unknown Country)" ) != 0 ) {
412 VikCoord new_center;
413 if ( vik_goto_place ( NULL, vvp, country, &new_center ) ) {
414 // Finally got something
415 vik_coord_to_latlon ( &new_center, ll );
416 result = 3;
417 *name = country;
418 goto tidy;
419 }
420 }
421 }
422 }
423
424 tidy:
425 g_mapped_file_unref ( mf );
80586339 426 (void)g_remove ( tmpname );
a14f46cf
RN
427 g_free ( tmpname );
428 return result;
429}