/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2012 Free Software Foundation, Inc. * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "actions.h" #include "callbacks.h" #include "gth-file-source-selections.h" #include "gth-selections-manager.h" #include "shortcuts.h" #define BROWSER_DATA_KEY "selections-browser-data" #define N_SELECTIONS 3 static const GActionEntry actions[] = { { "add-to-selection-1", gth_browser_activate_add_to_selection, "i", "1" }, { "add-to-selection-2", gth_browser_activate_add_to_selection, "i", "2" }, { "add-to-selection-3", gth_browser_activate_add_to_selection, "i", "3" }, { "go-to-selection-1", gth_browser_activate_go_to_selection, "i", "1" }, { "go-to-selection-2", gth_browser_activate_go_to_selection, "i", "2" }, { "go-to-selection-3", gth_browser_activate_go_to_selection, "i", "3" }, { "remove-to-selection-1", gth_browser_activate_remove_from_selection, "i", "1" }, { "remove-to-selection-2", gth_browser_activate_remove_from_selection, "i", "2" }, { "remove-to-selection-3", gth_browser_activate_remove_from_selection, "i", "3" }, { "go-to-container-from-selection", gth_browser_activate_go_to_file_container }, { "remove-from-selection", gth_browser_activate_remove_from_current_selection } }; static const GthShortcut shortcuts[] = { { "add-to-selection-1", N_("Add to selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "1" }, { "add-to-selection-2", N_("Add to selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "2" }, { "add-to-selection-3", N_("Add to selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "3" }, { "remove-from-selection-1", N_("Remove from selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "1" }, { "remove-from-selection-2", N_("Remove from selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "2" }, { "remove-from-selection-3", N_("Remove from selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "3" }, { "go-to-selection-1", N_("Show selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "1" }, { "go-to-selection-2", N_("Show selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "2" }, { "go-to-selection-3", N_("Show selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_INTERNAL, GTH_SHORTCUT_CATEGORY_HIDDEN, "3" }, /* Not real actions, used in the shorcut window for documentation. */ { "add-to-selection-doc", N_("Add to selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_DOC, GTH_SHORTCUT_CATEGORY_SELECTIONS, "1...3" }, { "remove-from-selection-doc", N_("Remove from selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_DOC, GTH_SHORTCUT_CATEGORY_SELECTIONS, "1...3" }, { "go-to-selection-doc", N_("Show selection"), GTH_SHORTCUT_CONTEXT_BROWSER_VIEWER | GTH_SHORTCUT_CONTEXT_DOC, GTH_SHORTCUT_CATEGORY_SELECTIONS, "1...3" }, }; static const GthMenuEntry file_list_popup_open_entries[] = { { N_("Open Folder"), "win.go-to-container-from-selection" }, }; static const GthMenuEntry file_list_popup_delete_entries[] = { { N_("Remove from Selection"), "win.remove-from-selection" }, }; typedef struct { GthBrowser *browser; guint vfs_merge_open_id; guint vfs_merge_delete_id; GtkWidget *selection_buttons[N_SELECTIONS]; gulong folder_changed_id; } BrowserData; static void browser_data_free (BrowserData *data) { g_signal_handler_disconnect (gth_main_get_default_monitor (), data->folder_changed_id); g_free (data); } static void selection_clicked_cb (GtkWidget *button, gpointer user_data) { BrowserData *data = user_data; int n_selection = 0; for (n_selection = 0; n_selection < N_SELECTIONS; n_selection++) if (button == data->selection_buttons[n_selection]) break; g_return_if_fail (n_selection >= 0 && n_selection <= N_SELECTIONS - 1); gth_browser_show_selection (data->browser, n_selection + 1); } static GtkWidget * _selection_button_new (int n_selection, gpointer user_data) { GtkWidget *button; char *tooltip; tooltip = g_strdup_printf (_("Show selection %d"), n_selection); button = gtk_button_new (); gtk_container_add (GTK_CONTAINER (button), gtk_image_new_from_icon_name (gth_selection_get_icon_name (n_selection), GTK_ICON_SIZE_MENU)); gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); gtk_widget_show_all (button); gtk_widget_set_sensitive (button, ! gth_selections_manager_get_is_empty (n_selection)); gtk_widget_set_tooltip_text (button, tooltip); g_signal_connect (button, "clicked", G_CALLBACK (selection_clicked_cb), user_data); g_free (tooltip); return button; } static GtkWidget * create_selection_buttons (BrowserData *data) { GtkWidget *box; int i; box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); gtk_widget_show (box); for (i = 0; i < N_SELECTIONS; i++) { data->selection_buttons[i] = _selection_button_new (i + 1, data); gtk_box_pack_start (GTK_BOX (box), data->selection_buttons[i], FALSE, FALSE, 0); } return box; } static void folder_changed_cb (GthMonitor *monitor, GFile *parent, GList *list /* GFile list */, int position, GthMonitorEvent event, gpointer user_data) { BrowserData *data = user_data; int n_selection; if (event == GTH_MONITOR_EVENT_CHANGED) return; if (! g_file_has_uri_scheme (parent, "selection")) return; n_selection = _g_file_get_n_selection (parent); if (n_selection <= 0) return; gtk_widget_set_sensitive (data->selection_buttons[n_selection - 1], ! gth_selections_manager_get_is_empty (n_selection)); } void selections__gth_browser_construct_cb (GthBrowser *browser) { BrowserData *data; GtkWidget *filter_bar; GtkWidget *filter_bar_extra_area; GtkWidget *selection_buttons; g_return_if_fail (GTH_IS_BROWSER (browser)); data = g_new0 (BrowserData, 1); g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free); data->browser = browser; g_action_map_add_action_entries (G_ACTION_MAP (browser), actions, G_N_ELEMENTS (actions), browser); gth_window_add_shortcuts (GTH_WINDOW (browser), shortcuts, G_N_ELEMENTS (shortcuts)); filter_bar = gth_browser_get_filterbar (browser); filter_bar_extra_area = gth_filterbar_get_extra_area (GTH_FILTERBAR (filter_bar)); selection_buttons = create_selection_buttons (data); gtk_box_pack_start (GTK_BOX (filter_bar_extra_area), selection_buttons, FALSE, FALSE, 0); data->folder_changed_id = g_signal_connect (gth_main_get_default_monitor (), "folder-changed", G_CALLBACK (folder_changed_cb), data); } void selections__gth_browser_selection_changed_cb (GthBrowser *browser, int n_selected) { BrowserData *data; if (! GTH_IS_FILE_SOURCE_SELECTIONS (gth_browser_get_location_source (browser))) return; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); gth_window_enable_action (GTH_WINDOW (browser), "go-to-container-from-selection", n_selected == 1); } static guint get_numeric_keyval (GthBrowser *browser, GdkEventKey *event) { guint keyval; gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (browser))), event->hardware_keycode, event->state & ~GDK_SHIFT_MASK, event->group, &keyval, NULL, NULL, NULL); /* This fixes the keyboard shortcuts for French keyboards (and * maybe others as well) where the number keys are shifted. */ if ((keyval < GDK_KEY_1) || (keyval > GDK_KEY_3)) gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (browser))), event->hardware_keycode, event->state | GDK_SHIFT_MASK, event->group, &keyval, NULL, NULL, NULL); return keyval; } gpointer selections__gth_browser_file_list_key_press_cb (GthBrowser *browser, GdkEventKey *event) { gpointer result = NULL; guint modifiers; modifiers = gtk_accelerator_get_default_mod_mask (); if (((event->state & modifiers) == GDK_MOD1_MASK) || ((event->state & modifiers) == (GDK_SHIFT_MASK|GDK_MOD1_MASK))) { guint keyval; keyval = get_numeric_keyval (browser, event); switch (keyval) { case GDK_KEY_1: case GDK_KEY_2: case GDK_KEY_3: /* Alt+Shift+n => remove from selection n */ if ((event->state & modifiers) == (GDK_SHIFT_MASK|GDK_MOD1_MASK)) gth_browser_remove_from_selection (browser, keyval - GDK_KEY_1 + 1); else /* Alt+n => add to selection n */ gth_browser_add_to_selection (browser, keyval - GDK_KEY_1 + 1); result = GINT_TO_POINTER (1); break; } } if ((event->state & modifiers) == GDK_CONTROL_MASK) { guint keyval; keyval = get_numeric_keyval (browser, event); switch (keyval) { case GDK_KEY_1: case GDK_KEY_2: case GDK_KEY_3: /* Control+n => go to selection n */ gth_browser_show_selection (browser, keyval - GDK_KEY_1 + 1); result = GINT_TO_POINTER (1); break; } } return result; } void selections__gth_browser_load_location_after_cb (GthBrowser *browser, GthFileData *location_data) { BrowserData *data; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); if (GTH_IS_FILE_SOURCE_SELECTIONS (gth_browser_get_location_source (browser))) { if (data->vfs_merge_open_id == 0) data->vfs_merge_open_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_OPEN_ACTIONS), file_list_popup_open_entries, G_N_ELEMENTS (file_list_popup_open_entries)); if (data->vfs_merge_delete_id == 0) data->vfs_merge_delete_id = gth_menu_manager_append_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_DELETE_ACTIONS), file_list_popup_delete_entries, G_N_ELEMENTS (file_list_popup_delete_entries)); } else { gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_OPEN_ACTIONS), data->vfs_merge_open_id); gth_menu_manager_remove_entries (gth_browser_get_menu_manager (browser, GTH_BROWSER_MENU_MANAGER_FILE_LIST_DELETE_ACTIONS), data->vfs_merge_delete_id); data->vfs_merge_open_id = 0; data->vfs_merge_delete_id = 0; } } void selections__gth_browser_update_extra_widget_cb (GthBrowser *browser) { GthFileData *location_data; GtkWidget *info_bar; int n_selection; char *msg; location_data = gth_browser_get_location_data (browser); if (! _g_content_type_is_a (g_file_info_get_content_type (location_data->info), "pix/selection")) return; n_selection = g_file_info_get_attribute_int32 (location_data->info, "pix::n-selection"); if (n_selection <= 0) return; info_bar = gth_browser_get_list_info_bar (browser); gtk_info_bar_set_message_type (GTK_INFO_BAR(info_bar), GTK_MESSAGE_INFO); gth_info_bar_set_icon_name (GTH_INFO_BAR (info_bar), "dialog-information-symbolic", GTK_ICON_SIZE_MENU); gth_info_bar_set_primary_text (GTH_INFO_BAR (info_bar), NULL); msg = g_strdup_printf (_("Use Alt-%d to add files to this selection, Ctrl-%d to view this selection, Alt+Shift+%d to remove files from this selection"), n_selection, n_selection, n_selection); gth_info_bar_set_secondary_text (GTH_INFO_BAR (info_bar), msg); gtk_widget_show (info_bar); g_free (msg); }