diff --git a/src/vnr-window.c b/src/vnr-window.c index 34c47c0..cab72ae 100755 --- a/src/vnr-window.c +++ b/src/vnr-window.c @@ -20,7 +20,7 @@ #include #include #define _(String) gettext (String) - +#include #include "config.h" #include #include @@ -36,6 +36,9 @@ #include "vnr-properties-dialog.h" #include "vnr-crop.h" #include "uni-exiv2.hpp" +#include +#include +// TODO: try not to use sys includes only for file exists stat() call. Maybe gtk method /* Timeout to hide the toolbar in fullscreen mode */ #define FULLSCREEN_TIMEOUT 1000 @@ -51,12 +54,19 @@ static void allow_slideshow(VnrWindow *window); static void leave_fs_cb (GtkButton *button, VnrWindow *window); static void toggle_show_next_cb (GtkToggleButton *togglebutton, VnrWindow *window); static void spin_value_change_cb (GtkSpinButton *spinbutton, VnrWindow *window); -static void save_image_cb (GtkWidget *widget, VnrWindow *window); +static gboolean save_image_cb (GtkWidget *widget, VnrWindow *window, gchar *type_override); +static void copyto_image_cb (GtkWidget *widget, VnrWindow *window); +static void rename_image_cb (GtkWidget *widget, VnrWindow *window); static void zoom_changed_cb (UniImageView *view, VnrWindow *window); static gboolean fullscreen_timeout_cb (VnrWindow *window); static gboolean leave_image_area_cb(GtkWidget * widget, GdkEventCrossing * ev, VnrWindow *window); static gboolean fullscreen_motion_cb(GtkWidget * widget, GdkEventMotion * ev, VnrWindow *window); static void open_with_launch_application_cb (GtkAction *action, VnrWindow *window); +static gboolean file_exists_warning(VnrWindow *window); +void file_extension_to_type(char* filetype_override, const gchar *filepath); +static gboolean file_move_copy (GtkWidget *dialog, VnrWindow *window); +static void refresh_list_and_display(VnrWindow *window, gboolean restart_slideshow, GtkWidget *dialog); +void setup_file_save_formats(); const gchar *ui_definition = "" "" @@ -68,7 +78,9 @@ const gchar *ui_definition = "" "" "" "" + "" "" + "" "" "" "" @@ -122,7 +134,9 @@ const gchar *ui_definition = "" "" "" "" + "" "" + "" "" "" "" @@ -761,7 +775,7 @@ rotate_pixbuf(VnrWindow *window, GdkPixbufRotation angle) _("Image modifications cannot be saved.\nWriting in this format is not supported."), FALSE); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE) - save_image_cb(NULL, window); + save_image_cb(NULL, window, NULL); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK) vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area), FALSE, @@ -819,7 +833,7 @@ flip_pixbuf(VnrWindow *window, gboolean horizontal) _("Image modifications cannot be saved.\nWriting in this format is not supported."), FALSE); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE) - save_image_cb(NULL, window); + save_image_cb(NULL, window, NULL); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK) vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area), FALSE, @@ -916,22 +930,31 @@ toggle_show_next_cb (GtkToggleButton *togglebutton, VnrWindow *window) stop_slideshow(window); } -static void -save_image_cb (GtkWidget *widget, VnrWindow *window) +static gboolean +save_image_cb (GtkWidget *widget, VnrWindow *window, gchar *type_override) { GError *error = NULL; if(!window->cursor_is_hidden) gdk_window_set_cursor(GTK_WIDGET(window)->window, gdk_cursor_new(GDK_WATCH)); /* This makes the cursor show NOW */ gdk_flush(); - + if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK) - vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area)); - + { + if(vnr_message_area_is_visible(VNR_MESSAGE_AREA(window->msg_area))) + { + vnr_message_area_hide(VNR_MESSAGE_AREA(window->msg_area)); + } + } /* Store exiv2 metadata to cache, so we can restore it afterwards */ - uni_read_exiv2_to_cache(VNR_FILE(window->file_list->data)->path); - - if(g_strcmp0(window->writable_format_name, "jpeg" ) == 0) + + char *type_use = window->writable_format_name; + // FIXME: use a list to validate against + if (g_strcmp0(type_override, "jpeg" ) == 0 || g_strcmp0(type_override, "png" ) == 0 || g_strcmp0(type_override, "bmp" ) == 0 || g_strcmp0(type_override, "svg" ) == 0) + { + type_use = type_override; + } + if(g_strcmp0(type_use, "jpeg" ) == 0) { gchar *quality; quality = g_strdup_printf ("%i", window->prefs->jpeg_quality); @@ -941,7 +964,7 @@ save_image_cb (GtkWidget *widget, VnrWindow *window) &error, "quality", quality, NULL); g_free(quality); } - else if(g_strcmp0(window->writable_format_name, "png" ) == 0) + else if(g_strcmp0(type_use, "png" ) == 0) { gchar *compression; compression = g_strdup_printf ("%i", window->prefs->png_compression); @@ -955,8 +978,9 @@ save_image_cb (GtkWidget *widget, VnrWindow *window) { gdk_pixbuf_save (uni_image_view_get_pixbuf(UNI_IMAGE_VIEW(window->view)), VNR_FILE(window->file_list->data)->path, - window->writable_format_name, &error, NULL); + type_use, &error, NULL); } + uni_read_exiv2_to_cache(VNR_FILE(window->file_list->data)->path); uni_write_exiv2_from_cache(VNR_FILE(window->file_list->data)->path); if(!window->cursor_is_hidden) @@ -966,13 +990,13 @@ save_image_cb (GtkWidget *widget, VnrWindow *window) { vnr_message_area_show(VNR_MESSAGE_AREA(window->msg_area), TRUE, error->message, FALSE); - return; + return FALSE; } if(window->prefs->reload_on_save) { vnr_window_open(window, FALSE); - return; + return TRUE; } window->modifications = 0; @@ -984,6 +1008,235 @@ save_image_cb (GtkWidget *widget, VnrWindow *window) if(gtk_widget_get_visible(window->props_dlg)) vnr_properties_dialog_update(VNR_PROPERTIES_DIALOG(window->props_dlg)); + + return TRUE; +} + + +static void +copyto_image_response_cb (GtkWidget *dialog, + gint response_id, + VnrWindow *window) +{ + if (response_id == GTK_RESPONSE_ACCEPT) + { + struct stat buffer; + + if (stat (gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)), &buffer) != 0 || file_exists_warning(window)) + { + char orig_file_path[255]; // FIXME: define string (255 char limitation seems wrong) + char filetype_override[255]; + gchar *new_file_path; + + strcpy(orig_file_path, VNR_FILE(window->file_list->data)->path); + new_file_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)); + file_extension_to_type(filetype_override, new_file_path); + + VNR_FILE(window->file_list->data)->path = new_file_path; + + if (! file_move_copy(dialog, window) ) + { + // TODO + } + + gtk_widget_destroy (dialog); + } + + } +} + +static void +copyto_image_cb (GtkWidget *widget, VnrWindow *window) +{ + GtkWidget *dialog; + dialog = gtk_file_chooser_dialog_new (_("Save As Image"), + GTK_WINDOW(window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_window_set_modal (GTK_WINDOW(dialog), FALSE); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), VNR_FILE(window->file_list->data)->path); + gchar *dirname; + if(window->file_list != NULL) + { + dirname = g_path_get_dirname (VNR_FILE(window->file_list->data)->path); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), dirname); + g_free(dirname); + } + + g_signal_connect (dialog, "response", + G_CALLBACK (copyto_image_response_cb), + window); + + gtk_widget_show_all (GTK_WIDGET(dialog)); +} + +static gboolean +file_exists_warning(VnrWindow *window) +{ + gchar *markup, *prompt, *warning; + GtkWidget *dlg = NULL; + int retval; + + warning = _("If you overwrite an item, it will be permanently lost."); + + prompt = g_strdup_printf (_("Are you sure you want to\n" + "overwrite \"%s\"?"), + VNR_FILE(window->file_list->data)->display_name); + markup = g_strdup_printf ("%s\n\n%s", + prompt, warning); + + + dlg = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + NULL); + + gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dlg), + markup); + + gtk_dialog_add_buttons (GTK_DIALOG (dlg), + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_YES, + NULL); + + retval = gtk_dialog_run(GTK_DIALOG(dlg)); + gtk_widget_destroy( dlg ); + + return (retval == GTK_RESPONSE_YES) ? TRUE : FALSE; +} + +/* not finished yet */ +void add_if_writable (GdkPixbufFormat *data, GSList **list) +{ + if (gdk_pixbuf_format_is_writable (data)) + *list = g_slist_prepend (*list, data); +} + +void setup_file_save_formats() +{ + GSList *formats = gdk_pixbuf_get_formats (); + GSList *writable_formats = NULL; + g_slist_foreach (formats, add_if_writable, &writable_formats); + g_slist_free (formats); +} + +/*** + * + * TODO: address how to restart slideshow and other things + * TODO: rename and copy to need confirm overwrite +*/ +static void +rename_image_response_cb (GtkWidget *dialog, + gint response_id, + VnrWindow *window) +{ + if (response_id == GTK_RESPONSE_ACCEPT) + { + struct stat buffer; + + if (stat (gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)), &buffer) != 0 || file_exists_warning(window)) + { + char orig_file_path[255]; // FIXME: define string (255 char limitation seems wrong) + char filetype_override[255]; + gchar *new_file_path; + + strcpy(orig_file_path, VNR_FILE(window->file_list->data)->path); + new_file_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)); + file_extension_to_type(filetype_override, new_file_path); + + if (file_move_copy(dialog, window) ) + { + if (! rename(orig_file_path, new_file_path)) + { + // TODO + } + } + + VNR_FILE(window->file_list->data)->path = new_file_path; + + gtk_widget_destroy (dialog); + + vnr_window_next(window, FALSE); + refresh_list_and_display(window, FALSE, dialog); + } + + } +} + +static gboolean +file_move_copy (GtkWidget *dialog, VnrWindow *window) +{ + struct stat buffer; + + if (stat (gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)), &buffer) != 0 || file_exists_warning(window)) + { + char orig_file_path[255]; // FIXME: define string (255 char limitation seems wrong) + char filetype_override[255]; + gchar *new_file_path; + + strcpy(orig_file_path, VNR_FILE(window->file_list->data)->path); + new_file_path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (dialog)); + file_extension_to_type(filetype_override, new_file_path); + + return save_image_cb(NULL, window, filetype_override); + } + + return FALSE; +} + +void file_extension_to_type(char* filetype_override, const gchar *filepath) +{ + gchar *file_extension; + file_extension = strrchr (filepath, '.'); + + int i; + for (i = 1; file_extension[i]; i++) + { // NOTE: using this instead of strlwr and including ... don't want the bloat for one function call + filetype_override[i-1] = tolower(file_extension[i]); + } + filetype_override[i - 1] = '\0'; // FIXME: file_extension and file_extension2 should be same variable + + if (filetype_override == NULL) + strcpy(filetype_override, ".jpeg"); // fast method, could also use &(fspec[strlen(fspec)]). + + // FIXME: would be better to use EXIM data on new filename to get file image type + // Only JPEG is handled. There could be others + if (strcmp(filetype_override, "jpg" ) == 0 || g_strcmp0(filetype_override, "jpe" ) == 0) + strcpy(filetype_override, "jpeg"); +} + +static void +rename_image_cb (GtkWidget *widget, VnrWindow *window) +{ + GtkWidget *dialog; + dialog = gtk_file_chooser_dialog_new (_("Move/Rename Image"), + GTK_WINDOW(window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + + gtk_window_set_modal (GTK_WINDOW(dialog), FALSE); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), VNR_FILE(window->file_list->data)->path); + gchar *dirname; + if(window->file_list != NULL) + { + dirname = g_path_get_dirname (VNR_FILE(window->file_list->data)->path); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), dirname); + g_free(dirname); + } + + g_signal_connect (dialog, "response", + G_CALLBACK (rename_image_response_cb), + window); + + gtk_widget_show_all (GTK_WIDGET(dialog)); } static void @@ -1301,7 +1554,7 @@ vnr_window_cmd_open(GtkAction *action, VnrWindow *window) { dirname = g_path_get_dirname (VNR_FILE(window->file_list->data)->path); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), dirname); - g_free(dirname); + // g_free(dirname); } g_signal_connect (dialog, "response", @@ -1587,7 +1840,7 @@ vnr_window_cmd_delete(GtkAction *action, VnrWindow *window) NULL); } - if(!window->prefs->confirm_delete || gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_YES ) + if((!window->prefs->confirm_delete || gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_YES )) { GFile *file; GError *error = NULL; @@ -1603,50 +1856,7 @@ vnr_window_cmd_delete(GtkAction *action, VnrWindow *window) } else { - GList *next; - - next = g_list_next(window->file_list); - if(next == NULL) - next = g_list_first(window->file_list); - - if(g_list_length(g_list_first(window->file_list)) != 1) - window->file_list = g_list_delete_link (window->file_list, window->file_list); - else - { - g_list_free(window->file_list); - next = NULL; - } - - if(next == NULL) - { - vnr_window_close(window); - gtk_action_group_set_sensitive(window->actions_collection, FALSE); - deny_slideshow(window); - vnr_window_set_list(window, NULL, FALSE); - vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area), TRUE, - _("The given locations contain no images."), - TRUE); - restart_slideshow = FALSE; - - - if(gtk_widget_get_visible(window->props_dlg)) - vnr_properties_dialog_clear(VNR_PROPERTIES_DIALOG(window->props_dlg)); - } - else - { - vnr_window_set_list(window, next, FALSE); - if(window->prefs->confirm_delete && !window->cursor_is_hidden) - gdk_window_set_cursor(GTK_WIDGET(dlg)->window, - gdk_cursor_new(GDK_WATCH)); - - gdk_flush(); - - vnr_window_close(window); - vnr_window_open(window, FALSE); - if(window->prefs->confirm_delete && !window->cursor_is_hidden) - gdk_window_set_cursor(GTK_WIDGET(dlg)->window, - gdk_cursor_new(GDK_LEFT_PTR)); - } + refresh_list_and_display(window, restart_slideshow, dlg); } } @@ -1667,6 +1877,55 @@ vnr_window_cmd_delete(GtkAction *action, VnrWindow *window) } } +static void refresh_list_and_display(VnrWindow *window, gboolean restart_slideshow, GtkWidget *dlg) +{ + // GtkWidget *dlg = NULL; + GList *next; + + next = g_list_next(window->file_list); + if(next == NULL) + next = g_list_first(window->file_list); + + if(g_list_length(g_list_first(window->file_list)) != 1) + window->file_list = g_list_delete_link (window->file_list, window->file_list); + else + { + g_list_free(window->file_list); + next = NULL; + } + + if(next == NULL) + { + vnr_window_close(window); + gtk_action_group_set_sensitive(window->actions_collection, FALSE); + deny_slideshow(window); + vnr_window_set_list(window, NULL, FALSE); + vnr_message_area_show(VNR_MESSAGE_AREA (window->msg_area), TRUE, + _("The given locations contain no images."), + TRUE); + restart_slideshow = FALSE; + + + if(gtk_widget_get_visible(window->props_dlg)) + vnr_properties_dialog_clear(VNR_PROPERTIES_DIALOG(window->props_dlg)); + } + else + { + vnr_window_set_list(window, next, FALSE); + if(window->prefs->confirm_delete && !window->cursor_is_hidden) + gdk_window_set_cursor(GTK_WIDGET(dlg)->window, + gdk_cursor_new(GDK_WATCH)); + + gdk_flush(); + + vnr_window_close(window); + vnr_window_open(window, FALSE); + if(window->prefs->confirm_delete && !window->cursor_is_hidden) + gdk_window_set_cursor(GTK_WIDGET(dlg)->window, + gdk_cursor_new(GDK_LEFT_PTR)); + } +} + static void vnr_window_cmd_crop(GtkAction *action, VnrWindow *window) { @@ -1713,7 +1972,7 @@ vnr_window_cmd_crop(GtkAction *action, VnrWindow *window) _("Image modifications cannot be saved.\nWriting in this format is not supported."), FALSE); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_SAVE) - save_image_cb(NULL, window); + save_image_cb(NULL, window, NULL); else if(window->prefs->behavior_modify == VNR_PREFS_MODIFY_ASK) vnr_message_area_show_with_button(VNR_MESSAGE_AREA(window->msg_area), FALSE, @@ -1755,6 +2014,18 @@ static const GtkActionEntry action_entry_save[] = { G_CALLBACK (save_image_cb) }, }; +static const GtkActionEntry action_entry_copyto[] = { + { "FileCopyTo", GTK_STOCK_SAVE, N_("Copy _To"), "T", + N_("Copy To file"), + G_CALLBACK (copyto_image_cb) }, +}; + +static const GtkActionEntry action_entry_rename[] = { + { "FileRename", GTK_STOCK_SAVE, N_("Move/Rename"), "F2", + N_("Move/Rename file"), + G_CALLBACK (rename_image_cb) }, +}; + static const GtkToggleActionEntry toggle_entry_properties[] = { { "Properties", GTK_STOCK_PROPERTIES, N_("_Properties"), NULL, N_("Properties"), @@ -2048,6 +2319,7 @@ vnr_window_init (VnrWindow * window) gtk_ui_manager_insert_action_group (window->ui_mngr, window->actions_window, 0); + // --- save window->action_save = gtk_action_group_new("MenuActionSave"); @@ -2062,6 +2334,36 @@ vnr_window_init (VnrWindow * window) gtk_ui_manager_insert_action_group (window->ui_mngr, window->action_save, 0); + // --- rename + window->action_rename = gtk_action_group_new("MenuActionRename"); + + + gtk_action_group_set_translation_domain (window->action_rename, + GETTEXT_PACKAGE); + + gtk_action_group_add_actions (window->action_rename, + action_entry_rename, + G_N_ELEMENTS (action_entry_rename), + window); + + gtk_ui_manager_insert_action_group (window->ui_mngr, + window->action_rename, 0); + + // --- copyto + window->action_copyto = gtk_action_group_new("MenuActionCopyTo"); + + gtk_action_group_set_translation_domain (window->action_copyto, + GETTEXT_PACKAGE); + + gtk_action_group_add_actions (window->action_copyto, + action_entry_copyto, + G_N_ELEMENTS (action_entry_copyto), + window); + + gtk_ui_manager_insert_action_group (window->ui_mngr, + window->action_copyto, 0); + + // --- properties window->action_properties = gtk_action_group_new("MenuActionProperties");