X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/1bc1c05ba5f58d69e95fe5bf50e472a5e8735988..c6acf18ddc123a52e92f0757310cefc9292b46a7:/src/vikwindow.c diff --git a/src/vikwindow.c b/src/vikwindow.c index 89a8a823..c1f98f83 100644 --- a/src/vikwindow.c +++ b/src/vikwindow.c @@ -3,7 +3,7 @@ * * Copyright (C) 2003-2005, Evan Battaglia * Copyright (C) 2005-2006, Alex Foobarian - * Copyright (C) 2012, Rob Norris + * Copyright (C) 2012-2013, Rob Norris * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,6 +37,7 @@ #include "viklayer_defaults.h" #include "icons/icons.h" #include "vikexttools.h" +#include "vikexttool_datasources.h" #include "garminsymbols.h" #include "vikmapslayer.h" #include "geonamessearch.h" @@ -85,7 +86,6 @@ static void newwindow_cb ( GtkAction *a, VikWindow *vw ); // Signals static void open_window ( VikWindow *vw, GSList *files ); -static void statusbar_update ( VikWindow *vw, vik_statusbar_type_t vs_type, const gchar *message ); static void destroy_window ( GtkWidget *widget, gpointer data ); @@ -178,6 +178,7 @@ struct _VikWindow { gchar *filename; gboolean modified; + VikLoadType_t loaded_type; GtkWidget *open_dia, *save_dia; GtkWidget *save_img_dia, *save_img_dir_dia; @@ -214,7 +215,6 @@ enum { enum { VW_NEWWINDOW_SIGNAL, VW_OPENWINDOW_SIGNAL, - VW_STATUSBAR_UPDATE_SIGNAL, VW_LAST_SIGNAL }; @@ -243,35 +243,48 @@ VikStatusbar * vik_window_get_statusbar ( VikWindow *vw ) return vw->viking_vs; } -/** - * For signalling the update from a background thread - */ -void vik_window_signal_statusbar_update (VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type) -{ - g_signal_emit ( G_OBJECT(vw), window_signals[VW_STATUSBAR_UPDATE_SIGNAL], 0, vs_type, message ); -} +typedef struct { + VikStatusbar *vs; + vik_statusbar_type_t vs_type; + gchar* message; // Always make a copy of this data +} statusbar_idle_data; /** * For the actual statusbar update! */ -static gboolean statusbar_idle_update ( gpointer indata ) +static gboolean statusbar_idle_update ( statusbar_idle_data *sid ) { - gpointer *data = indata; - vik_statusbar_set_message ( data[0], GPOINTER_TO_INT(data[2]), data[1] ); + vik_statusbar_set_message ( sid->vs, sid->vs_type, sid->message ); + g_free ( sid->message ); + g_free ( sid ); return FALSE; } /** - * Update statusbar in the main thread + * vik_window_statusbar_update: + * @vw: The main window in which the statusbar will be updated. + * @message: The string to be displayed. This is copied. + * @vs_type: The part of the statusbar to be updated. + * + * This updates any part of the statusbar with the new string. + * It handles calling from the main thread or any background thread + * ATM this mostly used from background threads - as from the main thread + * one may use the vik_statusbar_set_message() directly. */ -static void window_statusbar_update ( VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type ) +void vik_window_statusbar_update ( VikWindow *vw, const gchar* message, vik_statusbar_type_t vs_type ) { - // ATM we know the message has been statically allocated so this is OK (no need to handle any freeing) - static gpointer data[3]; - data[0] = vw->viking_vs; - data[1] = (gchar*) message; - data[2] = GINT_TO_POINTER(vs_type); - g_idle_add ( (GSourceFunc) statusbar_idle_update, data ); + statusbar_idle_data *sid = g_malloc ( sizeof (statusbar_idle_data) ); + sid->vs = vw->viking_vs; + sid->vs_type = vs_type; + sid->message = g_strdup ( message ); + + if ( g_thread_self() == vik_window_get_thread ( vw ) ) { + g_idle_add ( (GSourceFunc) statusbar_idle_update, sid ); + } + else { + // From a background thread + gdk_threads_add_idle ( (GSourceFunc) statusbar_idle_update, sid ); + } } // Actual signal handlers @@ -282,10 +295,13 @@ static void destroy_window ( GtkWidget *widget, gtk_main_quit (); } -static void statusbar_update ( VikWindow *vw, vik_statusbar_type_t vs_type, const gchar *message ) -{ - window_statusbar_update ( vw, message, vs_type ); -} +#define VIK_SETTINGS_WIN_SIDEPANEL "window_sidepanel" +#define VIK_SETTINGS_WIN_STATUSBAR "window_statusbar" +#define VIK_SETTINGS_WIN_TOOLBAR "window_toolbar" +// Menubar setting to off is never auto saved in case it's accidentally turned off +// It's not so obvious so to recover the menu visibility. +// Thus this value is for setting manually via editting the settings file directly +#define VIK_SETTINGS_WIN_MENUBAR "window_menubar" VikWindow *vik_window_new_window () { @@ -299,11 +315,43 @@ VikWindow *vik_window_new_window () G_CALLBACK (vik_window_new_window), NULL); g_signal_connect (G_OBJECT (vw), "openwindow", G_CALLBACK (open_window), NULL); - g_signal_connect (G_OBJECT (vw), "statusbarupdate", - G_CALLBACK (statusbar_update), vw); gtk_widget_show_all ( GTK_WIDGET(vw) ); + if ( a_vik_get_restore_window_state() ) { + // These settings are applied after the show all as these options hide widgets + gboolean sidepanel; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_SIDEPANEL, &sidepanel ) ) + if ( ! sidepanel ) { + gtk_widget_hide ( GTK_WIDGET(vw->viking_vlp) ); + GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewSidePanel" ); + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE ); + } + + gboolean statusbar; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_STATUSBAR, &statusbar ) ) + if ( ! statusbar ) { + gtk_widget_hide ( GTK_WIDGET(vw->viking_vs) ); + GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewStatusBar" ); + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE ); + } + + gboolean toolbar; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_TOOLBAR, &toolbar ) ) + if ( ! toolbar ) { + gtk_widget_hide ( GTK_WIDGET(vw->toolbar) ); + GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewToolBar" ); + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE ); + } + + gboolean menubar; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_MENUBAR, &menubar ) ) + if ( ! menubar ) { + gtk_widget_hide ( gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu" ) ); + GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/SetShow/ViewMainMenu" ); + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), FALSE ); + } + } window_count++; return vw; @@ -311,6 +359,100 @@ VikWindow *vik_window_new_window () return NULL; } +/** + * determine_location_thread: + * @vw: The window that will get updated + * @threaddata: Data used by our background thread mechanism + * + * Use the features in vikgoto to determine where we are + * Then set up the viewport: + * 1. To goto the location + * 2. Set an appropriate level zoom for the location type + * 3. Some statusbar message feedback + */ +static int determine_location_thread ( VikWindow *vw, gpointer threaddata ) +{ + struct LatLon ll; + gchar *name = NULL; + gint ans = a_vik_goto_where_am_i ( vw->viking_vvp, &ll, &name ); + + int result = a_background_thread_progress ( threaddata, 1.0 ); + if ( result != 0 ) { + vik_window_statusbar_update ( vw, _("Location lookup aborted"), VIK_STATUSBAR_INFO ); + return -1; /* Abort thread */ + } + + if ( ans ) { + // Zoom out a little + gdouble zoom = 16.0; + + if ( ans == 2 ) { + // Position found with city precision - so zoom out more + zoom = 128.0; + } + else if ( ans == 3 ) { + // Position found via country name search - so zoom wayyyy out + zoom = 2048.0; + } + + vik_viewport_set_zoom ( vw->viking_vvp, zoom ); + vik_viewport_set_center_latlon ( vw->viking_vvp, &ll ); + + gchar *message = g_strdup_printf ( _("Location found: %s"), name ); + vik_window_statusbar_update ( vw, message, VIK_STATUSBAR_INFO ); + g_free ( name ); + g_free ( message ); + + // Signal to redraw from the background + vik_layers_panel_emit_update ( vw->viking_vlp ); + } + else + vik_window_statusbar_update ( vw, _("Unable to determine location"), VIK_STATUSBAR_INFO ); + + return 0; +} + +/** + * Steps to be taken once initial loading has completed + */ +void vik_window_new_window_finish ( VikWindow *vw ) +{ + // Don't add a map if we've loaded a Viking file already + if ( vw->filename ) + return; + + if ( a_vik_get_startup_method ( ) == VIK_STARTUP_METHOD_SPECIFIED_FILE ) { + vik_window_open_file ( vw, a_vik_get_startup_file(), TRUE ); + if ( vw->filename ) + return; + } + + // Maybe add a default map layer + if ( a_vik_get_add_default_map_layer () ) { + VikMapsLayer *vml = VIK_MAPS_LAYER ( vik_layer_create(VIK_LAYER_MAPS, vw->viking_vvp, NULL, FALSE) ); + vik_layer_rename ( VIK_LAYER(vml), _("Default Map") ); + vik_aggregate_layer_add_layer ( vik_layers_panel_get_top_layer(vw->viking_vlp), VIK_LAYER(vml), TRUE ); + + draw_update ( vw ); + } + + // If not loaded any file, maybe try the location lookup + if ( vw->loaded_type == LOAD_TYPE_READ_FAILURE ) { + if ( a_vik_get_startup_method ( ) == VIK_STARTUP_METHOD_AUTO_LOCATION ) { + + vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, _("Trying to determine location...") ); + + a_background_thread ( GTK_WINDOW(vw), + _("Determining location"), + (vik_thr_func) determine_location_thread, + vw, + NULL, + NULL, + 1 ); + } + } +} + static void open_window ( VikWindow *vw, GSList *files ) { gboolean change_fn = (g_slist_length(files) == 1); /* only change fn if one file */ @@ -318,7 +460,7 @@ static void open_window ( VikWindow *vw, GSList *files ) while ( cur_file ) { // Only open a new window if a viking file gchar *file_name = cur_file->data; - if (vw != NULL && check_file_magic_vik ( file_name ) ) { + if (vw != NULL && vw->filename && check_file_magic_vik ( file_name ) ) { VikWindow *newvw = vik_window_new_window (); if (newvw) vik_window_open_file ( newvw, file_name, TRUE ); @@ -363,6 +505,12 @@ static void window_finalize ( GObject *gob ) window_list = g_slist_remove ( window_list, vw ); gdk_cursor_unref ( vw->busy_cursor ); + int tt; + for (tt = 0; tt < vw->vt->n_tools; tt++ ) + if ( vw->vt->tools[tt].ti.destroy ) + vw->vt->tools[tt].ti.destroy ( vw->vt->tools[tt].state ); + g_free ( vw->vt->tools ); + g_free ( vw->vt ); G_OBJECT_CLASS(parent_class)->finalize(gob); } @@ -375,7 +523,6 @@ static void vik_window_class_init ( VikWindowClass *klass ) window_signals[VW_NEWWINDOW_SIGNAL] = g_signal_new ( "newwindow", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, newwindow), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); window_signals[VW_OPENWINDOW_SIGNAL] = g_signal_new ( "openwindow", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, openwindow), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); - window_signals[VW_STATUSBAR_UPDATE_SIGNAL] = g_signal_new ( "statusbarupdate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (VikWindowClass, statusbarupdate), NULL, NULL, g_cclosure_marshal_VOID__UINT_POINTER, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER); object_class = G_OBJECT_CLASS (klass); @@ -404,13 +551,16 @@ static void zoom_changed (GtkMenuShell *menushell, } } -static GtkWidget * create_zoom_menu_all_levels () +/** + * @mpp: The initial zoom level + */ +static GtkWidget *create_zoom_menu_all_levels ( gdouble mpp ) { GtkWidget *menu = gtk_menu_new (); - char *itemLabels[] = { "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", NULL }; + char *itemLabels[] = { "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768" }; int i; - for (i = 0 ; itemLabels[i] != NULL ; i++) + for (i = 0 ; i < G_N_ELEMENTS(itemLabels) ; i++) { GtkWidget *item = gtk_menu_item_new_with_label (itemLabels[i]); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); @@ -418,6 +568,14 @@ static GtkWidget * create_zoom_menu_all_levels () g_object_set_data (G_OBJECT (item), "position", GINT_TO_POINTER(i)); } + gint active = 2 + round ( log (mpp) / log (2) ); + // Ensure value derived from mpp is in bounds of the menu + if ( active >= G_N_ELEMENTS(itemLabels) ) + active = G_N_ELEMENTS(itemLabels) - 1; + if ( active < 0 ) + active = 0; + gtk_menu_set_active ( GTK_MENU(menu), active ); + return menu; } @@ -464,6 +622,66 @@ static gint zoom_popup_handler (GtkWidget *widget) return TRUE; } +enum { + TARGET_URIS, +}; + +static void drag_data_received_cb ( GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint target_type, + guint time, + gpointer data ) +{ + gboolean success = FALSE; + + if ( (selection_data != NULL) && (gtk_selection_data_get_length(selection_data) > 0) ) { + switch (target_type) { + case TARGET_URIS: { + gchar *str = (gchar*)gtk_selection_data_get_data(selection_data); + g_debug ("drag received string:%s \n", str); + + // Convert string into GSList of individual entries for use with our open signal + gchar **entries = g_strsplit(str, "\r\n", 0); + GSList *filenames = NULL; + gint entry_runner = 0; + gchar *entry = entries[entry_runner]; + while (entry) { + if ( g_strcmp0 ( entry, "" ) ) { + // Drag+Drop gives URIs. And so in particular, %20 in place of spaces in filenames + // thus need to convert the text into a plain string + gchar *filename = g_filename_from_uri ( entry, NULL, NULL ); + if ( filename ) + filenames = g_slist_append ( filenames, filename ); + } + entry_runner++; + entry = entries[entry_runner]; + } + + if ( filenames ) + g_signal_emit ( G_OBJECT(VIK_WINDOW_FROM_WIDGET(widget)), window_signals[VW_OPENWINDOW_SIGNAL], 0, filenames ); + // NB: GSList & contents are freed by main.open_window + + success = TRUE; + break; + } + default: break; + } + } + + gtk_drag_finish ( context, success, FALSE, time ); +} + +#define VIK_SETTINGS_WIN_MAX "window_maximized" +#define VIK_SETTINGS_WIN_FULLSCREEN "window_fullscreen" +#define VIK_SETTINGS_WIN_WIDTH "window_width" +#define VIK_SETTINGS_WIN_HEIGHT "window_height" +#define VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH "window_save_image_width" +#define VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT "window_save_image_height" +#define VIK_SETTINGS_WIN_SAVE_IMAGE_PNG "window_save_image_as_png" + static void vik_window_init ( VikWindow *vw ) { GtkWidget *main_vbox; @@ -487,15 +705,28 @@ static void vik_window_init ( VikWindow *vw ) gtk_action_activate ( gtk_action_group_get_action ( vw->action_group, "Pan" ) ); vw->filename = NULL; - + vw->loaded_type = LOAD_TYPE_READ_FAILURE; //AKA none vw->modified = FALSE; vw->only_updating_coord_mode_ui = FALSE; vw->pan_move = FALSE; vw->pan_x = vw->pan_y = -1; - vw->draw_image_width = DRAW_IMAGE_DEFAULT_WIDTH; - vw->draw_image_height = DRAW_IMAGE_DEFAULT_HEIGHT; - vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG; + + gint draw_image_width; + if ( a_settings_get_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH, &draw_image_width ) ) + vw->draw_image_width = draw_image_width; + else + vw->draw_image_width = DRAW_IMAGE_DEFAULT_WIDTH; + gint draw_image_height; + if ( a_settings_get_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT, &draw_image_height ) ) + vw->draw_image_height = draw_image_height; + else + vw->draw_image_height = DRAW_IMAGE_DEFAULT_HEIGHT; + gboolean draw_image_save_as_png; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_SAVE_IMAGE_PNG, &draw_image_save_as_png ) ) + vw->draw_image_save_as_png = draw_image_save_as_png; + else + vw->draw_image_save_as_png = DRAW_IMAGE_DEFAULT_SAVE_AS_PNG; main_vbox = gtk_vbox_new(FALSE, 1); gtk_container_add (GTK_CONTAINER (vw), main_vbox); @@ -505,8 +736,10 @@ static void vik_window_init ( VikWindow *vw ) gtk_toolbar_set_icon_size (vw->toolbar, GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_toolbar_set_style (vw->toolbar, GTK_TOOLBAR_ICONS); + vik_ext_tool_datasources_add_menu_items ( vw, vw->uim ); + GtkWidget * zoom_levels = gtk_ui_manager_get_widget (vw->uim, "/MainMenu/View/SetZoom"); - GtkWidget * zoom_levels_menu = create_zoom_menu_all_levels (); + GtkWidget * zoom_levels_menu = create_zoom_menu_all_levels ( vik_viewport_get_zoom(vw->viking_vvp) ); gtk_menu_item_set_submenu (GTK_MENU_ITEM (zoom_levels), zoom_levels_menu); g_signal_connect ( G_OBJECT(zoom_levels_menu), "selection-done", G_CALLBACK(zoom_changed), vw); g_signal_connect_swapped ( G_OBJECT(vw->viking_vs), "clicked", G_CALLBACK(zoom_popup_handler), zoom_levels_menu ); @@ -525,8 +758,6 @@ static void vik_window_init ( VikWindow *vw ) // Allow key presses to be processed anywhere g_signal_connect_swapped (G_OBJECT (vw), "key_press_event", G_CALLBACK (key_press_event), vw); - gtk_window_set_default_size ( GTK_WINDOW(vw), VIKING_WINDOW_WIDTH, VIKING_WINDOW_HEIGHT); - hpaned = gtk_hpaned_new (); gtk_paned_pack1 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vlp), FALSE, FALSE ); gtk_paned_pack2 ( GTK_PANED(hpaned), GTK_WIDGET (vw->viking_vvp), TRUE, TRUE ); @@ -540,11 +771,55 @@ static void vik_window_init ( VikWindow *vw ) window_list = g_slist_prepend ( window_list, vw); + gint height = VIKING_WINDOW_HEIGHT; + gint width = VIKING_WINDOW_WIDTH; + + if ( a_vik_get_restore_window_state() ) { + if ( a_settings_get_integer ( VIK_SETTINGS_WIN_HEIGHT, &height ) ) { + // Enforce a basic minimum size + if ( height < 160 ) + height = 160; + } + else + // No setting - so use default + height = VIKING_WINDOW_HEIGHT; + + if ( a_settings_get_integer ( VIK_SETTINGS_WIN_WIDTH, &width ) ) { + // Enforce a basic minimum size + if ( width < 320 ) + width = 320; + } + else + // No setting - so use default + width = VIKING_WINDOW_WIDTH; + + gboolean maxed; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_MAX, &maxed ) ) + if ( maxed ) + gtk_window_maximize ( GTK_WINDOW(vw) ); + + gboolean full; + if ( a_settings_get_boolean ( VIK_SETTINGS_WIN_FULLSCREEN, &full ) ) { + if ( full ) { + gtk_window_fullscreen ( GTK_WINDOW(vw) ); + GtkWidget *check_box = gtk_ui_manager_get_widget ( vw->uim, "/ui/MainMenu/View/FullScreen" ); + gtk_check_menu_item_set_active ( GTK_CHECK_MENU_ITEM(check_box), TRUE ); + } + } + } + + gtk_window_set_default_size ( GTK_WINDOW(vw), width, height ); + vw->open_dia = NULL; vw->save_dia = NULL; vw->save_img_dia = NULL; vw->save_img_dir_dia = NULL; + // Only accept Drag and Drop of files onto the viewport + gtk_drag_dest_set ( GTK_WIDGET(vw->viking_vvp), GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY ); + gtk_drag_dest_add_uri_targets ( GTK_WIDGET(vw->viking_vvp) ); + g_signal_connect ( GTK_WIDGET(vw->viking_vvp), "drag-data-received", G_CALLBACK(drag_data_received_cb), NULL ); + // Store the thread value so comparisons can be made to determine the gdk update method // Hopefully we are storing the main thread value here :) // [ATM any window initialization is always be performed by the main thread] @@ -661,6 +936,37 @@ static gboolean delete_event( VikWindow *vw ) default: gtk_widget_destroy ( GTK_WIDGET(dia) ); return ! save_file(NULL, vw); } } + + if ( window_count == 1 ) { + // On the final window close - save latest state - if it's wanted... + if ( a_vik_get_restore_window_state() ) { + gint state = gdk_window_get_state ( GTK_WIDGET(vw)->window ); + gboolean state_max = state & GDK_WINDOW_STATE_MAXIMIZED; + a_settings_set_boolean ( VIK_SETTINGS_WIN_MAX, state_max ); + + gboolean state_fullscreen = state & GDK_WINDOW_STATE_FULLSCREEN; + a_settings_set_boolean ( VIK_SETTINGS_WIN_FULLSCREEN, state_fullscreen ); + + a_settings_set_boolean ( VIK_SETTINGS_WIN_SIDEPANEL, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->viking_vlp)) ); + + a_settings_set_boolean ( VIK_SETTINGS_WIN_STATUSBAR, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->viking_vs)) ); + + a_settings_set_boolean ( VIK_SETTINGS_WIN_TOOLBAR, GTK_WIDGET_VISIBLE (GTK_WIDGET(vw->toolbar)) ); + + // If supersized - no need to save the enlarged width+height values + if ( ! (state_fullscreen || state_max) ) { + gint width, height; + gtk_window_get_size ( GTK_WINDOW (vw), &width, &height ); + a_settings_set_integer ( VIK_SETTINGS_WIN_WIDTH, width ); + a_settings_set_integer ( VIK_SETTINGS_WIN_HEIGHT, height ); + } + } + + a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_WIDTH, vw->draw_image_width ); + a_settings_set_integer ( VIK_SETTINGS_WIN_SAVE_IMAGE_HEIGHT, vw->draw_image_height ); + a_settings_set_boolean ( VIK_SETTINGS_WIN_SAVE_IMAGE_PNG, vw->draw_image_save_as_png ); + } + return FALSE; } @@ -1684,6 +1990,12 @@ static VikToolInterface select_tool = static void draw_pan_cb ( GtkAction *a, VikWindow *vw ) { + // Since the treeview cell editting intercepts standard keyboard handlers, it means we can receive events here + // Thus if currently editting, ensure we don't move the viewport when Ctrl+ is received + VikLayer *sel = vik_layers_panel_get_selected ( vw->viking_vlp ); + if ( sel && vik_treeview_get_editing ( sel->vt ) ) + return; + if (!strcmp(gtk_action_get_name(a), "PanNorth")) { vik_viewport_set_center_screen ( vw->viking_vvp, vik_viewport_get_width(vw->viking_vvp)/2, 0 ); } else if (!strcmp(gtk_action_get_name(a), "PanEast")) { @@ -1803,7 +2115,7 @@ static void menu_cut_layer_cb ( GtkAction *a, VikWindow *vw ) static void menu_paste_layer_cb ( GtkAction *a, VikWindow *vw ) { - if ( a_clipboard_paste ( vw->viking_vlp ) ) + if ( vik_layers_panel_paste_selected ( vw->viking_vlp ) ) { vw->modified = TRUE; } @@ -2209,7 +2521,7 @@ void vik_window_set_busy_cursor ( VikWindow *vw ) { gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw)), vw->busy_cursor ); // Viewport has a separate cursor - gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, vw->busy_cursor ); + gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->busy_cursor ); // Ensure cursor updated before doing stuff while( gtk_events_pending() ) gtk_main_iteration(); @@ -2219,14 +2531,14 @@ void vik_window_clear_busy_cursor ( VikWindow *vw ) { gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw)), NULL ); // Restore viewport cursor - gdk_window_set_cursor ( GTK_WIDGET(vw->viking_vvp)->window, vw->viewport_cursor ); + gdk_window_set_cursor ( gtk_widget_get_window(GTK_WIDGET(vw->viking_vvp)), vw->viewport_cursor ); } void vik_window_open_file ( VikWindow *vw, const gchar *filename, gboolean change_filename ) { vik_window_set_busy_cursor ( vw ); - - switch ( a_file_load ( vik_layers_panel_get_top_layer(vw->viking_vlp), vw->viking_vvp, filename ) ) + vw->loaded_type = a_file_load ( vik_layers_panel_get_top_layer(vw->viking_vlp), vw->viking_vvp, filename ); + switch ( vw->loaded_type ) { case LOAD_TYPE_READ_FAILURE: a_dialog_error_msg ( GTK_WINDOW(vw), _("The file you requested could not be opened.") ); @@ -2303,11 +2615,17 @@ static void load_file ( GtkAction *a, VikWindow *vw ) if ( ! vw->open_dia ) { vw->open_dia = gtk_file_chooser_dialog_new (_("Please select a GPS data file to open. "), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + gchar *cwd = g_get_current_dir(); + if ( cwd ) { + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->open_dia), cwd ); + g_free ( cwd ); + } + GtkFileFilter *filter; // NB file filters are listed this way for alphabetical ordering #ifdef VIK_CONFIG_GEOCACHES @@ -2399,11 +2717,17 @@ static gboolean save_file_as ( GtkAction *a, VikWindow *vw ) if ( ! vw->save_dia ) { vw->save_dia = gtk_file_chooser_dialog_new (_("Save as Viking File."), - GTK_WINDOW(vw), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); + GTK_WINDOW(vw), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gchar *cwd = g_get_current_dir(); + if ( cwd ) { + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_dia), cwd ); + g_free ( cwd ); + } + GtkFileFilter *filter; filter = gtk_file_filter_new (); gtk_file_filter_set_name( filter, _("All") ); @@ -2561,7 +2885,7 @@ static void export_to_common ( VikWindow *vw, VikFileType_t vft, const gchar *ex NULL ); GtkWidget *gw = gtk_file_chooser_widget_new ( GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER ); - gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), gw, TRUE, TRUE, 0 ); + gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), gw, TRUE, TRUE, 0 ); // try to make it a nice size - otherwise seems to default to something impractically small gtk_window_set_default_size ( GTK_WINDOW(dialog), 600, 300 ); @@ -2593,6 +2917,42 @@ static void export_to_kml ( GtkAction *a, VikWindow *vw ) export_to_common ( vw, FILE_TYPE_KML, ".kml" ); } +static void file_properties_cb ( GtkAction *a, VikWindow *vw ) +{ + gchar *message = NULL; + if ( vw->filename ) { + if ( g_file_test ( vw->filename, G_FILE_TEST_EXISTS ) ) { + // Get some timestamp information of the file + GStatBuf stat_buf; + if ( g_stat ( vw->filename, &stat_buf ) == 0 ) { + gchar time_buf[64]; + strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) ); + gchar *size = NULL; + gint byte_size = stat_buf.st_size; + // See http://en.wikipedia.org/wiki/Megabyte (and Kilobyte) + // hence using 1000 rather than 1024 + // so get output as per 'ls' or the Gtk file open dialog + if ( byte_size < 1000 ) + size = g_strdup_printf ( _("%d bytes"), byte_size ); + else if ( byte_size < 1000*1000 ) + size = g_strdup_printf ( _("%3.1f kB"), (gdouble)byte_size / 1000 ); + else + size = g_strdup_printf ( _("%3.1f MB"), (gdouble)byte_size / (1000*1000) ); + message = g_strdup_printf ( _("%s\n\n%s\n\n%s"), vw->filename, time_buf, size ); + g_free (size); + } + } + else + message = g_strdup ( _("File not accessible") ); + } + else + message = g_strdup ( _("No Viking File") ); + + // Show the info + a_dialog_info_msg ( GTK_WINDOW(vw), message ); + g_free ( message ); +} + static void acquire_from_gps ( GtkAction *a, VikWindow *vw ) { // Via the file menu, acquiring from a GPS makes a new layer @@ -2600,37 +2960,35 @@ static void acquire_from_gps ( GtkAction *a, VikWindow *vw ) // thus maintain the behaviour ATM. // Hence explicit setting here (as the value may be changed elsewhere) vik_datasource_gps_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gps_interface, NULL, NULL ); } static void acquire_from_file ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_file_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_file_interface, NULL, NULL ); } -#ifdef VIK_CONFIG_GOOGLE -static void acquire_from_google ( GtkAction *a, VikWindow *vw ) +static void acquire_from_routing ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_google_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_routing_interface, NULL, NULL ); } -#endif #ifdef VIK_CONFIG_OPENSTREETMAP static void acquire_from_osm ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_interface, NULL, NULL ); } static void acquire_from_my_osm ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_my_traces_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_osm_my_traces_interface, NULL, NULL ); } #endif #ifdef VIK_CONFIG_GEOCACHES static void acquire_from_gc ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_gc_interface, NULL, NULL ); } #endif @@ -2638,17 +2996,23 @@ static void acquire_from_gc ( GtkAction *a, VikWindow *vw ) static void acquire_from_geotag ( GtkAction *a, VikWindow *vw ) { vik_datasource_geotag_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_geotag_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_geotag_interface, NULL, NULL ); } #endif #ifdef VIK_CONFIG_GEONAMES static void acquire_from_wikipedia ( GtkAction *a, VikWindow *vw ) { - a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_wikipedia_interface ); + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_wikipedia_interface, NULL, NULL ); } #endif +static void acquire_from_url ( GtkAction *a, VikWindow *vw ) +{ + vik_datasource_url_interface.mode = VIK_DATASOURCE_CREATENEWLAYER; + a_acquire(vw, vw->viking_vlp, vw->viking_vvp, &vik_datasource_url_interface, NULL, NULL ); +} + static void goto_default_location( GtkAction *a, VikWindow *vw) { struct LatLon ll; @@ -2689,12 +3053,14 @@ static void preferences_change_update ( VikWindow *vw, gpointer data ) // Want to update all TrackWaypoint layers GList *layers = vik_layers_panel_get_all_layers_of_type ( vw->viking_vlp, VIK_LAYER_TRW, TRUE ); - GList *iter = g_list_first ( layers ); - while ( iter ) { + if ( !layers ) + return; + + while ( layers ) { // Reset the individual waypoints themselves due to the preferences change - VikTrwLayer *vtl = VIK_TRW_LAYER(VIK_LAYER(layers->data)); + VikTrwLayer *vtl = VIK_TRW_LAYER(layers->data); vik_trw_layer_reset_waypoints ( vtl ); - iter = g_list_next ( iter ); + layers = g_list_next ( layers ); } g_list_free ( layers ); @@ -2731,7 +3097,10 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw ) VIK_LAYER_WIDGET_SPINBUTTON, NULL, NULL, - NULL }, + NULL, + NULL, + NULL, + }, }; VikLayerParam pref_lon[] = { { VIK_LAYER_NUM_TYPES, @@ -2742,7 +3111,10 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw ) VIK_LAYER_WIDGET_SPINBUTTON, NULL, NULL, - NULL }, + NULL, + NULL, + NULL, + }, }; /* Get current center */ @@ -3005,6 +3377,12 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only ) GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); + gchar *cwd = g_get_current_dir(); + if ( cwd ) { + gtk_file_chooser_set_current_folder ( GTK_FILE_CHOOSER(vw->save_img_dia), cwd ); + g_free ( cwd ); + } + GtkFileChooser *chooser = GTK_FILE_CHOOSER ( vw->save_img_dia ); /* Add filters */ GtkFileFilter *filter; @@ -3018,13 +3396,16 @@ static gchar* draw_image_filename ( VikWindow *vw, gboolean one_image_only ) gtk_file_filter_add_mime_type ( filter, "image/jpeg"); gtk_file_chooser_add_filter ( chooser, filter ); + if ( !vw->draw_image_save_as_png ) + gtk_file_chooser_set_filter ( chooser, filter ); + filter = gtk_file_filter_new (); gtk_file_filter_set_name ( filter, _("PNG") ); gtk_file_filter_add_mime_type ( filter, "image/png"); gtk_file_chooser_add_filter ( chooser, filter ); - // Default to pngs - gtk_file_chooser_set_filter ( chooser, filter ); + if ( vw->draw_image_save_as_png ) + gtk_file_chooser_set_filter ( chooser, filter ); gtk_window_set_transient_for ( GTK_WINDOW(vw->save_img_dia), GTK_WINDOW(vw) ); gtk_window_set_destroy_with_parent ( GTK_WINDOW(vw->save_img_dia), TRUE ); @@ -3102,6 +3483,8 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) // Can we not hard code size here? if ( active > 17 ) active = 17; + if ( active < 0 ) + active = 0; gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo), active ); total_size_label = gtk_label_new ( NULL ); @@ -3119,6 +3502,9 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) png_radio = gtk_radio_button_new_with_label ( NULL, _("Save as PNG") ); jpeg_radio = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(png_radio), _("Save as JPEG") ); + gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), png_radio, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), jpeg_radio, FALSE, FALSE, 0); + if ( ! vw->draw_image_save_as_png ) gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(jpeg_radio), TRUE ); @@ -3130,8 +3516,6 @@ static void draw_to_image_file ( VikWindow *vw, gboolean one_image_only ) gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), win_warning_label, FALSE, FALSE, 0); #endif gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), current_window_button, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), png_radio, FALSE, FALSE, 0); - gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), jpeg_radio, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zoom_combo, FALSE, FALSE, 0); @@ -3208,12 +3592,10 @@ static void draw_to_image_dir_cb ( GtkAction *a, VikWindow *vw ) draw_to_image_file ( vw, FALSE ); } -#if GTK_CHECK_VERSION(2,10,0) static void print_cb ( GtkAction *a, VikWindow *vw ) { a_print(vw, vw->viking_vvp); } -#endif /* really a misnomer: changes coord mode (actual coordinates) AND/OR draw mode (viewport only) */ static void window_change_coord_mode_cb ( GtkAction *old_a, GtkAction *a, VikWindow *vw ) @@ -3339,9 +3721,7 @@ static GtkActionEntry entries[] = { { "Acquire", GTK_STOCK_GO_DOWN, N_("A_cquire"), NULL, NULL, (GCallback)NULL }, { "AcquireGPS", NULL, N_("From _GPS..."), NULL, N_("Transfer data from a GPS device"), (GCallback)acquire_from_gps }, { "AcquireGPSBabel", NULL, N_("Import File With GPS_Babel..."), NULL, N_("Import file via GPSBabel converter"), (GCallback)acquire_from_file }, -#ifdef VIK_CONFIG_GOOGLE - { "AcquireGoogle", NULL, N_("Google _Directions..."), NULL, N_("Get driving directions from Google"), (GCallback)acquire_from_google }, -#endif + { "AcquireRouting", NULL, N_("_Directions..."), NULL, N_("Get driving directions"), (GCallback)acquire_from_routing }, #ifdef VIK_CONFIG_OPENSTREETMAP { "AcquireOSM", NULL, N_("_OSM Traces..."), NULL, N_("Get traces from OpenStreetMap"), (GCallback)acquire_from_osm }, { "AcquireMyOSM", NULL, N_("_My OSM Traces..."), NULL, N_("Get Your Own Traces from OpenStreetMap"), (GCallback)acquire_from_my_osm }, @@ -3352,18 +3732,16 @@ static GtkActionEntry entries[] = { #ifdef VIK_CONFIG_GEOTAG { "AcquireGeotag", NULL, N_("From Geotagged _Images..."), NULL, N_("Create waypoints from geotagged images"), (GCallback)acquire_from_geotag }, #endif + { "AcquireURL", NULL, N_("From _URL..."), NULL, N_("Get a file from a URL"), (GCallback)acquire_from_url }, #ifdef VIK_CONFIG_GEONAMES { "AcquireWikipedia", NULL, N_("From _Wikipedia Waypoints"), NULL, N_("Create waypoints from Wikipedia items in the current view"), (GCallback)acquire_from_wikipedia }, #endif { "Save", GTK_STOCK_SAVE, N_("_Save"), "S", N_("Save the file"), (GCallback)save_file }, { "SaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), NULL, N_("Save the file under different name"), (GCallback)save_file_as }, + { "FileProperties", NULL, N_("Properties..."), NULL, N_("File Properties"), (GCallback)file_properties_cb }, { "GenImg", GTK_STOCK_CLEAR, N_("_Generate Image File..."), NULL, N_("Save a snapshot of the workspace into a file"), (GCallback)draw_to_image_file_cb }, { "GenImgDir", GTK_STOCK_DND_MULTIPLE, N_("Generate _Directory of Images..."), NULL, N_("FIXME:IMGDIR"), (GCallback)draw_to_image_dir_cb }, - -#if GTK_CHECK_VERSION(2,10,0) { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb }, -#endif - { "Exit", GTK_STOCK_QUIT, N_("E_xit"), "W", N_("Exit the program"), (GCallback)window_close }, { "SaveExit", GTK_STOCK_QUIT, N_("Save and Exit"), NULL, N_("Save and Exit the program"), (GCallback)save_file_and_exit }, @@ -3499,6 +3877,8 @@ static void window_create_ui( VikWindow *window ) action.callback = (GCallback)menu_addlayer_cb; gtk_action_group_add_actions(action_group, &action, 1, window); + g_free ( (gchar*)action.label ); + if ( vik_layer_get_interface(i)->tools_count ) { gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Tools/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE); gtk_ui_manager_add_ui(uim, mid, "/ui/MainToolbar/ToolItems/", vik_layer_get_interface(i)->name, NULL, GTK_UI_MANAGER_SEPARATOR, FALSE); @@ -3527,10 +3907,12 @@ static void window_create_ui( VikWindow *window ) } GtkActionEntry action_dl; + gchar *layername = g_strdup_printf ( "Layer%s", vik_layer_get_interface(i)->fixed_layer_name ); gtk_ui_manager_add_ui(uim, mid, "/ui/MainMenu/Edit/LayerDefaults", vik_layer_get_interface(i)->name, - g_strdup_printf("Layer%s", vik_layer_get_interface(i)->fixed_layer_name), + layername, GTK_UI_MANAGER_MENUITEM, FALSE); + g_free (layername); // For default layers use action names of the form 'Layer' // This is to avoid clashing with just the layer name used above for the tool actions @@ -3541,6 +3923,8 @@ static void window_create_ui( VikWindow *window ) action_dl.tooltip = NULL; action_dl.callback = (GCallback)layer_defaults_cb; gtk_action_group_add_actions(action_group, &action_dl, 1, window); + g_free ( (gchar*)action_dl.name ); + g_free ( (gchar*)action_dl.label ); } g_object_unref (icon_factory);