Allow the copy of file paths to clipboard.
authorLaurent Monin <geeqie@norz.org>
Wed, 23 Apr 2008 22:17:21 +0000 (22:17 +0000)
committerLaurent Monin <geeqie@norz.org>
Wed, 23 Apr 2008 22:17:21 +0000 (22:17 +0000)
This feature is disabled by default, it can be set through
Preferences > Advanced > Behavior > Show "Copy path" ...
When enabled, it adds a menu entry "Copy path" that let the
user copies current selection's paths to X clipboard.
It is very convenient to paste paths to xterm for example.
Patch by Carles Pina i Estany and me.

16 files changed:
src/collect-table.c
src/dupe.c
src/globals.c
src/img-view.c
src/layout_image.c
src/layout_util.c
src/layout_util.h
src/pan-view.c
src/preferences.c
src/rcfile.c
src/search.c
src/typedefs.h
src/utilops.c
src/utilops.h
src/view_file_icon.c
src/view_file_list.c

index 2481949..c8bb8f8 100644 (file)
@@ -625,6 +625,13 @@ static void collection_table_popup_delete_cb(GtkWidget *widget, gpointer data)
        file_util_delete(NULL, collection_table_popup_file_list(ct), ct->listview);
 }
 
+static void collection_table_popup_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       CollectTable *ct = data;
+
+       file_util_copy_path_list_to_clipboard(collection_table_popup_file_list(ct));
+}
+
 static void collection_table_popup_sort_cb(GtkWidget *widget, gpointer data)
 {
        CollectTable *ct;
@@ -799,6 +806,9 @@ static GtkWidget *collection_table_popup_menu(CollectTable *ct, gint over_icon)
                        G_CALLBACK(collection_table_popup_rename_cb), ct);
        menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, over_icon,
                        G_CALLBACK(collection_table_popup_delete_cb), ct);
+       if (options->show_copy_path)
+               menu_item_add_sensitive(menu, _("_Copy path"), over_icon,
+                                       G_CALLBACK(collection_table_popup_copy_path_cb), ct);
        menu_item_add_divider(menu);
 
        submenu_add_sort(menu, G_CALLBACK(collection_table_popup_sort_cb), ct, FALSE, TRUE, FALSE, 0);
index 4f9f52b..2969363 100644 (file)
@@ -2197,6 +2197,13 @@ static void dupe_menu_delete_cb(GtkWidget *widget, gpointer data)
        file_util_delete(NULL, dupe_listview_get_selection(dw, dw->listview), dw->window);
 }
 
+static void dupe_menu_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       DupeWindow *dw = data;
+
+       file_util_copy_path_list_to_clipboard(dupe_listview_get_selection(dw, dw->listview));
+}
+
 static void dupe_menu_remove_cb(GtkWidget *widget, gpointer data)
 {
        DupeWindow *dw = data;
@@ -2258,6 +2265,9 @@ static GtkWidget *dupe_menu_popup_main(DupeWindow *dw, DupeItem *di)
                                G_CALLBACK(dupe_menu_rename_cb), dw);
        menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, on_row,
                                G_CALLBACK(dupe_menu_delete_cb), dw);
+       if (options->show_copy_path)
+               menu_item_add_sensitive(menu, _("_Copy path"), on_row,
+                                       G_CALLBACK(dupe_menu_copy_path_cb), dw);
        menu_item_add_divider(menu);
        menu_item_add_stock_sensitive(menu, _("Rem_ove"), GTK_STOCK_REMOVE, on_row,
                                G_CALLBACK(dupe_menu_remove_cb), dw);
index 3122326..d5a97ac 100644 (file)
@@ -117,6 +117,7 @@ ConfOptions *init_options(ConfOptions *options)
        options->panels.sort.selection_state = 0;
 
        options->progressive_key_scrolling = FALSE;
+       options->show_copy_path = FALSE;
        options->show_icon_names = TRUE;
 
        options->slideshow.delay = 150;
index 5dd013f..2488449 100644 (file)
@@ -1183,6 +1183,15 @@ static void view_delete_cb(GtkWidget *widget, gpointer data)
        file_util_delete(image_get_fd(imd), NULL, imd->widget);
 }
 
+static void view_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       ViewWindow *vw = data;
+       ImageWindow *imd;
+
+       imd = view_window_active_image(vw);
+       file_util_copy_path_to_clipboard(image_get_fd(imd));
+}
+
 static void view_fullscreen_cb(GtkWidget *widget, gpointer data)
 {
        ViewWindow *vw = data;
@@ -1279,6 +1288,8 @@ static GtkWidget *view_popup_menu(ViewWindow *vw)
        menu_item_add(menu, _("_Move..."), G_CALLBACK(view_move_cb), vw);
        menu_item_add(menu, _("_Rename..."), G_CALLBACK(view_rename_cb), vw);
        menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(view_delete_cb), vw);
+       if (options->show_copy_path)
+               menu_item_add(menu, _("_Copy path"), G_CALLBACK(view_copy_path_cb), vw);
 
        menu_item_add_divider(menu);
 
index 82b7718..2560969 100644 (file)
@@ -637,6 +637,13 @@ static void li_pop_menu_copy_cb(GtkWidget *widget, gpointer data)
                       li_pop_menu_click_parent(widget, lw));
 }
 
+static void li_pop_menu_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       file_util_copy_path_to_clipboard(layout_image_get_fd(lw));
+}
+
 static void li_pop_menu_move_cb(GtkWidget *widget, gpointer data)
 {
        LayoutWindow *lw = data;
@@ -765,6 +772,12 @@ static GtkWidget *layout_image_pop_menu(LayoutWindow *lw)
        if (!path) gtk_widget_set_sensitive(item, FALSE);
        item = menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(li_pop_menu_delete_cb), lw);
        if (!path) gtk_widget_set_sensitive(item, FALSE);
+       
+       if (options->show_copy_path)
+               {
+               item = menu_item_add(menu, _("_Copy path"), G_CALLBACK(li_pop_menu_copy_path_cb), lw);
+               if (!path) gtk_widget_set_sensitive(item, FALSE);
+       }
 
        menu_item_add_divider(menu);
 
index f5b3890..0bba1f3 100644 (file)
@@ -261,6 +261,13 @@ static void layout_menu_copy_cb(GtkAction *action, gpointer data)
        file_util_copy(NULL, layout_selection_list(lw), NULL, layout_window(lw));
 }
 
+static void layout_menu_copy_path_cb(GtkAction *action, gpointer data)
+{
+       LayoutWindow *lw = data;
+
+       file_util_copy_path_list_to_clipboard(layout_selection_list(lw));
+}
+
 static void layout_menu_move_cb(GtkAction *action, gpointer data)
 {
        LayoutWindow *lw = data;
@@ -985,6 +992,38 @@ void layout_recent_add_path(const gchar *path)
        layout_recent_update_all();
 }
 
+/*
+ *-----------------------------------------------------------------------------
+ * copy path
+ *-----------------------------------------------------------------------------
+ */
+
+static void layout_copy_path_update(LayoutWindow *lw)
+{
+       GtkWidget *item = gtk_ui_manager_get_widget(lw->ui_manager, "/MainMenu/FileMenu/CopyPath");
+
+       if (!item) return;
+       
+       if (options->show_copy_path)
+               gtk_widget_show(item);
+       else
+               gtk_widget_hide(item);
+}
+
+void layout_copy_path_update_all(void)
+{
+       GList *work;
+
+       work = layout_window_list;
+       while (work)
+               {
+               LayoutWindow *lw = work->data;
+               work = work->next;
+
+               layout_copy_path_update(lw);
+               }
+}
+
 /*
  *-----------------------------------------------------------------------------
  * menu
@@ -1030,6 +1069,7 @@ static GtkActionEntry menu_entries[] = {
   { "Delete",  GTK_STOCK_DELETE,       N_("_Delete..."),       "<control>D",   NULL,   CB(layout_menu_delete_cb) },
   { "DeleteAlt1",GTK_STOCK_DELETE,     N_("_Delete..."),       "Delete",       NULL,   CB(layout_menu_delete_cb) },
   { "DeleteAlt2",GTK_STOCK_DELETE,     N_("_Delete..."),       "KP_Delete",    NULL,   CB(layout_menu_delete_cb) },
+  { "CopyPath",                NULL,           N_("_Copy path"),       NULL,           NULL,   CB(layout_menu_copy_path_cb) },
   { "CloseWindow",     GTK_STOCK_CLOSE,N_("C_lose window"),    "<control>W",   NULL,   CB(layout_menu_close_cb) },
   { "Quit",            GTK_STOCK_QUIT, N_("_Quit"),            "<control>Q",   NULL,   CB(layout_menu_exit_cb) },
 
@@ -1146,6 +1186,7 @@ static const char *menu_ui_description =
 "      <menuitem action='Move'/>"
 "      <menuitem action='Rename'/>"
 "      <menuitem action='Delete'/>"
+"      <menuitem action='CopyPath'/>"
 "      <separator/>"
 "      <menuitem action='CloseWindow'/>"
 "      <menuitem action='Quit'/>"
@@ -1387,8 +1428,9 @@ void layout_actions_setup(LayoutWindow *lw)
                g_error_free (error);
                exit (EXIT_FAILURE);
                }
-
+       
        layout_actions_setup_marks(lw);
+       layout_copy_path_update(lw);
 }
 
 void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window)
index b7d6a70..6630503 100644 (file)
@@ -28,6 +28,8 @@ void layout_edit_update_all(void);
 void layout_recent_update_all(void);
 void layout_recent_add_path(const gchar *path);
 
+void layout_copy_path_update_all(void);
+
 void layout_actions_setup(LayoutWindow *lw);
 void layout_actions_add_window(LayoutWindow *lw, GtkWidget *window);
 GtkWidget *layout_actions_menu_bar(LayoutWindow *lw);
index 2083520..16b9e6c 100644 (file)
@@ -2737,6 +2737,15 @@ static void pan_delete_cb(GtkWidget *widget, gpointer data)
        if (fd) file_util_delete(fd, NULL, pw->imd->widget);
 }
 
+static void pan_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       PanWindow *pw = data;
+       FileData *fd;
+
+       fd = pan_menu_click_fd(pw);
+       if (fd) file_util_copy_path_to_clipboard(fd);
+}
+
 static void pan_exif_date_toggle_cb(GtkWidget *widget, gpointer data)
 {
        PanWindow *pw = data;
@@ -2812,6 +2821,9 @@ static GtkWidget *pan_popup_menu(PanWindow *pw)
                                G_CALLBACK(pan_rename_cb), pw);
        menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active,
                                      G_CALLBACK(pan_delete_cb), pw);
+       if (options->show_copy_path)
+               menu_item_add_sensitive(menu, _("_Copy path"), active,
+                                       G_CALLBACK(pan_copy_path_cb), pw);
 
        menu_item_add_divider(menu);
        item = menu_item_add_check(menu, _("Sort by E_xif date"), pw->exif_date_enable,
index 5f9458f..1d67e1d 100644 (file)
@@ -270,6 +270,12 @@ static void config_window_apply(void)
 
        options->open_recent_list_maxsize = c_options->open_recent_list_maxsize;
        options->dnd_icon_size = c_options->dnd_icon_size;
+       
+       if (options->show_copy_path != c_options->show_copy_path)
+               {
+               options->show_copy_path = c_options->show_copy_path;
+               layout_copy_path_update_all();
+               }
 
 #ifdef DEBUG
        debug = debug_c;
@@ -1396,6 +1402,7 @@ static void config_tab_advanced(GtkWidget *notebook)
        gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
        gtk_widget_show(button);
 
+
        group = pref_group_new(vbox, FALSE, _("Behavior"), GTK_ORIENTATION_VERTICAL);
 
        pref_checkbox_new_int(group, _("Rectangular selection in icon view"),
@@ -1407,6 +1414,9 @@ static void config_tab_advanced(GtkWidget *notebook)
        pref_checkbox_new_int(group, _("In place renaming"),
                              options->file_ops.enable_in_place_rename, &c_options->file_ops.enable_in_place_rename);
 
+       pref_checkbox_new_int(group, _("Show \"Copy path\" menu item which write the path of selected files to clipboard"),
+                             options->show_copy_path, &c_options->show_copy_path);
+
        pref_spin_new_int(group, _("Open recent list maximum size"), NULL,
                          1, 50, 1, options->open_recent_list_maxsize, &c_options->open_recent_list_maxsize);
        
index 4fa49da..74a991f 100644 (file)
@@ -301,6 +301,7 @@ void save_options(void)
        WRITE_SUBTITLE("General Options");
 
        WRITE_BOOL(show_icon_names);
+       WRITE_BOOL(show_copy_path);
        WRITE_SEPARATOR();
 
        WRITE_BOOL(tree_descend_subdirs);
@@ -614,6 +615,7 @@ void load_options(void)
 
                /* general options */
                READ_BOOL(show_icon_names);
+               READ_BOOL(show_copy_path);
 
                READ_BOOL(tree_descend_subdirs);
                READ_BOOL(lazy_image_sync);
index 88c4e91..3766d10 100644 (file)
@@ -946,6 +946,13 @@ static void sr_menu_delete_cb(GtkWidget *widget, gpointer data)
        file_util_delete(NULL, search_result_selection_list(sd), sd->window);
 }
 
+static void sr_menu_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       SearchData *sd = data;
+
+       file_util_copy_path_list_to_clipboard(search_result_selection_list(sd));
+}
+
 static void sr_menu_remove_cb(GtkWidget *widget, gpointer data)
 {
        SearchData *sd = data;
@@ -993,6 +1000,9 @@ static GtkWidget *search_result_menu(SearchData *sd, gint on_row, gint empty)
                                G_CALLBACK(sr_menu_rename_cb), sd);
        menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, on_row,
                                      G_CALLBACK(sr_menu_delete_cb), sd);
+       if (options->show_copy_path)
+               menu_item_add_sensitive(menu, _("_Copy path"), on_row,
+                                       G_CALLBACK(sr_menu_copy_path_cb), sd);
        menu_item_add_divider(menu);
        menu_item_add_stock_sensitive(menu, _("Rem_ove"), GTK_STOCK_REMOVE, on_row,
                                      G_CALLBACK(sr_menu_remove_cb), sd);
index a346c53..66e549c 100644 (file)
@@ -749,6 +749,7 @@ struct _ConfOptions
        gint place_dialogs_under_mouse;
        gint mousewheel_scrolls;
        gint show_icon_names;
+       gint show_copy_path;
 
        /* various */
        gint startup_path_enable;
index eed3e32..3800aea 100644 (file)
@@ -1238,6 +1238,40 @@ void file_util_copy(FileData *source_fd, GList *source_list, const gchar *dest_p
        real_file_util_move(source_fd, source_list, dest_path, TRUE, parent);
 }
 
+void file_util_copy_path_to_clipboard(FileData *fd)
+{
+       GtkClipboard *clipboard;
+
+       if (!fd || !*fd->path) return;
+
+       clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
+       gtk_clipboard_set_text(clipboard, g_shell_quote(fd->path), -1);
+}
+
+void file_util_copy_path_list_to_clipboard(GList *list)
+{
+       GtkClipboard *clipboard;
+       GList *work;
+       GString *new;
+
+       clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
+       
+       new = g_string_new("");
+       work = list;
+       while (work) {
+               FileData *fd = work->data;
+               work = work->next;
+
+               if (!fd || !*fd->path) continue;
+       
+               g_string_append(new, g_shell_quote(fd->path));
+               if (work) g_string_append_c(new, ' ');
+               }
+       
+       gtk_clipboard_set_text(clipboard, new->str, new->len);
+       g_string_free(new, TRUE);
+}
+
 void file_util_move_simple(GList *list, const gchar *dest_path)
 {
        if (!list) return;
index ee143fd..90d1d64 100644 (file)
@@ -57,4 +57,7 @@ gint copy_file_ext(FileData *fd);
 gint move_file_ext(FileData *fd);
 gint rename_file_ext(FileData *fd);
 
+void file_util_copy_path_to_clipboard(FileData *fd);
+void file_util_copy_path_list_to_clipboard(GList *list);
+
 #endif
index acc5877..1e361c0 100644 (file)
@@ -242,6 +242,13 @@ static void vficon_pop_menu_delete_cb(GtkWidget *widget, gpointer data)
        file_util_delete(NULL, vficon_pop_menu_file_list(vfi), vfi->listview);
 }
 
+static void vficon_pop_menu_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       ViewFileIcon *vfi = data;
+
+       file_util_copy_path_list_to_clipboard(vficon_pop_menu_file_list(vfi));
+}
+
 static void vficon_pop_menu_sort_cb(GtkWidget *widget, gpointer data)
 {
        ViewFileIcon *vfi;
@@ -336,6 +343,11 @@ static GtkWidget *vficon_pop_menu(ViewFileIcon *vfi, gint active)
        gtk_widget_set_sensitive(item, active);
        item = menu_item_add_stock(menu, _("_Delete..."), GTK_STOCK_DELETE, G_CALLBACK(vficon_pop_menu_delete_cb), vfi);
        gtk_widget_set_sensitive(item, active);
+       if (options->show_copy_path)
+               {
+               item = menu_item_add(menu, _("_Copy path"), G_CALLBACK(vficon_pop_menu_copy_path_cb), vfi);
+               gtk_widget_set_sensitive(item, active);
+               }
 
        menu_item_add_divider(menu);
 
index ab9d2a0..f70768f 100644 (file)
@@ -344,6 +344,13 @@ static void vflist_pop_menu_copy_cb(GtkWidget *widget, gpointer data)
        file_util_copy(NULL, vflist_pop_menu_file_list(vfl), NULL, vfl->listview);
 }
 
+static void vflist_pop_menu_copy_path_cb(GtkWidget *widget, gpointer data)
+{
+       ViewFileList *vfl = data;
+
+       file_util_copy_path_list_to_clipboard(vflist_pop_menu_file_list(vfl));
+}
+
 static void vflist_pop_menu_move_cb(GtkWidget *widget, gpointer data)
 {
        ViewFileList *vfl = data;
@@ -581,7 +588,10 @@ static GtkWidget *vflist_pop_menu(ViewFileList *vfl, FileData *fd, gint col_idx)
        menu_item_add_sensitive(menu, _("_Rename..."), active,
                                G_CALLBACK(vflist_pop_menu_rename_cb), vfl);
        menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active,
-                               G_CALLBACK(vflist_pop_menu_delete_cb), vfl);
+                                     G_CALLBACK(vflist_pop_menu_delete_cb), vfl);
+       if (options->show_copy_path)
+               menu_item_add_sensitive(menu, _("_Copy path"), active,
+                                       G_CALLBACK(vflist_pop_menu_copy_path_cb), vfl);
 
        menu_item_add_divider(menu);