X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/82993cc7d379563c9a95e33c5e5369a957b0c121..d6c110f19fddb9e2ba1cab304a0fafd4a7c3fe46:/src/vikwindow.c diff --git a/src/vikwindow.c b/src/vikwindow.c index 51772ad1..324d0bbd 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 @@ -86,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 ); @@ -179,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; @@ -215,7 +215,6 @@ enum { enum { VW_NEWWINDOW_SIGNAL, VW_OPENWINDOW_SIGNAL, - VW_STATUSBAR_UPDATE_SIGNAL, VW_LAST_SIGNAL }; @@ -244,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 @@ -283,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 () { @@ -300,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; @@ -312,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 */ @@ -319,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 ); @@ -364,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); } @@ -376,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); @@ -476,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; @@ -499,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); @@ -539,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 ); @@ -554,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] @@ -675,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; } @@ -2229,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(); @@ -2239,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.") ); @@ -2550,7 +2842,7 @@ static gboolean export_to ( VikWindow *vw, GList *gl, VikFileType_t vft, const g // Show some progress if ( this_success ) { export_count++; - gchar *message = g_strconcat ( _("Exporting to file: "), fn, NULL ); + gchar *message = g_strdup_printf ( _("Exporting to file: %s"), fn ); vik_statusbar_set_message ( vw->viking_vs, VIK_STATUSBAR_INFO, message ); while ( gtk_events_pending() ) gtk_main_iteration (); @@ -2583,25 +2875,22 @@ static void export_to_common ( VikWindow *vw, VikFileType_t vft, const gchar *ex return; } - GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Export to directory"), + GtkWidget *dialog = gtk_file_chooser_dialog_new ( _("Export to directory"), GTK_WINDOW(vw), - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, 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 ); - - // 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 ); + gtk_window_set_transient_for ( GTK_WINDOW(dialog), GTK_WINDOW(vw) ); + gtk_window_set_destroy_with_parent ( GTK_WINDOW(dialog), TRUE ); + gtk_window_set_modal ( GTK_WINDOW(dialog), TRUE ); gtk_widget_show_all ( dialog ); if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { - gchar *dir = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(gw) ); + gchar *dir = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER(dialog) ); gtk_widget_destroy ( dialog ); if ( dir ) { if ( !export_to ( vw, gl, vft, dir, extension ) ) @@ -2625,6 +2914,46 @@ static void export_to_kml ( GtkAction *a, VikWindow *vw ) export_to_common ( vw, FILE_TYPE_KML, ".kml" ); } +#if !GLIB_CHECK_VERSION(2,26,0) +typedef struct stat GStatBuf; +#endif + +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 @@ -2640,12 +2969,10 @@ static void acquire_from_file ( GtkAction *a, VikWindow *vw ) 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, NULL, NULL ); + 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 ) @@ -2681,6 +3008,12 @@ static void acquire_from_wikipedia ( GtkAction *a, VikWindow *vw ) } #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; @@ -2721,12 +3054,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 ); @@ -2763,7 +3098,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, @@ -2774,7 +3112,10 @@ static void default_location_cb ( GtkAction *a, VikWindow *vw ) VIK_LAYER_WIDGET_SPINBUTTON, NULL, NULL, - NULL }, + NULL, + NULL, + NULL, + }, }; /* Get current center */ @@ -3162,6 +3503,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 ); @@ -3173,8 +3517,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); @@ -3380,9 +3722,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 }, @@ -3393,11 +3733,13 @@ 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 }, { "Print", GTK_STOCK_PRINT, N_("_Print..."), NULL, N_("Print maps"), (GCallback)print_cb }, @@ -3536,6 +3878,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); @@ -3564,10 +3908,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 @@ -3578,6 +3924,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);