]> git.street.me.uk Git - andy/viking.git/blob - src/dialog.c
If using GTK+2.24 or later don't use depreciated about dialog features as not needed...
[andy/viking.git] / src / dialog.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5  * Copyright (C) 2008, Hein Ragas <viking@ragas.nl>
6  * Copyright (C) 2010, Rob Norris <rw_norris@hotmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "viking.h"
29 #include "thumbnails.h"
30 #include "garminsymbols.h"
31 #include "degrees_converters.h"
32 #include "authors.h"
33 #include "documenters.h"
34 #include "vikgoto.h"
35 #include "util.h"
36
37 #include <glib/gi18n.h>
38
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42
43 void a_dialog_msg ( GtkWindow *parent, gint type, const gchar *info, const gchar *extra )
44 {
45   GtkWidget *msgbox = gtk_message_dialog_new ( parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, info, extra );
46   gtk_dialog_run ( GTK_DIALOG(msgbox) );
47   gtk_widget_destroy ( msgbox );
48 }
49
50 gboolean a_dialog_goto_latlon ( GtkWindow *parent, struct LatLon *ll, const struct LatLon *old )
51 {
52   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Go to Lat/Lon"),
53                                                   parent,
54                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
55                                                   GTK_STOCK_CANCEL,
56                                                   GTK_RESPONSE_REJECT,
57                                                   GTK_STOCK_OK,
58                                                   GTK_RESPONSE_ACCEPT,
59                                                   NULL);
60   GtkWidget *latlabel, *lonlabel;
61   GtkWidget *lat, *lon;
62   gchar *tmp_lat, *tmp_lon;
63
64   latlabel = gtk_label_new (_("Latitude:"));
65   lat = gtk_entry_new ();
66   tmp_lat = g_strdup_printf ( "%f", old->lat );
67   gtk_entry_set_text ( GTK_ENTRY(lat), tmp_lat );
68   g_free ( tmp_lat );
69
70   lonlabel = gtk_label_new (_("Longitude:"));
71   lon = gtk_entry_new ();
72   tmp_lon = g_strdup_printf ( "%f", old->lon );
73   gtk_entry_set_text ( GTK_ENTRY(lon), tmp_lon );
74   g_free ( tmp_lon );
75
76   gtk_widget_show ( latlabel );
77   gtk_widget_show ( lonlabel );
78   gtk_widget_show ( lat );
79   gtk_widget_show ( lon );
80
81   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel,  FALSE, FALSE, 0);
82   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lat, FALSE, FALSE, 0);
83   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonlabel,  FALSE, FALSE, 0);
84   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lon,  FALSE, FALSE, 0);
85
86   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
87
88   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
89   {
90     ll->lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lat) ) );
91     ll->lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lon) ) );
92     gtk_widget_destroy ( dialog );
93     return TRUE;
94   }
95
96   gtk_widget_destroy ( dialog );
97   return FALSE;
98 }
99
100 gboolean a_dialog_goto_utm ( GtkWindow *parent, struct UTM *utm, const struct UTM *old )
101 {
102   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Go to UTM"),
103                                                   parent,
104                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
105                                                   GTK_STOCK_CANCEL,
106                                                   GTK_RESPONSE_REJECT,
107                                                   GTK_STOCK_OK,
108                                                   GTK_RESPONSE_ACCEPT,
109                                                   NULL);
110   GtkWidget *norlabel, *easlabel, *nor, *eas;
111   GtkWidget *zonehbox, *zonespin, *letterentry;
112   gchar *tmp_eas, *tmp_nor;
113   gchar tmp_letter[2];
114
115   norlabel = gtk_label_new (_("Northing:"));
116   nor = gtk_entry_new ();
117   tmp_nor = g_strdup_printf("%ld", (long) old->northing );
118   gtk_entry_set_text ( GTK_ENTRY(nor), tmp_nor );
119   g_free ( tmp_nor );
120
121   easlabel = gtk_label_new (_("Easting:"));
122   eas = gtk_entry_new ();
123   tmp_eas = g_strdup_printf("%ld", (long) old->easting );
124   gtk_entry_set_text ( GTK_ENTRY(eas), tmp_eas );
125   g_free ( tmp_eas );
126
127   zonehbox = gtk_hbox_new ( FALSE, 0 );
128   gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( _("Zone:") ), FALSE, FALSE, 5 );
129   zonespin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( old->zone, 1, 60, 1, 5, 0 ), 1, 0 );
130   gtk_box_pack_start ( GTK_BOX(zonehbox), zonespin, TRUE, TRUE, 5 );
131   gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( _("Letter:") ), FALSE, FALSE, 5 );
132   letterentry = gtk_entry_new ();
133   gtk_entry_set_max_length ( GTK_ENTRY(letterentry), 1 );
134   gtk_entry_set_width_chars ( GTK_ENTRY(letterentry), 2 );
135   tmp_letter[0] = old->letter;
136   tmp_letter[1] = '\0';
137   gtk_entry_set_text ( GTK_ENTRY(letterentry), tmp_letter );
138   gtk_box_pack_start ( GTK_BOX(zonehbox), letterentry, FALSE, FALSE, 5 );
139
140   gtk_widget_show ( norlabel );
141   gtk_widget_show ( easlabel );
142   gtk_widget_show ( nor );
143   gtk_widget_show ( eas );
144
145   gtk_widget_show_all ( zonehbox );
146
147   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), norlabel, FALSE, FALSE, 0);
148   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), nor, FALSE, FALSE, 0);
149   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), easlabel,  FALSE, FALSE, 0);
150   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), eas,  FALSE, FALSE, 0);
151   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zonehbox,  FALSE, FALSE, 0);
152
153   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
154
155   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
156   {
157     const gchar *letter;
158     utm->northing = atof ( gtk_entry_get_text ( GTK_ENTRY(nor) ) );
159     utm->easting = atof ( gtk_entry_get_text ( GTK_ENTRY(eas) ) );
160     utm->zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(zonespin) );
161     letter = gtk_entry_get_text ( GTK_ENTRY(letterentry) );
162     if (*letter)
163        utm->letter = toupper(*letter);
164     gtk_widget_destroy ( dialog );
165     return TRUE;
166   }
167
168   gtk_widget_destroy ( dialog );
169   return FALSE;
170 }
171
172 void a_dialog_response_accept ( GtkDialog *dialog )
173 {
174   gtk_dialog_response ( dialog, GTK_RESPONSE_ACCEPT );
175 }
176
177 static void symbol_entry_changed_cb(GtkWidget *combo, GtkListStore *store)
178 {
179   GtkTreeIter iter;
180   gchar *sym;
181
182   if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter))
183     return;
184
185   gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
186   /* Note: symm is NULL when "(none)" is select (first cell is empty) */
187   gtk_widget_set_tooltip_text(combo, sym);
188   g_free(sym);
189 }
190
191 /* Specify if a new waypoint or not */
192 /* If a new waypoint then it uses the default_name for the suggested name allowing the user to change it.
193     The name to use is returned
194    When an existing waypoint the default name is shown but is not allowed to be changed and NULL is returned
195  */
196 /* todo: less on this side, like add track */
197 gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *vtl, VikWaypoint *wp, VikCoordMode coord_mode, gboolean is_new, gboolean *updated )
198 {
199   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Waypoint Properties"),
200                                                    parent,
201                                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
202                                                    GTK_STOCK_CANCEL,
203                                                    GTK_RESPONSE_REJECT,
204                                                    GTK_STOCK_OK,
205                                                    GTK_RESPONSE_ACCEPT,
206                                                    NULL);
207   struct LatLon ll;
208   GtkWidget *latlabel, *lonlabel, *namelabel, *latentry, *lonentry, *altentry, *altlabel, *nameentry=NULL;
209   GtkWidget *commentlabel, *commententry, *descriptionlabel, *descriptionentry, *imagelabel, *imageentry, *symbollabel, *symbolentry;
210   GtkListStore *store;
211
212   gchar *lat, *lon, *alt;
213
214   vik_coord_to_latlon ( &(wp->coord), &ll );
215
216   lat = g_strdup_printf ( "%f", ll.lat );
217   lon = g_strdup_printf ( "%f", ll.lon );
218   vik_units_height_t height_units = a_vik_get_units_height ();
219   switch (height_units) {
220   case VIK_UNITS_HEIGHT_METRES:
221     alt = g_strdup_printf ( "%f", wp->altitude );
222     break;
223   case VIK_UNITS_HEIGHT_FEET:
224     alt = g_strdup_printf ( "%f", VIK_METERS_TO_FEET(wp->altitude) );
225     break;
226   default:
227     alt = g_strdup_printf ( "%f", wp->altitude );
228     g_critical("Houston, we've had a problem. height=%d", height_units);
229   }
230
231   *updated = FALSE;
232
233   namelabel = gtk_label_new (_("Name:"));
234   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), namelabel, FALSE, FALSE, 0);
235   if ( is_new )
236   {
237     // New waypoint, so name is still changeable
238     nameentry = gtk_entry_new ();
239     if ( default_name )
240       gtk_entry_set_text( GTK_ENTRY(nameentry), default_name );
241     g_signal_connect_swapped ( nameentry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
242   }
243   else {
244     // Existing waypoint - so can not change the name this way - but at least can see it
245     if ( default_name )
246       nameentry = gtk_label_new ( default_name );
247   }
248   if ( nameentry )
249     gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), nameentry, FALSE, FALSE, 0);
250
251   latlabel = gtk_label_new (_("Latitude:"));
252   latentry = gtk_entry_new ();
253   gtk_entry_set_text ( GTK_ENTRY(latentry), lat );
254   g_free ( lat );
255
256   lonlabel = gtk_label_new (_("Longitude:"));
257   lonentry = gtk_entry_new ();
258   gtk_entry_set_text ( GTK_ENTRY(lonentry), lon );
259   g_free ( lon );
260
261   altlabel = gtk_label_new (_("Altitude:"));
262   altentry = gtk_entry_new ();
263   gtk_entry_set_text ( GTK_ENTRY(altentry), alt );
264   g_free ( alt );
265
266   commentlabel = gtk_label_new (_("Comment:"));
267   commententry = gtk_entry_new ();
268   gchar *cmt =  NULL;
269   // Auto put in some kind of 'name' as a comment if one previously 'goto'ed this exact location
270   cmt = a_vik_goto_get_search_string_for_this_place(VIK_WINDOW(parent));
271   if (cmt)
272     gtk_entry_set_text(GTK_ENTRY(commententry), cmt);
273
274   descriptionlabel = gtk_label_new (_("Description:"));
275   descriptionentry = gtk_entry_new ();
276
277   imagelabel = gtk_label_new (_("Image:"));
278   imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN);
279
280   {
281     GtkCellRenderer *r;
282     symbollabel = gtk_label_new (_("Symbol:"));
283     GtkTreeIter iter;
284
285     store = gtk_list_store_new(3, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING);
286     symbolentry = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
287     gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(symbolentry), 6);
288
289     g_signal_connect(symbolentry, "changed", G_CALLBACK(symbol_entry_changed_cb), store);
290     gtk_list_store_append (store, &iter);
291     gtk_list_store_set (store, &iter, 0, NULL, 1, NULL, 2, _("(none)"), -1);
292     a_populate_sym_list(store);
293
294     r = gtk_cell_renderer_pixbuf_new ();
295     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE);
296     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "pixbuf", 1, NULL);
297
298     r = gtk_cell_renderer_text_new ();
299     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE);
300     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "text", 2, NULL);
301
302     if ( !is_new && wp->symbol ) {
303       gboolean ok;
304       gchar *sym;
305       for (ok = gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &iter ); ok; ok = gtk_tree_model_iter_next ( GTK_TREE_MODEL(store), &iter)) {
306         gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
307         if (sym && !strcmp(sym, wp->symbol)) {
308           g_free(sym);
309           break;
310         } else {
311           g_free(sym);
312         }
313       }
314       // Ensure is it a valid symbol in the given symbol set (large vs small)
315       // Not all symbols are available in both
316       // The check prevents a Gtk Critical message
317       if ( iter.stamp )
318         gtk_combo_box_set_active_iter(GTK_COMBO_BOX(symbolentry), &iter);
319     }
320   }
321
322   if ( !is_new && wp->comment )
323     gtk_entry_set_text ( GTK_ENTRY(commententry), wp->comment );
324
325   if ( !is_new && wp->description )
326     gtk_entry_set_text ( GTK_ENTRY(descriptionentry), wp->description );
327
328   if ( !is_new && wp->image )
329     vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), wp->image );
330
331
332   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel, FALSE, FALSE, 0);
333   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latentry, FALSE, FALSE, 0);
334   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonlabel, FALSE, FALSE, 0);
335   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonentry, FALSE, FALSE, 0);
336   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altlabel, FALSE, FALSE, 0);
337   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altentry, FALSE, FALSE, 0);
338   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commentlabel, FALSE, FALSE, 0);
339   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commententry, FALSE, FALSE, 0);
340   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionlabel, FALSE, FALSE, 0);
341   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionentry, FALSE, FALSE, 0);
342   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imagelabel, FALSE, FALSE, 0);
343   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imageentry, FALSE, FALSE, 0);
344   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), symbollabel, FALSE, FALSE, 0);
345   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(symbolentry), FALSE, FALSE, 0);
346
347   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
348
349   gtk_widget_show_all ( gtk_dialog_get_content_area(GTK_DIALOG(dialog)) );
350
351   if ( !is_new ) {
352     // Shift left<->right to try not to obscure the waypoint.
353     trw_layer_dialog_shift ( vtl, GTK_WINDOW(dialog), &(wp->coord), FALSE );
354   }
355
356   while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
357   {
358     if ( is_new )
359     {
360       if ( strlen((gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) )) == 0 ) /* TODO: other checks (isalpha or whatever ) */
361         a_dialog_info_msg ( parent, _("Please enter a name for the waypoint.") );
362       else {
363         // NB: No check for unique names - this allows generation of same named entries.
364         gchar *entered_name = g_strdup ( (gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) ) );
365
366         /* Do It */
367         ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
368         ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
369         vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
370         // Always store in metres
371         switch (height_units) {
372         case VIK_UNITS_HEIGHT_METRES:
373           wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
374           break;
375         case VIK_UNITS_HEIGHT_FEET:
376           wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
377           break;
378         default:
379           wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
380           g_critical("Houston, we've had a problem. height=%d", height_units);
381         }
382         vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
383         vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
384         vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
385         if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
386           a_thumbnails_create ( wp->image );
387
388         GtkTreeIter iter, first;
389         gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
390         if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
391           vik_waypoint_set_symbol ( wp, NULL );
392         } else {
393           gchar *sym;
394           gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
395           vik_waypoint_set_symbol ( wp, sym );
396           g_free(sym);
397         }
398
399         gtk_widget_destroy ( dialog );
400         return entered_name;
401       }
402     }
403     else
404     {
405       ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
406       ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
407       vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
408       switch (height_units) {
409       case VIK_UNITS_HEIGHT_METRES:
410         wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
411         break;
412       case VIK_UNITS_HEIGHT_FEET:
413         wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
414         break;
415       default:
416         wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
417         g_critical("Houston, we've had a problem. height=%d", height_units);
418       }
419       if ( (! wp->comment) || strcmp ( wp->comment, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ) != 0 )
420         vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
421       if ( (! wp->description) || strcmp ( wp->description, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) ) != 0 )
422         vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
423       if ( (! wp->image) || strcmp ( wp->image, vik_file_entry_get_filename ( VIK_FILE_ENTRY ( imageentry ) ) ) != 0 )
424       {
425         vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
426         if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
427           a_thumbnails_create ( wp->image );
428       }
429
430       {
431         GtkTreeIter iter, first;
432         gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
433         if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
434           vik_waypoint_set_symbol ( wp, NULL );
435         } else {
436           gchar *sym;
437           gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
438           vik_waypoint_set_symbol ( wp, sym );
439           g_free(sym);
440         }
441       }         
442
443       gtk_widget_destroy ( dialog );
444       
445       *updated = TRUE;
446       return NULL;
447     }
448   }
449   gtk_widget_destroy ( dialog );
450   return NULL;
451 }
452
453 static void get_selected_foreach_func(GtkTreeModel *model,
454                                       GtkTreePath *path,
455                                       GtkTreeIter *iter,
456                                       gpointer data)
457 {
458   GList **list = data;
459   gchar *name;
460   gtk_tree_model_get (model, iter, 0, &name, -1);
461   *list = g_list_prepend(*list, name);
462 }
463
464 GList *a_dialog_select_from_list ( GtkWindow *parent, GList *names, gboolean multiple_selection_allowed, const gchar *title, const gchar *msg )
465 {
466   GtkTreeIter iter;
467   GtkCellRenderer *renderer;
468   GtkWidget *view;
469
470   GtkWidget *dialog = gtk_dialog_new_with_buttons (title,
471                                                   parent,
472                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
473                                                   GTK_STOCK_CANCEL,
474                                                   GTK_RESPONSE_REJECT,
475                                                   GTK_STOCK_OK,
476                                                   GTK_RESPONSE_ACCEPT,
477                                                   NULL);
478   /* When something is selected then OK */
479   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
480   GtkWidget *response_w = NULL;
481 #if GTK_CHECK_VERSION (2, 20, 0)
482   /* Default to not apply - as initially nothing is selected! */
483   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
484 #endif
485   GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);
486
487   GtkWidget *scrolledwindow;
488
489   GList *runner = names;
490   while (runner)
491   {
492     gtk_list_store_append(store, &iter);
493     gtk_list_store_set(store, &iter, 0, runner->data, -1);
494     runner = g_list_next(runner);
495   }
496
497   view = gtk_tree_view_new();
498   renderer = gtk_cell_renderer_text_new();
499   // Use the column header to display the message text,
500   // this makes the overall widget allocation simple as treeview takes up all the space
501   GtkTreeViewColumn *column;
502   column = gtk_tree_view_column_new_with_attributes (msg, renderer, "text", 0, NULL );
503   gtk_tree_view_column_set_sort_column_id (column, 0);
504   gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
505
506   gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
507   gtk_tree_selection_set_mode( gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
508       multiple_selection_allowed ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE );
509   g_object_unref(store);
510
511   scrolledwindow = gtk_scrolled_window_new ( NULL, NULL );
512   gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
513   gtk_container_add ( GTK_CONTAINER(scrolledwindow), view );
514
515   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), scrolledwindow, TRUE, TRUE, 0 );
516   // Ensure a reasonable number of items are shown, but let the width be automatically sized
517   gtk_widget_set_size_request ( dialog, -1, 400) ;
518
519   gtk_widget_show_all ( dialog );
520
521   if ( response_w )
522     gtk_widget_grab_focus ( response_w );
523
524   while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
525   {
526     GList *names = NULL;
527     GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
528     gtk_tree_selection_selected_foreach(selection, get_selected_foreach_func, &names);
529     if (names)
530     {
531       gtk_widget_destroy ( dialog );
532       return (names);
533     }
534     a_dialog_error_msg(parent, _("Nothing was selected"));
535   }
536   gtk_widget_destroy ( dialog );
537   return NULL;
538 }
539
540 gchar *a_dialog_new_track ( GtkWindow *parent, GHashTable *tracks, gchar *default_name, gboolean is_route )
541 {
542   GtkWidget *dialog = gtk_dialog_new_with_buttons ( is_route ? _("Add Route") : _("Add Track"),
543                                                   parent,
544                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
545                                                   GTK_STOCK_CANCEL,
546                                                   GTK_RESPONSE_REJECT,
547                                                   GTK_STOCK_OK,
548                                                   GTK_RESPONSE_ACCEPT,
549                                                   NULL);
550   GtkWidget *label = gtk_label_new ( is_route ? _("Route Name:") : _("Track Name:") );
551   GtkWidget *entry = gtk_entry_new ();
552
553   if (default_name)
554     gtk_entry_set_text ( GTK_ENTRY(entry), default_name );
555
556   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, FALSE, FALSE, 0);
557   gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry, FALSE, FALSE, 0);
558
559   g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
560
561   gtk_widget_show ( label );
562   gtk_widget_show ( entry );
563
564   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
565
566   while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
567   {
568     const gchar *constname = gtk_entry_get_text ( GTK_ENTRY(entry) );
569     if ( *constname == '\0' )
570       a_dialog_info_msg ( parent, _("Please enter a name for the track.") );
571     else {
572       gchar *name = g_strdup ( constname );
573       gtk_widget_destroy ( dialog );
574       return name;
575     }
576   }
577   gtk_widget_destroy ( dialog );
578   return NULL;
579 }
580
581 /* creates a vbox full of labels */
582 GtkWidget *a_dialog_create_label_vbox ( gchar **texts, int label_count )
583 {
584   GtkWidget *vbox, *label;
585   int i;
586   vbox = gtk_vbox_new( TRUE, 3 );
587
588   for ( i = 0; i < label_count; i++ )
589   {
590     label = gtk_label_new(NULL);
591     gtk_label_set_markup ( GTK_LABEL(label), _(texts[i]) );
592     gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, TRUE, 5 );
593   }
594   return vbox;
595 }
596
597 gboolean a_dialog_yes_or_no ( GtkWindow *parent, const gchar *message, const gchar *extra )
598 {
599   GtkWidget *dia;
600   dia = gtk_message_dialog_new ( parent,
601                                  GTK_DIALOG_DESTROY_WITH_PARENT,
602                                  GTK_MESSAGE_QUESTION,
603                                  GTK_BUTTONS_YES_NO,
604                                  message, extra );
605
606   if ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_YES )
607   {
608     gtk_widget_destroy ( dia );
609     return TRUE;
610   }
611   else
612   {
613     gtk_widget_destroy ( dia );
614     return FALSE;
615   }
616 }
617
618 static void zoom_spin_changed ( GtkSpinButton *spin, GtkWidget *pass_along[3] )
619 {
620   if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(pass_along[2]) ) )
621     gtk_spin_button_set_value ( 
622         GTK_SPIN_BUTTON(pass_along[GTK_WIDGET(spin) == pass_along[0] ? 1 : 0]),
623         gtk_spin_button_get_value ( spin ) );
624 }
625
626 gboolean a_dialog_custom_zoom ( GtkWindow *parent, gdouble *xmpp, gdouble *ympp )
627 {
628   GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Zoom Factors..."),
629                                                   parent,
630                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
631                                                   GTK_STOCK_CANCEL,
632                                                   GTK_RESPONSE_REJECT,
633                                                   GTK_STOCK_OK,
634                                                   GTK_RESPONSE_ACCEPT,
635                                                   NULL);
636   GtkWidget *table, *label, *xlabel, *xspin, *ylabel, *yspin, *samecheck;
637   GtkWidget *pass_along[3];
638
639   table = gtk_table_new ( 4, 2, FALSE );
640   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
641
642   label = gtk_label_new ( _("Zoom factor (in meters per pixel):") );
643   xlabel = gtk_label_new ( _("X (easting): "));
644   ylabel = gtk_label_new ( _("Y (northing): "));
645
646   pass_along[0] = xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *xmpp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
647   pass_along[1] = yspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *ympp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
648
649   pass_along[2] = samecheck = gtk_check_button_new_with_label ( _("X and Y zoom factors must be equal") );
650   /* TODO -- same factor */
651   /*  samecheck = gtk_check_button_new_with_label ( "Same x/y zoom factor" ); */
652
653   if ( *xmpp == *ympp )
654     gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(samecheck), TRUE );
655
656   gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
657   gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 1, 2 );
658   gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 1, 2 );
659   gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 2, 3 );
660   gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 2, 3 );
661   gtk_table_attach_defaults ( GTK_TABLE(table), samecheck, 0, 2, 3, 4 );
662
663   gtk_widget_show_all ( table );
664
665   g_signal_connect ( G_OBJECT(xspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
666   g_signal_connect ( G_OBJECT(yspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
667
668   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
669
670   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
671   {
672     *xmpp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
673     *ympp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
674     gtk_widget_destroy ( dialog );
675     return TRUE;
676   }
677   gtk_widget_destroy ( dialog );
678   return FALSE;
679 }
680
681 static void split_spin_focused ( GtkSpinButton *spin, GtkWidget *pass_along[1] )
682 {
683   gtk_toggle_button_set_active    (GTK_TOGGLE_BUTTON(pass_along[0]), 1);
684 }
685
686 gboolean a_dialog_time_threshold ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint *thr )
687 {
688   GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text, 
689                                                   parent,
690                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
691                                                   GTK_STOCK_CANCEL,
692                                                   GTK_RESPONSE_REJECT,
693                                                   GTK_STOCK_OK,
694                                                   GTK_RESPONSE_ACCEPT,
695                                                   NULL);
696   GtkWidget *table, *t1, *t2, *t3, *t4, *spin, *label;
697   GtkWidget *pass_along[1];
698
699   table = gtk_table_new ( 4, 2, FALSE );
700   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
701
702   label = gtk_label_new (label_text);
703
704   t1 = gtk_radio_button_new_with_label ( NULL, _("1 min") );
705   t2 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t1), _("1 hour") );
706   t3 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t2), _("1 day") );
707   t4 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t3), _("Custom (in minutes):") );
708
709   pass_along[0] = t4;
710
711   spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *thr, 0, 65536, 1, 5, 0 ), 1, 0 );
712
713   gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
714   gtk_table_attach_defaults ( GTK_TABLE(table), t1, 0, 1, 1, 2 );
715   gtk_table_attach_defaults ( GTK_TABLE(table), t2, 0, 1, 2, 3 );
716   gtk_table_attach_defaults ( GTK_TABLE(table), t3, 0, 1, 3, 4 );
717   gtk_table_attach_defaults ( GTK_TABLE(table), t4, 0, 1, 4, 5 );
718   gtk_table_attach_defaults ( GTK_TABLE(table), spin, 1, 2, 4, 5 );
719
720   gtk_widget_show_all ( table );
721
722   g_signal_connect ( G_OBJECT(spin), "grab-focus", G_CALLBACK(split_spin_focused), pass_along );
723
724   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
725
726   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
727   {
728     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t1))) {
729       *thr = 1;
730     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t2))) {
731       *thr = 60;
732     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t3))) {
733       *thr = 60 * 24;
734     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t4))) {
735       *thr = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
736     }
737     gtk_widget_destroy ( dialog );
738     return TRUE;
739   }
740   gtk_widget_destroy ( dialog );
741   return FALSE;
742 }
743
744 /**
745  * Dialog to return a positive number via a spinbox within the supplied limits
746  * A return value of zero indicates the dialog was cancelled
747  */
748 guint a_dialog_get_positive_number ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint default_num, guint min, guint max, guint step )
749 {
750   GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text,
751                                                    parent,
752                                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
753                                                    GTK_STOCK_CANCEL,
754                                                    GTK_RESPONSE_REJECT,
755                                                    GTK_STOCK_OK,
756                                                    GTK_RESPONSE_ACCEPT,
757                                                    NULL);
758   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
759   GtkWidget *response_w = NULL;
760 #if GTK_CHECK_VERSION (2, 20, 0)
761   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
762 #endif
763
764   GtkWidget *table, *spin, *label;
765   guint result = default_num;
766
767   table = gtk_table_new ( 2, 1, FALSE );
768   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
769
770   label = gtk_label_new (label_text);
771   spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( default_num, min, max, step, 5, 0 ), 1, 0 );
772
773   gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 1, 0, 1 );
774   gtk_table_attach_defaults ( GTK_TABLE(table), spin, 0, 1, 1, 2 );
775
776   if ( response_w )
777     gtk_widget_grab_focus ( response_w );
778
779   gtk_widget_show_all ( table );
780
781   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
782   {
783     result = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
784     gtk_widget_destroy ( dialog );
785     return result;
786   }
787
788   // Dialog cancelled
789   gtk_widget_destroy ( dialog );
790   return 0;
791 }
792
793 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 24)
794 static void about_url_hook (GtkAboutDialog *about,
795                             const gchar    *link,
796                             gpointer        data)
797 {
798   open_url (GTK_WINDOW(about), link);
799 }
800
801 static void about_email_hook (GtkAboutDialog *about,
802                               const gchar    *email,
803                               gpointer        data)
804 {
805   new_email (GTK_WINDOW(about), email);
806 }
807 #endif
808
809 void a_dialog_about ( GtkWindow *parent )
810 {
811   const gchar *program_name = PACKAGE_NAME;
812   const gchar *version = VIKING_VERSION;
813   const gchar *website = VIKING_URL;
814   const gchar *copyright = "2003-2008, Evan Battaglia\n2008-2010, Viking's contributors";
815   const gchar *comments = _("GPS Data and Topo Analyzer, Explorer, and Manager.");
816   const gchar *license = _("This program is free software; you can redistribute it and/or modify "
817                         "it under the terms of the GNU General Public License as published by "
818                         "the Free Software Foundation; either version 2 of the License, or "
819                         "(at your option) any later version."
820                         "\n\n"
821                         "This program is distributed in the hope that it will be useful, "
822                         "but WITHOUT ANY WARRANTY; without even the implied warranty of "
823                         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the "
824                         "GNU General Public License for more details."
825                         "\n\n"
826                         "You should have received a copy of the GNU General Public License "
827                         "along with this program; if not, write to the Free Software "
828                         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA");
829
830   // Newer versions of GTK 'just work', calling gtk_show_uri() on the URL or email and opens up the appropriate program
831   // This is the old method:
832 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 24)
833   gtk_about_dialog_set_url_hook (about_url_hook, NULL, NULL);
834   gtk_about_dialog_set_email_hook (about_email_hook, NULL, NULL);
835 #endif
836   gtk_show_about_dialog (parent,
837         /* TODO do not set program-name and correctly set info for g_get_application_name */
838         "program-name", program_name,
839         "version", version,
840         "website", website,
841         "comments", comments,
842         "copyright", copyright,
843         "license", license,
844         "wrap-license", TRUE,
845         /* logo automatically retrieved via gtk_window_get_default_icon_list */
846         "authors", AUTHORS,
847         "documenters", DOCUMENTERS,
848         "translator-credits", _("Translation is coordinated on http://launchpad.net/viking"),
849         NULL);
850 }
851
852 gboolean a_dialog_map_n_zoom(GtkWindow *parent, gchar *mapnames[], gint default_map, gchar *zoom_list[], gint default_zoom, gint *selected_map, gint *selected_zoom)
853 {
854   gchar **s;
855
856   GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Download along track"), parent, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
857   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
858   GtkWidget *response_w = NULL;
859 #if GTK_CHECK_VERSION (2, 20, 0)
860   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
861 #endif
862
863   GtkWidget *map_label = gtk_label_new(_("Map type:"));
864   GtkWidget *map_combo = vik_combo_box_text_new();
865   for (s = mapnames; *s; s++)
866     vik_combo_box_text_append (GTK_COMBO_BOX(map_combo), *s);
867   gtk_combo_box_set_active (GTK_COMBO_BOX(map_combo), default_map);
868
869   GtkWidget *zoom_label = gtk_label_new(_("Zoom level:"));
870   GtkWidget *zoom_combo = vik_combo_box_text_new();
871   for (s = zoom_list; *s; s++)
872     vik_combo_box_text_append (GTK_COMBO_BOX(zoom_combo), *s);
873   gtk_combo_box_set_active (GTK_COMBO_BOX(zoom_combo), default_zoom);
874
875   GtkTable *box = GTK_TABLE(gtk_table_new(2, 2, FALSE));
876   gtk_table_attach_defaults(box, map_label, 0, 1, 0, 1);
877   gtk_table_attach_defaults(box, map_combo, 1, 2, 0, 1);
878   gtk_table_attach_defaults(box, zoom_label, 0, 1, 1, 2);
879   gtk_table_attach_defaults(box, zoom_combo, 1, 2, 1, 2);
880
881   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
882
883   if ( response_w )
884     gtk_widget_grab_focus ( response_w );
885
886   gtk_widget_show_all ( dialog );
887   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
888     gtk_widget_destroy(dialog);
889     return FALSE;
890   }
891
892   *selected_map = gtk_combo_box_get_active(GTK_COMBO_BOX(map_combo));
893   *selected_zoom = gtk_combo_box_get_active(GTK_COMBO_BOX(zoom_combo));
894
895   gtk_widget_destroy(dialog);
896   return TRUE;
897 }
898
899 /**
900  * Display a dialog presenting the license of a map.
901  * Allow to read the license by launching a web browser.
902  */
903 void a_dialog_license ( GtkWindow *parent, const gchar *map, const gchar *license, const gchar *url)
904 {
905   GtkWidget *dialog = gtk_message_dialog_new (parent,
906                                  GTK_DIALOG_DESTROY_WITH_PARENT,
907                                  GTK_MESSAGE_INFO,
908                                  GTK_BUTTONS_OK,
909                                  _("The map data is licensed: %s."),
910                                  license);
911   gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
912     _("The data provided by '<b>%s</b>' are licensed under the following license: <b>%s</b>.\n"
913     "Please, read the license before continuing."),
914     map, license);
915 #define RESPONSE_OPEN_LICENSE 600
916   if (url != NULL) {
917     gtk_dialog_add_button (GTK_DIALOG (dialog), _("Open license"), RESPONSE_OPEN_LICENSE);
918   }
919   gint response;
920   do {
921     response = gtk_dialog_run (GTK_DIALOG (dialog));
922     if (response == RESPONSE_OPEN_LICENSE) {
923       open_url (parent, url);
924     }
925   } while (response != GTK_RESPONSE_DELETE_EVENT && response != GTK_RESPONSE_OK);
926   gtk_widget_destroy (dialog);
927 }