]> git.street.me.uk Git - andy/viking.git/blame_incremental - src/dialog.c
Fix incorrect GPSBabel/Garmin symbol names.
[andy/viking.git] / src / dialog.c
... / ...
CommitLineData
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
43void 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
50gboolean 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(dialog)->vbox), latlabel, FALSE, FALSE, 0);
82 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lat, FALSE, FALSE, 0);
83 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonlabel, FALSE, FALSE, 0);
84 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 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
100gboolean 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(dialog)->vbox), norlabel, FALSE, FALSE, 0);
148 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), nor, FALSE, FALSE, 0);
149 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), easlabel, FALSE, FALSE, 0);
150 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), eas, FALSE, FALSE, 0);
151 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 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
172void a_dialog_response_accept ( GtkDialog *dialog )
173{
174 gtk_dialog_response ( dialog, GTK_RESPONSE_ACCEPT );
175}
176
177static 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 */
197gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, 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(dialog)->vbox), 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(dialog)->vbox), 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(dialog)->vbox), latlabel, FALSE, FALSE, 0);
333 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), latentry, FALSE, FALSE, 0);
334 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonlabel, FALSE, FALSE, 0);
335 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonentry, FALSE, FALSE, 0);
336 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), altlabel, FALSE, FALSE, 0);
337 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), altentry, FALSE, FALSE, 0);
338 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), commentlabel, FALSE, FALSE, 0);
339 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), commententry, FALSE, FALSE, 0);
340 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), descriptionlabel, FALSE, FALSE, 0);
341 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), descriptionentry, FALSE, FALSE, 0);
342 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), imagelabel, FALSE, FALSE, 0);
343 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), imageentry, FALSE, FALSE, 0);
344 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), symbollabel, FALSE, FALSE, 0);
345 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), 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(dialog)->vbox );
350
351 while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
352 {
353 if ( is_new )
354 {
355 if ( strlen((gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) )) == 0 ) /* TODO: other checks (isalpha or whatever ) */
356 a_dialog_info_msg ( parent, _("Please enter a name for the waypoint.") );
357 else {
358 // NB: No check for unique names - this allows generation of same named entries.
359 gchar *entered_name = g_strdup ( (gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) ) );
360
361 /* Do It */
362 ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
363 ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
364 vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
365 // Always store in metres
366 switch (height_units) {
367 case VIK_UNITS_HEIGHT_METRES:
368 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
369 break;
370 case VIK_UNITS_HEIGHT_FEET:
371 wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
372 break;
373 default:
374 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
375 g_critical("Houston, we've had a problem. height=%d", height_units);
376 }
377 vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
378 vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
379 vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
380 if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
381 a_thumbnails_create ( wp->image );
382
383 GtkTreeIter iter, first;
384 gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
385 if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
386 vik_waypoint_set_symbol ( wp, NULL );
387 } else {
388 gchar *sym;
389 gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
390 vik_waypoint_set_symbol ( wp, sym );
391 g_free(sym);
392 }
393
394 gtk_widget_destroy ( dialog );
395 return entered_name;
396 }
397 }
398 else
399 {
400 ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
401 ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
402 vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
403 switch (height_units) {
404 case VIK_UNITS_HEIGHT_METRES:
405 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
406 break;
407 case VIK_UNITS_HEIGHT_FEET:
408 wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
409 break;
410 default:
411 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
412 g_critical("Houston, we've had a problem. height=%d", height_units);
413 }
414 if ( (! wp->comment) || strcmp ( wp->comment, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ) != 0 )
415 vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
416 if ( (! wp->description) || strcmp ( wp->description, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) ) != 0 )
417 vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
418 if ( (! wp->image) || strcmp ( wp->image, vik_file_entry_get_filename ( VIK_FILE_ENTRY ( imageentry ) ) ) != 0 )
419 {
420 vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
421 if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
422 a_thumbnails_create ( wp->image );
423 }
424
425 {
426 GtkTreeIter iter, first;
427 gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
428 if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
429 vik_waypoint_set_symbol ( wp, NULL );
430 } else {
431 gchar *sym;
432 gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
433 vik_waypoint_set_symbol ( wp, sym );
434 g_free(sym);
435 }
436 }
437
438 gtk_widget_destroy ( dialog );
439
440 *updated = TRUE;
441 return NULL;
442 }
443 }
444 gtk_widget_destroy ( dialog );
445 return NULL;
446}
447
448static void get_selected_foreach_func(GtkTreeModel *model,
449 GtkTreePath *path,
450 GtkTreeIter *iter,
451 gpointer data)
452{
453 GList **list = data;
454 gchar *name;
455 gtk_tree_model_get (model, iter, 0, &name, -1);
456 *list = g_list_prepend(*list, name);
457}
458
459GList *a_dialog_select_from_list ( GtkWindow *parent, GList *names, gboolean multiple_selection_allowed, const gchar *title, const gchar *msg )
460{
461 GtkTreeIter iter;
462 GtkCellRenderer *renderer;
463 GtkWidget *view;
464
465 GtkWidget *dialog = gtk_dialog_new_with_buttons (title,
466 parent,
467 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
468 GTK_STOCK_CANCEL,
469 GTK_RESPONSE_REJECT,
470 GTK_STOCK_OK,
471 GTK_RESPONSE_ACCEPT,
472 NULL);
473 /* When something is selected then OK */
474 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
475 GtkWidget *response_w = NULL;
476#if GTK_CHECK_VERSION (2, 20, 0)
477 /* Default to not apply - as initially nothing is selected! */
478 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
479#endif
480 GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);
481
482 GtkWidget *scrolledwindow;
483
484 GList *runner = names;
485 while (runner)
486 {
487 gtk_list_store_append(store, &iter);
488 gtk_list_store_set(store, &iter, 0, runner->data, -1);
489 runner = g_list_next(runner);
490 }
491
492 view = gtk_tree_view_new();
493 renderer = gtk_cell_renderer_text_new();
494 // Use the column header to display the message text,
495 // this makes the overall widget allocation simple as treeview takes up all the space
496 GtkTreeViewColumn *column;
497 column = gtk_tree_view_column_new_with_attributes (msg, renderer, "text", 0, NULL );
498 gtk_tree_view_column_set_sort_column_id (column, 0);
499 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
500
501 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
502 gtk_tree_selection_set_mode( gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
503 multiple_selection_allowed ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE );
504 g_object_unref(store);
505
506 scrolledwindow = gtk_scrolled_window_new ( NULL, NULL );
507 gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
508 gtk_container_add ( GTK_CONTAINER(scrolledwindow), view );
509
510 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), scrolledwindow, TRUE, TRUE, 0 );
511 // Ensure a reasonable number of items are shown, but let the width be automatically sized
512 gtk_widget_set_size_request ( dialog, -1, 400) ;
513
514 gtk_widget_show_all ( dialog );
515
516 if ( response_w )
517 gtk_widget_grab_focus ( response_w );
518
519 while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
520 {
521 GList *names = NULL;
522 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
523 gtk_tree_selection_selected_foreach(selection, get_selected_foreach_func, &names);
524 if (names)
525 {
526 gtk_widget_destroy ( dialog );
527 return (names);
528 }
529 a_dialog_error_msg(parent, _("Nothing was selected"));
530 }
531 gtk_widget_destroy ( dialog );
532 return NULL;
533}
534
535gchar *a_dialog_new_track ( GtkWindow *parent, GHashTable *tracks, gchar *default_name, gboolean is_route )
536{
537 GtkWidget *dialog = gtk_dialog_new_with_buttons ( is_route ? _("Add Route") : _("Add Track"),
538 parent,
539 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
540 GTK_STOCK_CANCEL,
541 GTK_RESPONSE_REJECT,
542 GTK_STOCK_OK,
543 GTK_RESPONSE_ACCEPT,
544 NULL);
545 GtkWidget *label = gtk_label_new ( is_route ? _("Route Name:") : _("Track Name:") );
546 GtkWidget *entry = gtk_entry_new ();
547
548 if (default_name)
549 gtk_entry_set_text ( GTK_ENTRY(entry), default_name );
550
551 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), label, FALSE, FALSE, 0);
552 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE, FALSE, 0);
553
554 g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
555
556 gtk_widget_show ( label );
557 gtk_widget_show ( entry );
558
559 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
560
561 while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
562 {
563 const gchar *constname = gtk_entry_get_text ( GTK_ENTRY(entry) );
564 if ( *constname == '\0' )
565 a_dialog_info_msg ( parent, _("Please enter a name for the track.") );
566 else {
567 gchar *name = g_strdup ( constname );
568 gtk_widget_destroy ( dialog );
569 return name;
570 }
571 }
572 gtk_widget_destroy ( dialog );
573 return NULL;
574}
575
576/* creates a vbox full of labels */
577GtkWidget *a_dialog_create_label_vbox ( gchar **texts, int label_count )
578{
579 GtkWidget *vbox, *label;
580 int i;
581 vbox = gtk_vbox_new( TRUE, 3 );
582
583 for ( i = 0; i < label_count; i++ )
584 {
585 label = gtk_label_new(NULL);
586 gtk_label_set_markup ( GTK_LABEL(label), _(texts[i]) );
587 gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, TRUE, 5 );
588 }
589 return vbox;
590}
591
592gboolean a_dialog_yes_or_no ( GtkWindow *parent, const gchar *message, const gchar *extra )
593{
594 GtkWidget *dia;
595 dia = gtk_message_dialog_new ( parent,
596 GTK_DIALOG_DESTROY_WITH_PARENT,
597 GTK_MESSAGE_QUESTION,
598 GTK_BUTTONS_YES_NO,
599 message, extra );
600
601 if ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_YES )
602 {
603 gtk_widget_destroy ( dia );
604 return TRUE;
605 }
606 else
607 {
608 gtk_widget_destroy ( dia );
609 return FALSE;
610 }
611}
612
613static void zoom_spin_changed ( GtkSpinButton *spin, GtkWidget *pass_along[3] )
614{
615 if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(pass_along[2]) ) )
616 gtk_spin_button_set_value (
617 GTK_SPIN_BUTTON(pass_along[GTK_WIDGET(spin) == pass_along[0] ? 1 : 0]),
618 gtk_spin_button_get_value ( spin ) );
619}
620
621gboolean a_dialog_custom_zoom ( GtkWindow *parent, gdouble *xmpp, gdouble *ympp )
622{
623 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Zoom Factors..."),
624 parent,
625 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
626 GTK_STOCK_CANCEL,
627 GTK_RESPONSE_REJECT,
628 GTK_STOCK_OK,
629 GTK_RESPONSE_ACCEPT,
630 NULL);
631 GtkWidget *table, *label, *xlabel, *xspin, *ylabel, *yspin, *samecheck;
632 GtkWidget *pass_along[3];
633
634 table = gtk_table_new ( 4, 2, FALSE );
635 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
636
637 label = gtk_label_new ( _("Zoom factor (in meters per pixel):") );
638 xlabel = gtk_label_new ( _("X (easting): "));
639 ylabel = gtk_label_new ( _("Y (northing): "));
640
641 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 );
642 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 );
643
644 pass_along[2] = samecheck = gtk_check_button_new_with_label ( _("X and Y zoom factors must be equal") );
645 /* TODO -- same factor */
646 /* samecheck = gtk_check_button_new_with_label ( "Same x/y zoom factor" ); */
647
648 if ( *xmpp == *ympp )
649 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(samecheck), TRUE );
650
651 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
652 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 1, 2 );
653 gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 1, 2 );
654 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 2, 3 );
655 gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 2, 3 );
656 gtk_table_attach_defaults ( GTK_TABLE(table), samecheck, 0, 2, 3, 4 );
657
658 gtk_widget_show_all ( table );
659
660 g_signal_connect ( G_OBJECT(xspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
661 g_signal_connect ( G_OBJECT(yspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
662
663 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
664
665 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
666 {
667 *xmpp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
668 *ympp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
669 gtk_widget_destroy ( dialog );
670 return TRUE;
671 }
672 gtk_widget_destroy ( dialog );
673 return FALSE;
674}
675
676static void split_spin_focused ( GtkSpinButton *spin, GtkWidget *pass_along[1] )
677{
678 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(pass_along[0]), 1);
679}
680
681gboolean a_dialog_time_threshold ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint *thr )
682{
683 GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text,
684 parent,
685 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
686 GTK_STOCK_CANCEL,
687 GTK_RESPONSE_REJECT,
688 GTK_STOCK_OK,
689 GTK_RESPONSE_ACCEPT,
690 NULL);
691 GtkWidget *table, *t1, *t2, *t3, *t4, *spin, *label;
692 GtkWidget *pass_along[1];
693
694 table = gtk_table_new ( 4, 2, FALSE );
695 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
696
697 label = gtk_label_new (label_text);
698
699 t1 = gtk_radio_button_new_with_label ( NULL, _("1 min") );
700 t2 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t1), _("1 hour") );
701 t3 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t2), _("1 day") );
702 t4 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t3), _("Custom (in minutes):") );
703
704 pass_along[0] = t4;
705
706 spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *thr, 0, 65536, 1, 5, 0 ), 1, 0 );
707
708 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
709 gtk_table_attach_defaults ( GTK_TABLE(table), t1, 0, 1, 1, 2 );
710 gtk_table_attach_defaults ( GTK_TABLE(table), t2, 0, 1, 2, 3 );
711 gtk_table_attach_defaults ( GTK_TABLE(table), t3, 0, 1, 3, 4 );
712 gtk_table_attach_defaults ( GTK_TABLE(table), t4, 0, 1, 4, 5 );
713 gtk_table_attach_defaults ( GTK_TABLE(table), spin, 1, 2, 4, 5 );
714
715 gtk_widget_show_all ( table );
716
717 g_signal_connect ( G_OBJECT(spin), "grab-focus", G_CALLBACK(split_spin_focused), pass_along );
718
719 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
720
721 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
722 {
723 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t1))) {
724 *thr = 1;
725 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t2))) {
726 *thr = 60;
727 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t3))) {
728 *thr = 60 * 24;
729 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t4))) {
730 *thr = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
731 }
732 gtk_widget_destroy ( dialog );
733 return TRUE;
734 }
735 gtk_widget_destroy ( dialog );
736 return FALSE;
737}
738
739/**
740 * Dialog to return a positive number via a spinbox within the supplied limits
741 * A return value of zero indicates the dialog was cancelled
742 */
743guint a_dialog_get_positive_number ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint default_num, guint min, guint max, guint step )
744{
745 GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text,
746 parent,
747 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
748 GTK_STOCK_CANCEL,
749 GTK_RESPONSE_REJECT,
750 GTK_STOCK_OK,
751 GTK_RESPONSE_ACCEPT,
752 NULL);
753 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
754 GtkWidget *response_w = NULL;
755#if GTK_CHECK_VERSION (2, 20, 0)
756 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
757#endif
758
759 GtkWidget *table, *spin, *label;
760 guint result = default_num;
761
762 table = gtk_table_new ( 2, 1, FALSE );
763 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
764
765 label = gtk_label_new (label_text);
766 spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( default_num, min, max, step, 5, 0 ), 1, 0 );
767
768 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 1, 0, 1 );
769 gtk_table_attach_defaults ( GTK_TABLE(table), spin, 0, 1, 1, 2 );
770
771 if ( response_w )
772 gtk_widget_grab_focus ( response_w );
773
774 gtk_widget_show_all ( table );
775
776 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
777 {
778 result = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
779 gtk_widget_destroy ( dialog );
780 return result;
781 }
782
783 // Dialog cancelled
784 gtk_widget_destroy ( dialog );
785 return 0;
786}
787
788static void about_url_hook (GtkAboutDialog *about,
789 const gchar *link,
790 gpointer data)
791{
792 open_url (GTK_WINDOW(about), link);
793}
794
795static void about_email_hook (GtkAboutDialog *about,
796 const gchar *email,
797 gpointer data)
798{
799 new_email (GTK_WINDOW(about), email);
800}
801
802void a_dialog_about ( GtkWindow *parent )
803{
804 const gchar *program_name = PACKAGE_NAME;
805 const gchar *version = VIKING_VERSION;
806 const gchar *website = VIKING_URL;
807 const gchar *copyright = "2003-2008, Evan Battaglia\n2008-2010, Viking's contributors";
808 const gchar *comments = _("GPS Data and Topo Analyzer, Explorer, and Manager.");
809 const gchar *license = _("This program is free software; you can redistribute it and/or modify "
810 "it under the terms of the GNU General Public License as published by "
811 "the Free Software Foundation; either version 2 of the License, or "
812 "(at your option) any later version."
813 "\n\n"
814 "This program is distributed in the hope that it will be useful, "
815 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
816 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
817 "GNU General Public License for more details."
818 "\n\n"
819 "You should have received a copy of the GNU General Public License "
820 "along with this program; if not, write to the Free Software "
821 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA");
822
823 gtk_about_dialog_set_url_hook (about_url_hook, NULL, NULL);
824 gtk_about_dialog_set_email_hook (about_email_hook, NULL, NULL);
825 gtk_show_about_dialog (parent,
826 /* TODO do not set program-name and correctly set info for g_get_application_name */
827 "program-name", program_name,
828 "version", version,
829 "website", website,
830 "comments", comments,
831 "copyright", copyright,
832 "license", license,
833 "wrap-license", TRUE,
834 /* logo automatically retrieved via gtk_window_get_default_icon_list */
835 "authors", AUTHORS,
836 "documenters", DOCUMENTERS,
837 "translator-credits", _("Translation is coordinated on http://launchpad.net/viking"),
838 NULL);
839}
840
841gboolean a_dialog_map_n_zoom(GtkWindow *parent, gchar *mapnames[], gint default_map, gchar *zoom_list[], gint default_zoom, gint *selected_map, gint *selected_zoom)
842{
843 gchar **s;
844
845 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 );
846 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
847 GtkWidget *response_w = NULL;
848#if GTK_CHECK_VERSION (2, 20, 0)
849 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
850#endif
851 GtkWidget *map_label = gtk_label_new(_("Map type:"));
852 GtkComboBox *map_combo = GTK_COMBO_BOX(gtk_combo_box_new_text());
853 for (s = mapnames; *s; s++)
854 gtk_combo_box_append_text(map_combo, *s);
855 gtk_combo_box_set_active (map_combo, default_map);
856 GtkWidget *zoom_label = gtk_label_new(_("Zoom level:"));
857 GtkComboBox *zoom_combo = GTK_COMBO_BOX(gtk_combo_box_new_text());
858 for (s = zoom_list; *s; s++)
859 gtk_combo_box_append_text(zoom_combo, *s);
860 gtk_combo_box_set_active (zoom_combo, default_zoom);
861
862 GtkTable *box = GTK_TABLE(gtk_table_new(2, 2, FALSE));
863 gtk_table_attach_defaults(box, GTK_WIDGET(map_label), 0, 1, 0, 1);
864 gtk_table_attach_defaults(box, GTK_WIDGET(map_combo), 1, 2, 0, 1);
865 gtk_table_attach_defaults(box, GTK_WIDGET(zoom_label), 0, 1, 1, 2);
866 gtk_table_attach_defaults(box, GTK_WIDGET(zoom_combo), 1, 2, 1, 2);
867
868 gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(box), FALSE, FALSE, 5 );
869
870 if ( response_w )
871 gtk_widget_grab_focus ( response_w );
872
873 gtk_widget_show_all ( dialog );
874 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
875 gtk_widget_destroy(dialog);
876 return FALSE;
877 }
878
879 *selected_map = gtk_combo_box_get_active(map_combo);
880 *selected_zoom = gtk_combo_box_get_active(zoom_combo);
881
882 gtk_widget_destroy(dialog);
883 return TRUE;
884}
885
886/**
887 * Display a dialog presenting the license of a map.
888 * Allow to read the license by launching a web browser.
889 */
890void a_dialog_license ( GtkWindow *parent, const gchar *map, const gchar *license, const gchar *url)
891{
892 GtkWidget *dialog = gtk_message_dialog_new (parent,
893 GTK_DIALOG_DESTROY_WITH_PARENT,
894 GTK_MESSAGE_INFO,
895 GTK_BUTTONS_OK,
896 _("The map data is licensed: %s."),
897 license);
898 gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
899 _("The data provided by '<b>%s</b>' are licensed under the following license: <b>%s</b>.\n"
900 "Please, read the license before continuing."),
901 map, license);
902#define RESPONSE_OPEN_LICENSE 600
903 if (url != NULL) {
904 gtk_dialog_add_button (GTK_DIALOG (dialog), _("Open license"), RESPONSE_OPEN_LICENSE);
905 }
906 gint response;
907 do {
908 response = gtk_dialog_run (GTK_DIALOG (dialog));
909 if (response == RESPONSE_OPEN_LICENSE) {
910 open_url (parent, url);
911 }
912 } while (response != GTK_RESPONSE_DELETE_EVENT && response != GTK_RESPONSE_OK);
913 gtk_widget_destroy (dialog);
914}