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