Contents of /trunk/src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 185 - (show annotations)
Mon Jun 29 14:07:46 2009 UTC (14 years, 10 months ago) by harbaum
File MIME type: text/plain
File size: 36213 byte(s)
Started wizard implementation
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of OSM2Go.
5 *
6 * OSM2Go is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OSM2Go is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <curl/curl.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "appdata.h"
27 #include "banner.h"
28
29 /* disable/enable main screen control dependant on presence of open project */
30 static void main_ui_enable(appdata_t *appdata) {
31 gboolean project_valid = (appdata->project != NULL);
32 gboolean osm_valid = (appdata->osm != NULL);
33
34 /* cancel any action in progress */
35 if(GTK_WIDGET_FLAGS(appdata->iconbar->cancel) & GTK_SENSITIVE)
36 map_action_cancel(appdata);
37
38 /* ---- set project name as window title ----- */
39 #if defined(USE_HILDON) && MAEMO_VERSION_MAJOR < 5
40 if(project_valid)
41 gtk_window_set_title(GTK_WINDOW(appdata->window), appdata->project->name);
42 else
43 gtk_window_set_title(GTK_WINDOW(appdata->window), "");
44 #else
45 char *str = NULL;
46 if(project_valid)
47 str = g_strdup_printf("OSM2Go - %s", appdata->project->name);
48 else
49 str = g_strdup_printf("OSM2Go");
50
51 gtk_window_set_title(GTK_WINDOW(appdata->window), str);
52 g_free(str);
53 #endif
54
55 if(appdata->iconbar && appdata->iconbar->toolbar)
56 gtk_widget_set_sensitive(appdata->iconbar->toolbar, osm_valid);
57
58 /* disable all menu entries related to map */
59 gtk_widget_set_sensitive(appdata->menu_osm, project_valid);
60 gtk_widget_set_sensitive(appdata->menu_item_osm_upload, osm_valid);
61 if(appdata->menu_item_osm_undo)
62 gtk_widget_set_sensitive(appdata->menu_item_osm_undo, osm_valid);
63 gtk_widget_set_sensitive(appdata->menu_item_osm_save_changes, osm_valid);
64 gtk_widget_set_sensitive(appdata->menu_item_osm_undo_changes, osm_valid);
65 gtk_widget_set_sensitive(appdata->menu_item_osm_relations, osm_valid);
66 gtk_widget_set_sensitive(appdata->track.menu_track, osm_valid);
67 gtk_widget_set_sensitive(appdata->menu_view, osm_valid);
68 gtk_widget_set_sensitive(appdata->menu_wms, osm_valid);
69 gtk_widget_set_sensitive(appdata->menu_map, osm_valid);
70
71 if(!project_valid)
72 statusbar_set(appdata, _("Please load or create a project"), FALSE);
73 }
74
75 /******************** begin of menu *********************/
76
77 static void
78 cb_menu_project_open(GtkMenuItem *item, gpointer data) {
79 appdata_t *appdata = (appdata_t*)data;
80 project_load(appdata, NULL);
81 main_ui_enable(appdata);
82 }
83
84 static void
85 cb_menu_project_wizard(GtkMenuItem *item, gpointer data) {
86 appdata_t *appdata = (appdata_t*)data;
87 project_wizard(appdata);
88 }
89
90 static void
91 cb_menu_about(GtkMenuItem *item, gpointer data) {
92 appdata_t *appdata = (appdata_t*)data;
93
94 const gchar *authors[] = {
95 "Till Harbaum <till@harbaum.org>",
96 "Andrew Chadwick <andrewc-osm2go@piffle.org>",
97 NULL };
98
99 const gchar *artists[] = {
100 "Andrew Zhilin <drew.zhilin@gmail.com>",
101 NULL };
102
103 gtk_show_about_dialog(GTK_WINDOW(appdata->window),
104 "name", "OSM2Go",
105 "version", VERSION,
106 "copyright", _("Copyright 2008-2009"),
107 "authors", authors,
108 "artists", artists,
109 "website", _("http://www.harbaum.org/till/maemo"),
110 "comments", _("Mobile OSM Editor"),
111 NULL);
112 }
113
114 void on_window_destroy (GtkWidget *widget, gpointer data);
115
116 static void
117 cb_menu_quit(GtkMenuItem *item, gpointer data) {
118 appdata_t *appdata = (appdata_t*)data;
119 gtk_widget_destroy(GTK_WIDGET(appdata->window));
120 }
121
122 static void
123 cb_menu_upload(GtkMenuItem *item, gpointer data) {
124 appdata_t *appdata = (appdata_t*)data;
125 if(!appdata->osm || !appdata->project) return;
126
127 if(project_check_demo(GTK_WIDGET(appdata->window), appdata->project))
128 return;
129
130 osm_upload(appdata, appdata->osm, appdata->project);
131 }
132
133 static void
134 cb_menu_download(GtkMenuItem *item, gpointer data) {
135 appdata_t *appdata = (appdata_t*)data;
136 if(!appdata->project) return;
137
138 if(project_check_demo(GTK_WIDGET(appdata->window), appdata->project))
139 return;
140
141 /* if we have valid osm data loaded: save state first */
142 if(appdata->osm) {
143 /* redraw the entire map by destroying all map items and redrawing them */
144 diff_save(appdata->project, appdata->osm);
145 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
146 osm_free(&appdata->icon, appdata->osm);
147
148 appdata->osm = NULL;
149 }
150
151 // download
152 if(osm_download(GTK_WIDGET(appdata->window), appdata->settings,
153 appdata->project)) {
154 banner_busy_start(appdata, 1, "Redrawing");
155 appdata->osm = osm_parse(appdata->project->path, appdata->project->osm);
156 diff_restore(appdata, appdata->project, appdata->osm);
157 map_paint(appdata);
158 banner_busy_stop(appdata); //"Redrawing"
159 }
160
161 main_ui_enable(appdata);
162 }
163
164 static void
165 cb_menu_wms_import(GtkMenuItem *item, gpointer data) {
166 appdata_t *appdata = (appdata_t*)data;
167 wms_import(appdata);
168 }
169
170 static void
171 cb_menu_wms_clear(GtkMenuItem *item, gpointer data) {
172 appdata_t *appdata = (appdata_t*)data;
173 wms_remove(appdata);
174 }
175
176 static void
177 cb_menu_wms_adjust(GtkMenuItem *item, gpointer data) {
178 appdata_t *appdata = (appdata_t*)data;
179 map_action_set(appdata, MAP_ACTION_BG_ADJUST);
180 }
181
182 /* ----------- hide objects for performance reasons ----------- */
183
184 static void
185 cb_menu_map_hide_sel(GtkMenuItem *item, gpointer data) {
186 appdata_t *appdata = (appdata_t*)data;
187 map_hide_selected(appdata);
188 }
189
190 static void
191 cb_menu_map_show_all(GtkMenuItem *item, gpointer data) {
192 appdata_t *appdata = (appdata_t*)data;
193 map_show_all(appdata);
194 }
195
196 /* ---------------------------------------------------------- */
197
198 #if 1 // mainly for testing
199 static void
200 cb_menu_redraw(GtkMenuItem *item, gpointer data) {
201 appdata_t *appdata = (appdata_t*)data;
202
203 /* redraw the entire map by destroying all map items and redrawing them */
204 banner_busy_start(appdata, 1, "Redrawing");
205 track_save(appdata->project, appdata->track.track);
206 diff_save(appdata->project, appdata->osm);
207 map_clear(appdata, MAP_LAYER_ALL);
208 osm_free(&appdata->icon, appdata->osm);
209
210 appdata->osm = osm_parse(appdata->project->path, appdata->project->osm);
211 diff_restore(appdata, appdata->project, appdata->osm);
212 map_paint(appdata);
213
214 appdata->track.track = track_restore(appdata, appdata->project);
215 if(appdata->track.track)
216 map_track_draw(appdata->map, appdata->track.track);
217
218 wms_load(appdata);
219 banner_busy_stop(appdata); //"Redrawing"
220 }
221 #endif
222
223 static void
224 cb_menu_map_no_icons(GtkCheckMenuItem *item, gpointer data) {
225 appdata_t *appdata = (appdata_t*)data;
226
227 banner_busy_start(appdata, 1, "Redrawing");
228 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
229 appdata->settings->no_icons = gtk_check_menu_item_get_active(item);
230 map_paint(appdata);
231 banner_busy_stop(appdata); //"Redrawing"
232 }
233
234 static void
235 cb_menu_map_no_antialias(GtkCheckMenuItem *item, gpointer data) {
236 appdata_t *appdata = (appdata_t*)data;
237
238 banner_busy_start(appdata, 1, "Redrawing");
239 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
240 appdata->settings->no_antialias = gtk_check_menu_item_get_active(item);
241 map_paint(appdata);
242 banner_busy_stop(appdata); //"Redrawing"
243 }
244
245 static void
246 cb_menu_style(GtkMenuItem *item, gpointer data) {
247 appdata_t *appdata = (appdata_t*)data;
248
249 style_select(GTK_WIDGET(appdata->window), appdata);
250 }
251
252 static void
253 cb_menu_undo(GtkMenuItem *item, gpointer data) {
254 appdata_t *appdata = (appdata_t*)data;
255
256 undo(appdata);
257
258 // the banner will be displayed from within undo with more details
259 }
260
261 static void
262 cb_menu_save_changes(GtkMenuItem *item, gpointer data) {
263 appdata_t *appdata = (appdata_t*)data;
264
265 diff_save(appdata->project, appdata->osm);
266 banner_show_info(appdata, _("Saved local changes"));
267 }
268
269 static void
270 cb_menu_undo_changes(GtkMenuItem *item, gpointer data) {
271 appdata_t *appdata = (appdata_t*)data;
272
273 if(!yes_no_f(GTK_WIDGET(appdata->window), NULL, 0, 0,
274 _("Discard local changes?"),
275 _("Throw away all the changes you've not "
276 "uploaded yet? This can't be undone.")))
277 return;
278
279 banner_busy_start(appdata, 1, _("Redrawing"));
280 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
281 osm_free(&appdata->icon, appdata->osm);
282 diff_remove(appdata->project);
283 appdata->osm = osm_parse(appdata->project->path, appdata->project->osm);
284 map_paint(appdata);
285 banner_busy_stop(appdata); //"Redrawing"
286
287 banner_show_info(appdata, _("Discarded local changes"));
288 }
289
290 static void
291 cb_menu_osm_relations(GtkMenuItem *item, gpointer data) {
292 relation_list((appdata_t*)data);
293 }
294
295 #if !defined(USE_HILDON) || (MAEMO_VERSION_MAJOR < 5)
296 static void
297 cb_menu_fullscreen(GtkCheckMenuItem *item, gpointer data) {
298 appdata_t *appdata = (appdata_t *)data;
299
300 if(gtk_check_menu_item_get_active(item))
301 gtk_window_fullscreen(GTK_WINDOW(appdata->window));
302 else
303 gtk_window_unfullscreen(GTK_WINDOW(appdata->window));
304 }
305 #endif
306
307 static void
308 cb_menu_zoomin(GtkMenuItem *item, appdata_t *appdata) {
309 if(!appdata || !appdata->map) return;
310
311 map_set_zoom(appdata->map, appdata->map->state->zoom*ZOOM_FACTOR_MENU, TRUE);
312 printf("zoom is now %f\n", appdata->map->state->zoom);
313 }
314
315 static void
316 cb_menu_zoomout(GtkMenuItem *item, appdata_t *appdata) {
317 if(!appdata || !appdata->map) return;
318
319 map_set_zoom(appdata->map, appdata->map->state->zoom/ZOOM_FACTOR_MENU, TRUE);
320 printf("zoom is now %f\n", appdata->map->state->zoom);
321 }
322
323 static void
324 cb_menu_view_detail_inc(GtkMenuItem *item, gpointer data) {
325 appdata_t *appdata = (appdata_t*)data;
326
327 printf("detail level increase\n");
328 map_detail_increase(appdata->map);
329 }
330
331 static void
332 cb_menu_view_detail_normal(GtkMenuItem *item, gpointer data) {
333 appdata_t *appdata = (appdata_t*)data;
334
335 printf("detail level normal\n");
336 map_detail_normal(appdata->map);
337 }
338
339 static void
340 cb_menu_view_detail_dec(GtkMenuItem *item, gpointer data) {
341 appdata_t *appdata = (appdata_t*)data;
342
343 printf("detail level decrease\n");
344 map_detail_decrease(appdata->map);
345 }
346
347 static void
348 cb_menu_track_import(GtkMenuItem *item, appdata_t *appdata) {
349 g_assert(appdata->settings);
350
351 /* open a file selector */
352 GtkWidget *dialog;
353
354 #ifdef USE_HILDON
355 dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(appdata->window),
356 GTK_FILE_CHOOSER_ACTION_OPEN);
357 #else
358 dialog = gtk_file_chooser_dialog_new (_("Import track file"),
359 GTK_WINDOW(appdata->window),
360 GTK_FILE_CHOOSER_ACTION_OPEN,
361 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
362 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
363 NULL);
364 #endif
365
366 if(appdata->settings->track_path) {
367 if(!g_file_test(appdata->settings->track_path, G_FILE_TEST_EXISTS)) {
368 char *last_sep = strrchr(appdata->settings->track_path, '/');
369 if(last_sep) {
370 *last_sep = 0; // seperate path from file
371
372 /* the user just created a new document */
373 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
374 appdata->settings->track_path);
375 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
376 last_sep+1);
377
378 /* restore full filename */
379 *last_sep = '/';
380 }
381 } else
382 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
383 appdata->settings->track_path);
384 }
385
386 gtk_widget_show_all (GTK_WIDGET(dialog));
387 if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
388 char *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
389
390 /* load a track */
391 appdata->track.track = track_import(appdata, filename);
392 if(appdata->track.track) {
393 if(appdata->settings->track_path) g_free(appdata->settings->track_path);
394 appdata->settings->track_path = g_strdup(filename);
395 }
396 g_free (filename);
397 }
398
399 gtk_widget_destroy (dialog);
400 }
401
402 static void
403 cb_menu_track_enable_gps(GtkMenuItem *item, gpointer data) {
404 appdata_t *appdata = (appdata_t*)data;
405
406 if(gtk_check_menu_item_get_active(
407 GTK_CHECK_MENU_ITEM(appdata->track.menu_item_enable_gps))) {
408 track_enable_gps(appdata, TRUE);
409 } else
410 track_enable_gps(appdata, FALSE);
411 }
412
413
414 static void
415 cb_menu_track_follow_gps(GtkMenuItem *item, gpointer data) {
416 appdata_t *appdata = (appdata_t*)data;
417
418 if(gtk_check_menu_item_get_active(
419 GTK_CHECK_MENU_ITEM(appdata->track.menu_item_follow_gps))) {
420 appdata->settings->follow_gps = TRUE;
421 } else
422 appdata->settings->follow_gps = FALSE;
423 }
424
425
426 static void
427 cb_menu_track_export(GtkMenuItem *item, appdata_t *appdata) {
428 g_assert(appdata->settings);
429
430 /* open a file selector */
431 GtkWidget *dialog;
432
433 #ifdef USE_HILDON
434 dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(appdata->window),
435 GTK_FILE_CHOOSER_ACTION_SAVE);
436 #else
437 dialog = gtk_file_chooser_dialog_new(_("Export track file"),
438 GTK_WINDOW(appdata->window),
439 GTK_FILE_CHOOSER_ACTION_SAVE,
440 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
441 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
442 NULL);
443 #endif
444
445 printf("set filename <%s>\n", appdata->settings->track_path);
446
447 if(appdata->settings->track_path) {
448 if(!g_file_test(appdata->settings->track_path, G_FILE_TEST_EXISTS)) {
449 char *last_sep = strrchr(appdata->settings->track_path, '/');
450 if(last_sep) {
451 *last_sep = 0; // seperate path from file
452
453 /* the user just created a new document */
454 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
455 appdata->settings->track_path);
456 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
457 last_sep+1);
458
459 /* restore full filename */
460 *last_sep = '/';
461 }
462 } else
463 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
464 appdata->settings->track_path);
465 }
466
467 if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_FM_OK) {
468 gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
469 if(filename) {
470 printf("export to %s\n", filename);
471
472 if(!g_file_test(filename, G_FILE_TEST_EXISTS) ||
473 yes_no_f(dialog, appdata, MISC_AGAIN_ID_EXPORT_OVERWRITE,
474 MISC_AGAIN_FLAG_DONT_SAVE_NO,
475 "Overwrite existing file",
476 "The file already exists. "
477 "Do you really want to replace it?")) {
478 if(appdata->settings->track_path)
479 g_free(appdata->settings->track_path);
480 appdata->settings->track_path = g_strdup(filename);
481
482 track_export(appdata, filename);
483 }
484 }
485 }
486
487 gtk_widget_destroy (dialog);
488 }
489
490
491 static void
492 cb_menu_track_clear(GtkMenuItem *item, gpointer data) {
493 appdata_t *appdata = (appdata_t*)data;
494 track_clear(appdata, appdata->track.track);
495 appdata->track.track = NULL;
496 }
497
498
499
500
501 /*
502 * Platform-specific UI tweaks.
503 */
504
505
506 #ifndef USE_HILDON
507 #ifdef PORTRAIT
508
509 // Portrait mode, for openmoko-like systems
510 #define uispecific_main_menu_new gtk_menu_new
511
512 #else
513
514 // Regular desktop builds
515 #define uispecific_main_menu_new gtk_menu_bar_new
516 #define UISPECIFIC_MAIN_MENU_IS_MENU_BAR
517 #define UISPECIFIC_MENU_HAS_ICONS
518 #define UISPECIFIC_MENU_HAS_ACCELS
519
520 #endif //PORTRAIT
521 #else//USE_HILDON
522
523 // Maemo/Hildon builds
524 #define uispecific_main_menu_new gtk_menu_new
525
526 #endif
527
528
529
530 // Half-arsed slapdash common menu item constructor. Let's use GtkBuilder
531 // instead so we have some flexibility.
532
533 static GtkWidget *
534 menu_append_new_item(appdata_t *appdata,
535 GtkWidget *menu_shell,
536 GtkSignalFunc activate_cb,
537 char *label,
538 const gchar *icon_name, // stock id or name for icon_load
539 // overridden by label, accels, icon_name
540 const gchar *accel_path,
541 guint accel_key, // from gdk/gdkkeysyms.h
542 GdkModifierType accel_mods, // e.g. GDK_CONTROL_MASK
543 gboolean enabled,
544 gboolean is_check, gboolean check_status)
545 {
546 GtkWidget *item = NULL;
547 GtkWidget *image = NULL;
548
549 gboolean stock_item_known = FALSE;
550 GtkStockItem stock_item;
551 if (icon_name != NULL) {
552 stock_item_known = gtk_stock_lookup(icon_name, &stock_item);
553 }
554
555 // Icons
556 #ifndef UISPECIFIC_MENU_HAS_ICONS
557 item = is_check ? gtk_check_menu_item_new_with_mnemonic (label)
558 : gtk_menu_item_new_with_mnemonic (label);
559 #else
560 if (is_check) {
561 item = gtk_check_menu_item_new_with_mnemonic (label);
562 }
563 else if (!stock_item_known) {
564 GdkPixbuf *pbuf = icon_load(&appdata->icon, icon_name);
565 if (pbuf) {
566 image = gtk_image_new_from_pixbuf(pbuf);
567 }
568 if (image) {
569 item = gtk_image_menu_item_new_with_mnemonic(label);
570 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
571 }
572 else {
573 item = gtk_menu_item_new_with_mnemonic(label);
574 }
575 }
576 else {
577 item = gtk_image_menu_item_new_with_mnemonic(label);
578 image = gtk_image_new_from_stock(icon_name, GTK_ICON_SIZE_MENU);
579 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
580 }
581 #endif
582
583 #ifdef UISPECIFIC_MENU_HAS_ACCELS
584 // Accelerators
585 // Default
586 if (accel_path != NULL) {
587 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
588 if (accel_key != 0) {
589 gtk_accel_map_add_entry( accel_path, accel_key, accel_mods );
590 }
591 else if (stock_item_known) {
592 gtk_accel_map_add_entry( accel_path, stock_item.keyval,
593 stock_item.modifier );
594 }
595 }
596 #endif
597
598 gtk_menu_shell_append(GTK_MENU_SHELL(menu_shell), GTK_WIDGET(item));
599 gtk_widget_set_sensitive(GTK_WIDGET(item), enabled);
600 if (is_check)
601 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), check_status);
602
603 g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(activate_cb),
604 appdata);
605 return item;
606 }
607
608
609 void menu_create(appdata_t *appdata) {
610 GtkWidget *menu, *item, *submenu;
611 GtkWidget *about_quit_items_menu;
612
613 if (g_module_supported()) {
614 printf("*** can use GModule: consider using GtkUIManager / GtkBuilder\n");
615 }
616
617 menu = uispecific_main_menu_new();
618 about_quit_items_menu = menu;
619
620 /* -------------------- Project submenu -------------------- */
621
622 GtkAccelGroup *accel_grp = gtk_accel_group_new();
623 item = gtk_menu_item_new_with_mnemonic( _("_Project") );
624 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
625 submenu = gtk_menu_new();
626 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
627 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
628 #ifdef UISPECIFIC_MAIN_MENU_IS_MENU_BAR
629 about_quit_items_menu = submenu;
630 #endif
631
632 menu_append_new_item(
633 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_project_open), _("_Open"),
634 GTK_STOCK_OPEN, "<OSM2Go-Main>/Project/Open",
635 0, 0, TRUE, FALSE, FALSE
636 );
637
638 menu_append_new_item(
639 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_project_wizard), _("_Wizard"),
640 GTK_STOCK_NEW, "<OSM2Go-Main>/Project/Wizard",
641 0, 0, TRUE, FALSE, FALSE
642 );
643
644 /* --------------- view menu ------------------- */
645
646 #ifndef UISPECIFIC_MAIN_MENU_IS_MENU_BAR
647 gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
648 #endif
649
650 appdata->menu_view = item = gtk_menu_item_new_with_mnemonic( _("_View") );
651 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
652 submenu = gtk_menu_new();
653 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
654 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
655
656 #if !defined(USE_HILDON) || (MAEMO_VERSION_MAJOR < 5)
657 appdata->menu_item_view_fullscreen = menu_append_new_item(
658 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_fullscreen), _("_Fullscreen"),
659 GTK_STOCK_FULLSCREEN, "<OSM2Go-Main>/View/Fullscreen",
660 0, 0, TRUE, TRUE, FALSE
661 );
662 #endif
663
664 menu_append_new_item(
665 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_zoomin), _("Zoom _in"),
666 GTK_STOCK_ZOOM_IN, "<OSM2Go-Main>/View/ZoomIn",
667 GDK_comma, GDK_CONTROL_MASK, TRUE, FALSE, FALSE
668 );
669
670 menu_append_new_item(
671 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_zoomout), _("Zoom _out"),
672 GTK_STOCK_ZOOM_OUT, "<OSM2Go-Main>/View/ZoomOut",
673 GDK_period, GDK_CONTROL_MASK, TRUE, FALSE, FALSE
674 );
675
676 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
677
678 menu_append_new_item(
679 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_view_detail_inc), _("More details"),
680 NULL, "<OSM2Go-Main>/View/DetailInc",
681 GDK_period, GDK_MOD1_MASK, TRUE, FALSE, FALSE
682 );
683
684 menu_append_new_item(
685 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_view_detail_normal), _("Normal details"),
686 NULL, "<OSM2Go-Main>/View/DetailNormal",
687 0, 0, TRUE, FALSE, FALSE
688 );
689
690 menu_append_new_item(
691 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_view_detail_dec), _("Less details"),
692 NULL, "<OSM2Go-Main>/View/DetailDec",
693 GDK_comma, GDK_MOD1_MASK, TRUE, FALSE, FALSE
694 );
695
696 /* -------------------- OSM submenu -------------------- */
697
698 appdata->menu_osm = item = gtk_menu_item_new_with_mnemonic( _("_OSM") );
699 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
700 submenu = gtk_menu_new();
701 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
702 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
703
704 appdata->menu_item_osm_upload = menu_append_new_item(
705 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_upload), _("_Upload"),
706 "upload.16", "<OSM2Go-Main>/OSM/Upload",
707 GDK_u, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE
708 );
709
710 menu_append_new_item(
711 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_download), _("_Download"),
712 "download.16", "<OSM2Go-Main>/OSM/Download",
713 GDK_d, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE
714 );
715
716 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
717
718 if(getenv("OSM2GO_UNDO_TEST")) {
719 appdata->menu_item_osm_undo = menu_append_new_item(
720 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_undo), _("_Undo"),
721 GTK_STOCK_UNDO, "<OSM2Go-Main>/OSM/Undo",
722 GDK_z, GDK_CONTROL_MASK, TRUE, FALSE, FALSE
723 );
724 } else
725 printf("set environment variable OSM2GO_UNDO_TEST to enable undo framework tests\n");
726
727 appdata->menu_item_osm_save_changes = menu_append_new_item(
728 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_save_changes), _("_Save local changes"),
729 GTK_STOCK_SAVE, "<OSM2Go-Main>/OSM/SaveChanges",
730 GDK_s, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE
731 );
732
733 appdata->menu_item_osm_undo_changes = menu_append_new_item(
734 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_undo_changes), _("Disca_rd local changes"),
735 GTK_STOCK_DELETE, "<OSM2Go-Main>/OSM/DiscardChanges",
736 0, 0, TRUE, FALSE, FALSE
737 );
738
739 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
740 appdata->menu_item_osm_relations = menu_append_new_item(
741 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_osm_relations), _("_Relations"),
742 NULL, "<OSM2Go-Main>/OSM/Relations",
743 GDK_r, GDK_SHIFT_MASK|GDK_CONTROL_MASK, TRUE, FALSE, FALSE
744 );
745
746 /* -------------------- wms submenu -------------------- */
747
748 appdata->menu_wms = item = gtk_menu_item_new_with_mnemonic( _("_WMS") );
749 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
750 submenu = gtk_menu_new();
751 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
752 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
753
754 menu_append_new_item(
755 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_import), _("_Import"),
756 GTK_STOCK_INDEX, "<OSM2Go-Main>/WMS/Import",
757 0, 0, TRUE, FALSE, FALSE
758 );
759
760 appdata->menu_item_wms_clear = menu_append_new_item(
761 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_clear), _("_Clear"),
762 GTK_STOCK_CLEAR, "<OSM2Go-Main>/WMS/Clear",
763 0, 0, TRUE, FALSE, FALSE
764 );
765 gtk_widget_set_sensitive(appdata->menu_item_wms_clear, FALSE);
766
767 appdata->menu_item_wms_adjust = menu_append_new_item(
768 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_wms_adjust), _("_Adjust"),
769 NULL, "<OSM2Go-Main>/WMS/Adjust",
770 0, 0, TRUE, FALSE, FALSE
771 );
772 gtk_widget_set_sensitive(appdata->menu_item_wms_adjust, FALSE);
773
774 /* -------------------- map submenu -------------------- */
775
776 appdata->menu_map = item = gtk_menu_item_new_with_mnemonic( _("_Map") );
777 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
778 submenu = gtk_menu_new();
779 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
780 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
781
782 appdata->menu_item_map_hide_sel = menu_append_new_item(
783 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_hide_sel), _("_Hide selected"),
784 GTK_STOCK_REMOVE, "<OSM2Go-Main>/Map/HideSelected",
785 0, 0, TRUE, FALSE, FALSE
786 );
787 gtk_widget_set_sensitive(appdata->menu_item_map_hide_sel, FALSE);
788
789 appdata->menu_item_map_show_all = menu_append_new_item(
790 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_show_all), _("_Show all"),
791 GTK_STOCK_ADD, "<OSM2Go-Main>/Map/ShowAll",
792 0, 0, TRUE, FALSE, FALSE
793 );
794 gtk_widget_set_sensitive(appdata->menu_item_map_show_all, FALSE);
795
796 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
797
798 menu_append_new_item(
799 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_style), _("St_yle"),
800 GTK_STOCK_SELECT_COLOR, "<OSM2Go-Main>/Map/Style",
801 0, 0, TRUE, FALSE, FALSE
802 );
803
804 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
805
806 /* switches mainly intended for testing/debugging */
807 menu_append_new_item(
808 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_redraw), _("_Redraw"),
809 NULL, "<OSM2Go-Main>/Map/Redraw",
810 GDK_r, GDK_CONTROL_MASK, TRUE, FALSE, FALSE
811 );
812
813 appdata->menu_item_map_no_icons = menu_append_new_item(
814 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_no_icons), _("No _icons"),
815 NULL, "<OSM2Go-Main>/Map/NoIcons",
816 0, 0, TRUE, TRUE, appdata->settings->no_icons
817 );
818
819 appdata->menu_item_map_no_antialias = menu_append_new_item(
820 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_map_no_antialias),
821 _("No _antialias"),
822 NULL, "<OSM2Go-Main>/Map/NoAntialias",
823 0, 0, TRUE, TRUE, appdata->settings->no_antialias
824 );
825
826 /* -------------------- track submenu -------------------- */
827
828 appdata->track.menu_track = item = gtk_menu_item_new_with_mnemonic(_("_Track"));
829 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
830 submenu = gtk_menu_new();
831 gtk_menu_set_accel_group(GTK_MENU(submenu), accel_grp);
832 gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
833
834 appdata->track.menu_item_import = menu_append_new_item(
835 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_import), _("_Import"),
836 NULL, "<OSM2Go-Main>/Track/Import",
837 0, 0, TRUE, FALSE, FALSE
838 );
839
840 appdata->track.menu_item_export = menu_append_new_item(
841 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_export), _("_Export"),
842 NULL, "<OSM2Go-Main>/Track/Export",
843 0, 0, FALSE, FALSE, FALSE
844 );
845
846 appdata->track.menu_item_clear = menu_append_new_item(
847 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_clear), _("_Clear"),
848 GTK_STOCK_CLEAR, "<OSM2Go-Main>/Track/Clear",
849 0, 0, FALSE, FALSE, FALSE
850 );
851
852
853 appdata->track.menu_item_enable_gps = menu_append_new_item(
854 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_enable_gps),_("_GPS enable"),
855 NULL, "<OSM2Go-Main>/Track/GPS",
856 GDK_g, GDK_CONTROL_MASK|GDK_SHIFT_MASK, TRUE, TRUE,
857 appdata->settings->enable_gps
858 );
859
860 appdata->track.menu_item_follow_gps = menu_append_new_item(
861 appdata, submenu, GTK_SIGNAL_FUNC(cb_menu_track_follow_gps), _("GPS follow"),
862 NULL, "<OSM2Go-Main>/Track/Follow",
863 0, 0, appdata->settings->enable_gps, TRUE,
864 appdata->settings->follow_gps
865 );
866
867 /* ------------------------------------------------------- */
868
869 gtk_menu_shell_append(GTK_MENU_SHELL(about_quit_items_menu),
870 gtk_separator_menu_item_new());
871
872 menu_append_new_item(
873 appdata, about_quit_items_menu, GTK_SIGNAL_FUNC(cb_menu_about), _("_About"),
874 GTK_STOCK_ABOUT, "<OSM2Go-Main>/About",
875 0, 0, TRUE, FALSE, FALSE
876 );
877
878 menu_append_new_item(
879 appdata, about_quit_items_menu, GTK_SIGNAL_FUNC(cb_menu_quit), _("_Quit"),
880 GTK_STOCK_QUIT, "<OSM2Go-Main>/Quit",
881 0, 0, TRUE, FALSE, FALSE
882 );
883
884 gtk_window_add_accel_group(GTK_WINDOW(appdata->window), accel_grp);
885
886 #ifdef USE_HILDON
887 hildon_window_set_menu(appdata->window, GTK_MENU(menu));
888 #else
889 GtkWidget *menu_bar = menu;
890
891 #ifndef UISPECIFIC_MAIN_MENU_IS_MENU_BAR
892 // we need to make one first
893 menu_bar = gtk_menu_bar_new();
894
895 GtkWidget *root_menu = gtk_menu_item_new_with_label (_("Menu"));
896 gtk_widget_show(root_menu);
897
898 gtk_menu_bar_append(menu_bar, root_menu);
899 gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
900
901 gtk_widget_show(menu_bar);
902 #endif //UISPECIFIC_MAIN_MENU_IS_MENU_BAR
903
904 gtk_box_pack_start(GTK_BOX(appdata->vbox), menu_bar, 0, 0, 0);
905
906 #endif //USE_HILDON
907 }
908
909 /********************* end of menu **********************/
910
911 #ifdef UISPECIFIC_MENU_HAS_ACCELS
912 #define ACCELS_FILE "accels"
913
914 static void menu_accels_load(appdata_t *appdata) {
915 char *accels_file = g_strdup_printf("%s/" ACCELS_FILE,
916 appdata->settings->base_path);
917 gtk_accel_map_load(accels_file);
918 g_free(accels_file);
919 }
920
921 static void menu_accels_save(appdata_t *appdata) {
922 char *accels_file = g_strdup_printf("%s" ACCELS_FILE,
923 appdata->settings->base_path);
924 gtk_accel_map_save(accels_file);
925 g_free(accels_file);
926 }
927
928 #endif
929
930
931 void cleanup(appdata_t *appdata) {
932 #ifdef UISPECIFIC_MENU_HAS_ACCELS
933 menu_accels_save(appdata);
934 #endif
935
936 settings_save(appdata->settings);
937
938 #ifdef USE_HILDON
939 if(appdata->osso_context)
940 osso_deinitialize(appdata->osso_context);
941
942 appdata->program = NULL;
943 #endif
944
945 printf("waiting for gtk to shut down ");
946
947 /* let gtk clean up first */
948 while(gtk_events_pending()) {
949 putchar('.');
950 gtk_main_iteration();
951 }
952
953 printf(" ok\n");
954
955 /* save project file */
956 if(appdata->project)
957 project_save(GTK_WIDGET(appdata->window), appdata->project);
958
959 map_remove_bg_image(appdata->map);
960
961 osm_free(&appdata->icon, appdata->osm);
962
963 curl_global_cleanup();
964
965 josm_presets_free(appdata->presets);
966
967 icon_free_all(&appdata->icon);
968
969 gps_release(appdata);
970
971 settings_free(appdata->settings);
972
973 statusbar_free(appdata->statusbar);
974
975 iconbar_free(appdata->iconbar);
976
977 project_free(appdata->project);
978
979 if(appdata->menu_item_osm_undo)
980 undo_free(appdata->undo.state);
981
982 puts("everything is gone");
983 }
984
985 void on_window_destroy (GtkWidget *widget, gpointer data) {
986 appdata_t *appdata = (appdata_t*)data;
987
988 gtk_main_quit();
989 appdata->window = NULL;
990 }
991
992 gboolean on_window_key_press(GtkWidget *widget,
993 GdkEventKey *event, gpointer data) {
994 appdata_t *appdata = (appdata_t*)data;
995 int handled = FALSE;
996
997 // the map handles some keys on its own ...
998 switch(event->keyval) {
999
1000 #ifdef USE_HILDON
1001 /* this is in fact a mapping to GDK_F6 */
1002 case HILDON_HARDKEY_FULLSCREEN:
1003 #else
1004 case GDK_F11:
1005 #endif
1006 if(!gtk_check_menu_item_get_active(
1007 GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen))) {
1008 gtk_window_fullscreen(GTK_WINDOW(appdata->window));
1009 gtk_check_menu_item_set_active(
1010 GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen), TRUE);
1011 } else {
1012 gtk_window_unfullscreen(GTK_WINDOW(appdata->window));
1013 gtk_check_menu_item_set_active(
1014 GTK_CHECK_MENU_ITEM(appdata->menu_item_view_fullscreen), FALSE);
1015 }
1016
1017 handled = TRUE;
1018 break;
1019 }
1020
1021 /* forward unprocessed key presses to map */
1022 if(!handled && appdata->project && appdata->osm)
1023 handled = map_key_press_event(appdata, event);
1024
1025 return handled;
1026 }
1027
1028 int main(int argc, char *argv[]) {
1029 appdata_t appdata;
1030
1031 /* init appdata */
1032 memset(&appdata, 0, sizeof(appdata));
1033
1034 printf("Using locale for %s in %s\n", PACKAGE, LOCALEDIR);
1035
1036 setlocale(LC_ALL, "");
1037 bindtextdomain(PACKAGE, LOCALEDIR);
1038 bind_textdomain_codeset(PACKAGE, "UTF-8");
1039 textdomain(PACKAGE);
1040
1041 /* Must initialize libcurl before any threads are started */
1042 curl_global_init(CURL_GLOBAL_ALL);
1043
1044 g_thread_init(NULL);
1045
1046 gtk_init (&argc, &argv);
1047
1048 gps_init(&appdata);
1049
1050 #ifdef USE_HILDON
1051 printf("Installing osso context for \"org.harbaum." PACKAGE "\"\n");
1052 appdata.osso_context = osso_initialize("org.harbaum."PACKAGE,
1053 VERSION, TRUE, NULL);
1054 if(appdata.osso_context == NULL)
1055 fprintf(stderr, "error initiating osso context\n");
1056
1057 dbus_register(&appdata);
1058 #endif
1059
1060 #ifdef USE_HILDON
1061 /* Create the hildon program and setup the title */
1062 appdata.program = HILDON_PROGRAM(hildon_program_get_instance());
1063 g_set_application_name("OSM2Go");
1064
1065 /* Create HildonWindow and set it to HildonProgram */
1066 appdata.window = HILDON_WINDOW(hildon_window_new());
1067 hildon_program_add_window(appdata.program, appdata.window);
1068 #else
1069 /* Create a Window. */
1070 appdata.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1071 gtk_window_set_title(GTK_WINDOW(appdata.window), "OSM2Go");
1072 /* Set a decent default size for the window. */
1073 gtk_window_set_default_size(GTK_WINDOW(appdata.window),
1074 DEFAULT_WIDTH, DEFAULT_HEIGHT);
1075 gtk_window_set_icon(GTK_WINDOW(appdata.window),
1076 icon_load(&appdata.icon, PACKAGE));
1077 #endif
1078
1079 g_signal_connect(G_OBJECT(appdata.window), "destroy",
1080 G_CALLBACK(on_window_destroy), &appdata);
1081
1082 g_signal_connect(G_OBJECT(appdata.window), "key_press_event",
1083 G_CALLBACK(on_window_key_press), &appdata);
1084
1085 /* user specific init */
1086 appdata.settings = settings_load();
1087
1088 appdata.vbox = gtk_vbox_new(FALSE,0);
1089 menu_create(&appdata);
1090 #ifdef UISPECIFIC_MENU_HAS_ACCELS
1091 menu_accels_load(&appdata);
1092 #endif
1093
1094 /* ----------------------- setup main window ---------------- */
1095
1096 GtkWidget *hbox = gtk_hbox_new(FALSE,0);
1097 GtkWidget *vbox = gtk_vbox_new(FALSE,0);
1098
1099 #ifdef PORTRAIT
1100 gtk_box_pack_start(GTK_BOX(vbox), iconbar_new(&appdata), FALSE, FALSE, 0);
1101 #endif
1102
1103 /* generate main map view */
1104 GtkWidget *map = map_new(&appdata);
1105 if(!map) {
1106 cleanup(&appdata);
1107 return -1;
1108 }
1109
1110 gtk_box_pack_start(GTK_BOX(vbox), map, TRUE, TRUE, 0);
1111 gtk_box_pack_start(GTK_BOX(vbox), statusbar_new(&appdata), FALSE, FALSE, 0);
1112
1113 #ifndef PORTRAIT
1114 gtk_box_pack_start(GTK_BOX(hbox), iconbar_new(&appdata), FALSE, FALSE, 0);
1115 #endif
1116 // gtk_box_pack_start(GTK_BOX(hbox), gtk_vseparator_new(), FALSE, FALSE, 0);
1117 gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
1118
1119 gtk_box_pack_start(GTK_BOX(appdata.vbox), hbox, TRUE, TRUE, 0);
1120
1121 gtk_container_add(GTK_CONTAINER(appdata.window), appdata.vbox);
1122
1123 gtk_widget_show_all(GTK_WIDGET(appdata.window));
1124
1125 appdata.presets = josm_presets_load();
1126
1127 /* let gtk do its thing before loading the data, */
1128 /* so the user sees something */
1129 while(gtk_events_pending())
1130 gtk_main_iteration();
1131
1132 /* load project if one is specified in the settings */
1133 if(appdata.settings->project)
1134 project_load(&appdata, appdata.settings->project);
1135
1136 main_ui_enable(&appdata);
1137
1138 /* start GPS if enabled by config */
1139 if(appdata.settings && appdata.settings->enable_gps)
1140 track_enable_gps(&appdata, TRUE);
1141
1142 /* again let the ui do its thing */
1143 while(gtk_events_pending())
1144 gtk_main_iteration();
1145
1146 /* start to interact with the user now that the gui is running */
1147 if(appdata.settings->first_run_demo) {
1148 messagef(GTK_WIDGET(appdata.window), _("Welcome to OSM2Go"),
1149 _("This is the first time you run OSM2Go. "
1150 "A demo project has been loaded to get you "
1151 "started. You can play around with this demo as much "
1152 "as you like. However, you cannot upload or download "
1153 "the demo project.\n\n"
1154 "In order to start working on real data you'll have "
1155 "to setup a new project and enter your OSM user name "
1156 "and password. You'll then be able to download the "
1157 "latest data from OSM and upload your changes into "
1158 "the OSM main database."
1159 ));
1160 }
1161
1162 /* ------------ jump into main loop ---------------- */
1163 gtk_main();
1164
1165 puts("gtk_main() left");
1166
1167 track_save(appdata.project, appdata.track.track);
1168 track_clear(&appdata, appdata.track.track);
1169 appdata.track.track = NULL;
1170
1171 /* save a diff if there are dirty entries */
1172 diff_save(appdata.project, appdata.osm);
1173
1174 cleanup(&appdata);
1175
1176 return 0;
1177 }
1178
1179 // vim:et:ts=8:sw=2:sts=2:ai