gnome-commander r1658 - in branches/gcmd-1-3: . doc/C po src



Author: epiotr
Date: Thu Mar 20 21:30:57 2008
New Revision: 1658
URL: http://svn.gnome.org/viewvc/gnome-commander?rev=1658&view=rev

Log:
Added GUI for keyboard shortcuts management

Added:
   branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.cc
   branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.h
Modified:
   branches/gcmd-1-3/ChangeLog
   branches/gcmd-1-3/configure.in
   branches/gcmd-1-3/doc/C/gnome-commander.xml
   branches/gcmd-1-3/po/POTFILES.in
   branches/gcmd-1-3/src/Makefile.am
   branches/gcmd-1-3/src/gnome-cmd-main-menu.cc
   branches/gcmd-1-3/src/gnome-cmd-user-actions.cc
   branches/gcmd-1-3/src/gnome-cmd-user-actions.h

Modified: branches/gcmd-1-3/configure.in
==============================================================================
--- branches/gcmd-1-3/configure.in	(original)
+++ branches/gcmd-1-3/configure.in	Thu Mar 20 21:30:57 2008
@@ -44,7 +44,7 @@
 
 GLIB_REQ=2.6.0
 GMODULE_REQ=2.0.0
-GTK_REQ=2.8.0
+GTK_REQ=2.10.0
 GNOME_REQ=2.0.0
 GNOMEUI_REQ=2.4.0
 GNOMEVFS_REQ=2.0.0

Modified: branches/gcmd-1-3/doc/C/gnome-commander.xml
==============================================================================
--- branches/gcmd-1-3/doc/C/gnome-commander.xml	(original)
+++ branches/gcmd-1-3/doc/C/gnome-commander.xml	Thu Mar 20 21:30:57 2008
@@ -4137,8 +4137,7 @@
     <sect2 id="gnome-commander-user-actions-managing">
         <title>Managing user actions</title>
         <para>Key bindings reside in [key-bindings] section of &app; config file
-              (<term><guilabel>~/.gnome2/gnome-commander</guilabel></term>).
-              Currently there is no GUI for key configuration management.</para>
+              (<term><guilabel>~/.gnome2/gnome-commander</guilabel></term>).</para>
         <para>Config file syntax:</para>
         <para>
             <command>[&lt;shift&gt;][&lt;control&gt;][&lt;alt&gt;][&lt;win&gt;]key_name=action[|options]</command>
@@ -4420,7 +4419,12 @@
                     </row>
                     <row valign="top">
                         <entry><para>options.edit_mime_types</para></entry>
-                        <entry><para>Edit MIME types</para></entry>
+                        <entry><para>Configure MIME types</para></entry>
+                        <entry><para></para></entry>
+                    </row>
+                    <row valign="top">
+                        <entry><para>options.shortcuts</para></entry>
+                        <entry><para>Configure keyboard shortcuts</para></entry>
                         <entry><para></para></entry>
                     </row>
                     <row valign="top">

Modified: branches/gcmd-1-3/po/POTFILES.in
==============================================================================
--- branches/gcmd-1-3/po/POTFILES.in	(original)
+++ branches/gcmd-1-3/po/POTFILES.in	Thu Mar 20 21:30:57 2008
@@ -28,6 +28,7 @@
 src/gnome-cmd-file-props-dialog.cc
 src/gnome-cmd-file-selector.cc
 src/gnome-cmd-file.cc
+src/gnome-cmd-key-shortcuts-dialog.cc
 src/gnome-cmd-list-popmenu.cc
 src/gnome-cmd-main-menu.cc
 src/gnome-cmd-main-win.cc

Modified: branches/gcmd-1-3/src/Makefile.am
==============================================================================
--- branches/gcmd-1-3/src/Makefile.am	(original)
+++ branches/gcmd-1-3/src/Makefile.am	Thu Mar 20 21:30:57 2008
@@ -50,6 +50,7 @@
 	gnome-cmd-file.h gnome-cmd-file.cc \
 	gnome-cmd-hintbox.h gnome-cmd-hintbox.cc \
 	gnome-cmd-includes.h \
+	gnome-cmd-key-shortcuts-dialog.h gnome-cmd-key-shortcuts-dialog.cc \
 	gnome-cmd-list-popmenu.h gnome-cmd-list-popmenu.cc \
 	gnome-cmd-main-menu.h gnome-cmd-main-menu.cc \
 	gnome-cmd-main-win.h gnome-cmd-main-win.cc \

Added: branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.cc
==============================================================================
--- (empty file)
+++ branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.cc	Thu Mar 20 21:30:57 2008
@@ -0,0 +1,614 @@
+/*
+    GNOME Commander - A GNOME based file manager
+    Copyright (C) 2001-2006 Marcus Bjurman
+
+    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, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include "gnome-cmd-includes.h"
+#include "gnome-cmd-key-shortcuts-dialog.h"
+#include "gnome-cmd-data.h"
+#include "gnome-cmd-hintbox.h"
+#include "dict.h"
+#include "utils.h"
+
+using namespace std;
+
+
+#define GNOME_CMD_TYPE_KEY_SHORTCUTS_DIALOG          (gnome_cmd_key_shortcuts_dialog_get_type())
+#define GNOME_CMD_KEY_SHORTCUTS_DIALOG(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_CMD_TYPE_KEY_SHORTCUTS_DIALOG, GnomeCmdKeyShortcutsDialog))
+#define GNOME_CMD_KEY_SHORTCUTS_DIALOG_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_CMD_TYPE_KEY_SHORTCUTS_DIALOG, GnomeCmdKeyShortcutsDialogClass))
+#define GNOME_CMD_IS_KEY_SHORTCUTS_DIALOG(obj)       (G_TYPE_INSTANCE_CHECK_TYPE ((obj), GNOME_CMD_TYPE_KEY_SHORTCUTS_DIALOG)
+
+
+typedef struct _GnomeCmdKeyShortcutsDialog GnomeCmdKeyShortcutsDialog;
+typedef struct _GnomeCmdKeyShortcutsDialogClass GnomeCmdKeyShortcutsDialogClass;
+
+
+struct GnomeCmdKeyShortcutsDialogPrivate
+{
+    GnomeCmdUserActions actions;            // local copy of user actions
+
+  public:
+
+    GnomeCmdKeyShortcutsDialogPrivate();
+};
+
+
+struct _GnomeCmdKeyShortcutsDialog
+{
+    GtkDialog parent;
+
+    GnomeCmdKeyShortcutsDialogPrivate *priv;
+
+    static GnomeCmdUserActions *user_actions;
+};
+
+
+struct _GnomeCmdKeyShortcutsDialogClass
+{
+    GtkDialogClass parent_class;
+};
+
+
+inline GnomeCmdKeyShortcutsDialogPrivate::GnomeCmdKeyShortcutsDialogPrivate()
+{
+    if (_GnomeCmdKeyShortcutsDialog::user_actions)
+        actions = *_GnomeCmdKeyShortcutsDialog::user_actions;
+}
+
+
+GnomeCmdUserActions *_GnomeCmdKeyShortcutsDialog::user_actions = NULL;
+
+
+G_DEFINE_TYPE (GnomeCmdKeyShortcutsDialog, gnome_cmd_key_shortcuts_dialog, GTK_TYPE_DIALOG)
+
+
+static void gnome_cmd_key_shortcuts_dialog_finalize (GObject *object)
+{
+    GnomeCmdKeyShortcutsDialog *dialog = GNOME_CMD_KEY_SHORTCUTS_DIALOG (object);
+
+    delete dialog->priv;
+
+    G_OBJECT_CLASS (gnome_cmd_key_shortcuts_dialog_parent_class)->finalize (object);
+}
+
+
+static void response_callback (GnomeCmdKeyShortcutsDialog *dialog, int response_id, gpointer data)
+{
+    switch (response_id)
+    {
+        case GTK_RESPONSE_OK:
+            if (dialog->user_actions)
+                *dialog->user_actions = dialog->priv->actions;
+            break;
+
+        case GTK_RESPONSE_NONE:
+        case GTK_RESPONSE_DELETE_EVENT:
+        case GTK_RESPONSE_CANCEL:
+            break;
+
+        case GTK_RESPONSE_HELP:
+            gnome_cmd_help_display ("gnome-commander.xml", "gnome-commander-user-actions");
+            g_signal_stop_emission_by_name (dialog, "response");
+            break;
+
+        default :
+            g_assert_not_reached ();
+    }
+}
+
+
+static void gnome_cmd_key_shortcuts_dialog_class_init (GnomeCmdKeyShortcutsDialogClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = gnome_cmd_key_shortcuts_dialog_finalize;
+}
+
+
+inline GtkWidget *create_view_and_model (GnomeCmdUserActions &user_actions);
+inline GtkTreeModel *create_and_fill_model (GnomeCmdUserActions &user_actions);
+
+static void accel_edited_callback (GtkCellRendererAccel *accel, const char *path_string, guint accel_key, GdkModifierType accel_mask, guint hardware_keycode, GtkWidget *view);
+static void cell_edited_callback (GtkCellRendererText *cell, gchar *path_string, gchar *new_text, GtkWidget *view);
+static void add_clicked_callback (GtkButton *button, GtkWidget *view);
+static void remove_clicked_callback (GtkButton *button, GtkWidget *view);
+
+
+static void gnome_cmd_key_shortcuts_dialog_init (GnomeCmdKeyShortcutsDialog *dialog)
+{
+    dialog->priv = new GnomeCmdKeyShortcutsDialogPrivate;
+
+    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
+    gtk_window_set_title (GTK_WINDOW (dialog), _("Keyboard Shortcuts"));
+    gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+    gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+    gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
+    gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
+
+    GtkWidget *vbox = gtk_vbox_new (FALSE, 12);
+    gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
+    gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
+    gtk_widget_show (vbox);
+
+    GtkWidget *hbox = gtk_hbox_new (FALSE, 12);
+    gtk_container_add (GTK_CONTAINER (vbox), hbox);
+    gtk_widget_show (hbox);
+
+    GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+    gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
+    gtk_box_pack_start (GTK_BOX (hbox), scrolled_window, TRUE, TRUE, 0);
+    gtk_widget_show (scrolled_window);
+
+    GtkWidget *view = create_view_and_model (*dialog->user_actions);
+    gtk_widget_set_size_request (view, 600, 400);
+    gtk_container_add (GTK_CONTAINER (scrolled_window), view);
+    gtk_widget_show (view);
+
+    GtkWidget *box = gnome_cmd_hint_box_new (_("To edit a shortcut key, click on the "
+                                               "corresponding row and type a new "
+                                               "accelerator, or press escape to "
+                                               "cancel."));
+    gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
+    gtk_widget_show (box);
+
+    vbox = gtk_vbox_new (FALSE, 12);
+    gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+    gtk_widget_show (vbox);
+
+    GtkWidget *button = gtk_button_new_from_stock (GTK_STOCK_ADD);
+    g_signal_connect (button, "clicked", G_CALLBACK (add_clicked_callback), view);
+    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+    gtk_widget_show (button);
+
+    button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+    g_signal_connect (button, "clicked", G_CALLBACK (remove_clicked_callback), view);
+    gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+    gtk_widget_show (button);
+
+    gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                            GTK_STOCK_HELP, GTK_RESPONSE_HELP,
+                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                            GTK_STOCK_OK, GTK_RESPONSE_OK,
+                            NULL);
+
+    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+    g_signal_connect (dialog, "response", G_CALLBACK (response_callback), dialog);
+
+    gtk_widget_grab_focus (view);
+}
+
+
+void gnome_cmd_key_shortcuts_dialog_new (GnomeCmdUserActions &user_actions)
+{
+    GnomeCmdKeyShortcutsDialog::user_actions = &user_actions;        // ugly hack, but can't come to any better method of passing data to gnome_cmd_key_shortcuts_dialog_init ()
+
+    GtkWidget *dialog = gtk_widget_new (GNOME_CMD_TYPE_KEY_SHORTCUTS_DIALOG, NULL);
+
+    g_return_if_fail (dialog != NULL);
+
+    gtk_dialog_run (GTK_DIALOG (dialog));
+
+    gtk_widget_destroy (dialog);
+}
+
+
+inline GtkTreeViewColumn *create_new_text_column (GtkTreeView *view, GtkCellRenderer *&renderer, gint COL_ID, const gchar *title=NULL)
+{
+    renderer = gtk_cell_renderer_text_new ();
+
+    GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (title,
+                                                                       renderer,
+                                                                       "text", COL_ID,
+                                                                       NULL);
+    g_object_set (col,
+                  "clickable", TRUE,
+                  "resizable", TRUE,
+                  NULL);
+
+    // pack tree view column into tree view
+    gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
+
+    return col;
+}
+
+
+inline GtkTreeViewColumn *create_new_text_column (GtkTreeView *view, gint COL_ID, const gchar *title=NULL)
+{
+    GtkCellRenderer *renderer = NULL;
+
+    return create_new_text_column (view, renderer, COL_ID, title);
+}
+
+
+inline GtkTreeViewColumn *create_new_accel_column (GtkTreeView *view, GtkCellRenderer *&renderer, gint COL_KEYS_ID, gint COL_MODS_ID, const gchar *title=NULL)
+{
+    renderer = gtk_cell_renderer_accel_new ();
+    renderer->mode = GTK_CELL_RENDERER_MODE_EDITABLE;
+    GTK_CELL_RENDERER_TEXT (renderer)->editable = TRUE;
+
+    GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (title,
+                                                                       renderer,
+                                                                       "accel-key", COL_KEYS_ID,
+                                                                       "accel-mods", COL_MODS_ID,
+                                                                       // "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
+                                                                       NULL);
+    g_object_set (col,
+                  "clickable", TRUE,
+                  "resizable", TRUE,
+                  NULL);
+
+    // pack tree view column into tree view
+    gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
+
+    return col;
+}
+
+
+inline GtkTreeViewColumn *create_new_combo_column (GtkTreeView *view, GtkCellRenderer *&renderer, gint COL_ID, const gchar *title=NULL)
+{
+    renderer = gtk_cell_renderer_combo_new ();
+
+    GtkTreeViewColumn *col = gtk_tree_view_column_new_with_attributes (title,
+                                                                       renderer,
+                                                                       "text", COL_ID,
+                                                                       "has-entry", TRUE,
+                                                                       // "model", ...,
+                                                                       // "text-column", ...,
+                                                                       NULL);
+    g_object_set (col,
+                  "clickable", TRUE,
+                  "resizable", TRUE,
+                  NULL);
+
+    // pack tree view column into tree view
+    gtk_tree_view_append_column (GTK_TREE_VIEW (view), col);
+
+    return col;
+}
+
+
+enum
+{
+    COL_SHORTCUT,       // FIXME: temporarily, to be removed
+    COL_ACCEL_KEY,
+    COL_ACCEL_MASK,
+    COL_ACTION,
+    COL_ACCEL_CLOSURE,
+    COL_OPTION,
+    NUM_COLUMNS
+} ;
+
+
+enum
+{
+    SORTID_SHORTCUT,    // FIXME: temporarily, to be removed
+    SORTID_ACCEL,
+    SORTID_ACTION,
+    SORTID_OPTION
+};
+
+
+inline GtkWidget *create_view_and_model (GnomeCmdUserActions &user_actions)
+{
+    GtkWidget *view = gtk_tree_view_new ();
+
+    g_object_set (view,
+                  "rules-hint", TRUE,
+                  "enable-search", TRUE,
+                  "search-column", COL_ACTION,
+                  NULL);
+
+    GtkCellRenderer *renderer = NULL;
+    GtkTreeViewColumn *col = NULL;
+
+    GtkTooltips *tips = gtk_tooltips_new ();
+
+    col = create_new_text_column (GTK_TREE_VIEW (view), renderer, COL_SHORTCUT, "test: [key-bindings]"); // FIXME: temporarily, to be removed
+    gtk_tooltips_set_tip (tips, col->button, "Keyboard shortcuts as specified in ~/.gnome2/gnome-commander", NULL);          // FIXME: temporarily, to be removed
+
+    g_object_set (renderer,
+                  "foreground-set", TRUE,
+                  "foreground", "DarkGray",
+                  NULL);
+
+    col = create_new_accel_column (GTK_TREE_VIEW (view), renderer, COL_ACCEL_KEY, COL_ACCEL_MASK, _("Shortcut Key"));
+    gtk_tooltips_set_tip (tips, col->button, _("Keyboard shortcut for selected action"), NULL);
+    gtk_tree_view_column_set_sort_column_id (col, SORTID_ACCEL);
+
+    g_signal_connect (renderer, "accel-edited", G_CALLBACK (accel_edited_callback), view);
+    // g_signal_connect (renderer, "accel-cleared", G_CALLBACK (gimp_action_view_accel_cleared), view);
+
+    col = create_new_combo_column (GTK_TREE_VIEW (view), renderer, COL_ACTION, _("Action"));
+    gtk_tooltips_set_tip (tips, col->button, _("User action"), NULL);
+    gtk_tree_view_column_set_sort_column_id (col, SORTID_ACTION);
+
+    g_object_set (renderer,
+                  "editable", TRUE,
+                  NULL);
+
+    col = create_new_text_column (GTK_TREE_VIEW (view), renderer, COL_OPTION, _("Options"));
+    gtk_tooltips_set_tip (tips, col->button, _("Optional data"), NULL);
+    gtk_tree_view_column_set_sort_column_id (col, SORTID_OPTION);
+    g_signal_connect(renderer, "edited", (GCallback) cell_edited_callback, view);
+
+    g_object_set (renderer,
+                  "editable", TRUE,
+                  "ellipsize-set", TRUE,
+                  "ellipsize", PANGO_ELLIPSIZE_END,
+                  NULL);
+
+    GtkTreeModel *model = create_and_fill_model (user_actions);
+
+    gtk_tree_view_set_model (GTK_TREE_VIEW (view), model);
+
+    g_object_unref (model);          // destroy model automatically with view
+
+    GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+    gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+    GtkTreeIter iter;
+
+    if (gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (view)), &iter))      // select the first row here...
+        gtk_tree_selection_select_iter (selection, &iter);
+
+    return view;
+}
+
+
+static gint sort_by_col (GtkTreeModel *model, GtkTreeIter *i1, GtkTreeIter *i2, gpointer COL)
+{
+    gchar *s1;
+    gchar *s2;
+
+    gtk_tree_model_get (model, i1, GPOINTER_TO_UINT (COL), &s1, -1);
+    gtk_tree_model_get (model, i2, GPOINTER_TO_UINT (COL), &s2, -1);
+
+    gint retval = 0;
+
+    if (!s1 && !s2)
+        return retval;
+
+    if (!s1)
+        retval = 1;
+    else
+        if (!s2)
+            retval = -1;
+        else
+        {
+            // compare s1 and s2 in UTF8 aware way, case insensitive
+            gchar *is1 = g_utf8_casefold (s1, -1);
+            gchar *is2 = g_utf8_casefold (s2, -1);
+
+            retval = g_utf8_collate (is1, is2);
+
+            g_free (is1);
+            g_free (is2);
+        }
+
+    g_free (s1);
+    g_free (s2);
+
+    return retval;
+}
+
+
+static gint sort_by_accel (GtkTreeModel *model, GtkTreeIter *i1, GtkTreeIter *i2, gpointer user_data)
+{
+    guint key1, key2;
+    GdkModifierType mask1, mask2;
+
+    gtk_tree_model_get (model, i1, COL_ACCEL_KEY, &key1, COL_ACCEL_MASK, &mask1, -1);
+    gtk_tree_model_get (model, i2, COL_ACCEL_KEY, &key2, COL_ACCEL_MASK, &mask2, -1);
+
+    if (mask1<mask2)
+        return -1;
+
+    if (mask1>mask2)
+        return 1;
+
+    return key1 - key2;
+}
+
+
+inline GtkTreeModel *create_and_fill_model (GnomeCmdUserActions &user_actions)
+{
+    GtkListStore *store = gtk_list_store_new (NUM_COLUMNS,
+                                              G_TYPE_STRING,            //  COL_SHORTCUT               // FIXME: temporarily, to be removed
+                                              G_TYPE_UINT,              //  COL_ACCEL_KEY
+                                              GDK_TYPE_MODIFIER_TYPE,   //  COL_ACCEL_MASK
+                                              G_TYPE_STRING,            //  COL_ACTION
+                                              G_TYPE_CLOSURE,           //  COL_ACCEL_CLOSURE
+                                              G_TYPE_STRING);           //  COL_OPTION
+
+    GtkTreeIter iter;
+
+    for (GnomeCmdUserActions::const_iterator i=user_actions.begin(); i!=user_actions.end(); ++i)
+         if (!ascii_isupper (*i))                                       // ignore lowercase keys as they duplicate uppercase ones
+         {
+             gtk_list_store_append (store, &iter);
+             gtk_list_store_set (store, &iter,
+                                 COL_SHORTCUT, user_actions.key(i),     // FIXME: temporarily, to be removed
+                                 COL_ACCEL_KEY, i->first.keyval,
+                                 COL_ACCEL_MASK, i->first.state,
+                                 COL_ACTION, user_actions.description(i),
+                                 COL_OPTION, user_actions.options(i),
+                                 -1);
+         }
+
+    GtkTreeSortable *sortable = GTK_TREE_SORTABLE (store);
+
+    gtk_tree_sortable_set_sort_func (sortable, SORTID_ACCEL, sort_by_accel, NULL, NULL);
+    gtk_tree_sortable_set_sort_func (sortable, SORTID_ACTION, sort_by_col, GUINT_TO_POINTER (COL_ACTION), NULL);
+    gtk_tree_sortable_set_sort_func (sortable, SORTID_OPTION, sort_by_col, GUINT_TO_POINTER (COL_OPTION), NULL);
+
+    gtk_tree_sortable_set_sort_column_id (sortable, SORTID_ACTION, GTK_SORT_ASCENDING);   // set initial sort order
+
+    return GTK_TREE_MODEL (store);
+}
+
+
+inline gboolean conflict_confirm (GtkWidget *view, const gchar *action, guint accel_key, GdkModifierType accel_mask)
+{
+    gchar *accel_string = gtk_accelerator_get_label (accel_key, accel_mask);
+
+    GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+                                             (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT),
+                                             GTK_MESSAGE_WARNING,
+                                             GTK_BUTTONS_NONE,
+                                             _("Shortcut \"%s\" is already taken by \"%s\"."),
+                                             accel_string, action);
+    gtk_dialog_add_buttons (GTK_DIALOG (dlg), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                              _("_Reassign shortcut"), GTK_RESPONSE_OK,
+                                              NULL);
+    gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_CANCEL);
+    gtk_window_set_title (GTK_WINDOW (dlg), _("Conflicting Shortcuts"));
+    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("Reassigning the shortcut will cause it "
+                                                                          "to be removed from \"%s\"."), action);
+    gtk_widget_show_all (dlg);
+    gint response = gtk_dialog_run (GTK_DIALOG (dlg));
+
+    gtk_widget_destroy (dlg);
+
+    g_free (accel_string);
+
+    return response==GTK_RESPONSE_OK;
+}
+
+
+inline gboolean equal_accel (GtkTreeModel *model, GtkTreeIter *i, guint key, GdkModifierType mask)
+{
+    guint accel_key  = 0;
+    GdkModifierType accel_mask = (GdkModifierType) 0;
+
+    gtk_tree_model_get (model, i,
+                        COL_ACCEL_KEY, &accel_key,
+                        COL_ACCEL_MASK, &accel_mask,
+                        -1);
+
+    return accel_key==key && accel_mask==mask;
+}
+
+
+inline gboolean find_accel (GtkTreeModel *model, GtkTreeIter *i, guint key, GdkModifierType mask)
+{
+    gboolean valid_iter;
+
+    for (valid_iter=gtk_tree_model_get_iter_first (model, i); valid_iter; valid_iter=gtk_tree_model_iter_next (model, i))
+        if (equal_accel (model, i, key, mask))
+            return TRUE;
+
+    return FALSE;
+}
+
+
+inline void set_accel (GtkTreeModel *model, GtkTreePath *path, guint accel_key, GdkModifierType accel_mask)
+{
+    GtkTreeIter iter;
+
+    if (gtk_tree_model_get_iter (model, &iter, path))
+        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                            COL_ACCEL_KEY, accel_key,
+                            COL_ACCEL_MASK, accel_mask,
+                            -1);
+}
+
+
+static void accel_edited_callback (GtkCellRendererAccel *accel, const char *path_string, guint accel_key, GdkModifierType accel_mask, guint hardware_keycode, GtkWidget *view)
+{
+    DEBUG('a', "Key event:  %s (%#x)\n", key2str(accel_mask,accel_key).c_str(), accel_key);
+
+    if (!accel_key)
+        gnome_cmd_show_message (NULL, _("Invalid shortcut."));
+    else
+    {
+        GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+        GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+        GtkTreeIter iter;
+
+        // do nothing if accelerators haven't changed...
+        if (gtk_tree_model_get_iter (model, &iter, path) && equal_accel (model, &iter, accel_key, accel_mask))
+            return;
+
+        if (!find_accel (model, &iter, accel_key, accel_mask))                  //  store new values if there isn't any duplicate...
+            set_accel (model, path, accel_key, accel_mask);
+        else
+        {
+            gchar *action;
+
+            gtk_tree_model_get (model, &iter, COL_ACTION, &action, -1);         // ...otherwise retrieve conflicting action...
+
+            if (conflict_confirm (view, action, accel_key, accel_mask))         // ...and ask user for confirmation
+            {
+                set_accel (model, path, accel_key, accel_mask);
+                gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+            }
+
+            g_free (action);
+        }
+
+        gtk_tree_path_free (path);
+    }
+}
+
+
+static void cell_edited_callback (GtkCellRendererText *cell, gchar *path_string, gchar *new_text, GtkWidget *view)
+{
+    GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+    GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
+    GtkTreeIter iter;
+
+    if (gtk_tree_model_get_iter (model, &iter, path))
+        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                            COL_OPTION, new_text,
+                            -1);
+}
+
+
+static void remove_clicked_callback (GtkButton *button, GtkWidget *view)
+{
+    GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
+    GtkTreeIter iter;
+
+    if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+    {
+        GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+        gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+        gtk_tree_selection_select_iter (selection, &iter);
+    }
+}
+
+
+static void add_clicked_callback (GtkButton *button, GtkWidget *view)
+{
+    GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+    GtkTreeIter iter;
+
+    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+    gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+                        COL_ACTION, _("Do nothing"),                                                                    // FIXME: temporarily, use "no.action" -> _("Do nothing")
+                        -1);
+
+    GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
+    gtk_widget_grab_focus (view);
+    gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, gtk_tree_view_get_column (GTK_TREE_VIEW (view),1), TRUE);    // FIXME: temporarily, change col idx 1 -> 0
+    gtk_tree_path_free(path);
+    // start editing accelerator
+}

Added: branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.h
==============================================================================
--- (empty file)
+++ branches/gcmd-1-3/src/gnome-cmd-key-shortcuts-dialog.h	Thu Mar 20 21:30:57 2008
@@ -0,0 +1,26 @@
+/*
+    GNOME Commander - A GNOME based file manager
+    Copyright (C) 2001-2006 Marcus Bjurman
+
+    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, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+#ifndef __GNOME_CMD_KEY_SHORTCUTS_DIALOG_H__
+#define __GNOME_CMD_KEY_SHORTCUTS_DIALOG_H__
+
+#include "gnome-cmd-user-actions.h"
+
+void gnome_cmd_key_shortcuts_dialog_new (GnomeCmdUserActions &user_actions);
+
+#endif // __GNOME_CMD_KEY_SHORTCUTS_DIALOG_H__

Modified: branches/gcmd-1-3/src/gnome-cmd-main-menu.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-main-menu.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-main-menu.cc	Thu Mar 20 21:30:57 2008
@@ -701,8 +701,14 @@
             GNOME_APP_PIXMAP_STOCK, GTK_STOCK_PREFERENCES,
             NULL
         },
-    {
-            MENU_TYPE_ITEM, _("Edit _MIME Types..."), "", NULL,
+        {
+            MENU_TYPE_ITEM, _("_Keyboard Shortcuts..."), "", NULL,
+            (gpointer) options_edit_shortcuts, NULL,
+            GNOME_APP_PIXMAP_STOCK, GTK_STOCK_ITALIC,
+            NULL
+        },
+        {
+            MENU_TYPE_ITEM, _("_MIME Types..."), "", NULL,
             (gpointer) options_edit_mime_types, NULL,
             GNOME_APP_PIXMAP_NONE, 0,
             NULL

Modified: branches/gcmd-1-3/src/gnome-cmd-user-actions.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-user-actions.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-user-actions.cc	Thu Mar 20 21:30:57 2008
@@ -38,6 +38,7 @@
 #include "gnome-cmd-prepare-move-dialog.h"
 #include "gnome-cmd-python-plugin.h"
 #include "gnome-cmd-search-dialog.h"
+#include "gnome-cmd-key-shortcuts-dialog.h"
 #include "gnome-cmd-user-actions.h"
 #include "plugin_manager.h"
 #include "cap.h"
@@ -175,6 +176,7 @@
                        {no_action, "no.action", NN_("Do nothing")},
                        {options_edit, "options.edit", NN_("Options")},
                        {options_edit_mime_types, "options.edit_mime_types", NN_("MIME types")},
+                       {options_edit_shortcuts, "options.shortcuts", NN_("Keyboard shortcuts")},
                        {plugins_configure, "plugins.configure", NN_("Configure plugins")},
                        {plugins_execute_python, "plugins.execute_python", NN_("Execute python plugin")},
                        {view_back, "view.back", NN_("Go back one directory")},
@@ -1123,6 +1125,12 @@
 }
 
 
+void options_edit_shortcuts (GtkMenuItem *menuitem, gpointer not_used)
+{
+    gnome_cmd_key_shortcuts_dialog_new (gcmd_user_actions);
+}
+
+
 void options_edit_mime_types (GtkMenuItem *menuitem, gpointer not_used)
 {
     edit_mimetypes (NULL, FALSE);

Modified: branches/gcmd-1-3/src/gnome-cmd-user-actions.h
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-user-actions.h	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-user-actions.h	Thu Mar 20 21:30:57 2008
@@ -180,6 +180,8 @@
     const_iterator begin()                                                  {  return action.begin();                           }
     const_iterator end()                                                    {  return action.end();                             }
 
+    const gchar *key(const_iterator &i)                                     {  return key2str(*i).c_str();                      }       // FIXME: temporarily, to be removed
+    const gchar *name(const_iterator &i)                                    {  return action_func[i->second.func].c_str();      }       // FIXME: temporarily, to be removed
     const gchar *description(const_iterator &i)                             {  return _(action_name[i->second.func].c_str());   }
     const gchar *options(const_iterator &i)                                 {  return i->second.user_data.c_str();              }
 };
@@ -280,6 +282,7 @@
 /************** Options Menu **************/
 GNOME_CMD_USER_ACTION(options_edit);
 GNOME_CMD_USER_ACTION(options_edit_mime_types);
+GNOME_CMD_USER_ACTION(options_edit_shortcuts);
 
 /************** Connections Menu **************/
 GNOME_CMD_USER_ACTION(connections_open);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]