Save hotkeys to config
[clawsker.git] / clawsker
index 57356352cec6bd3f61c93dd2eed452f608b67109..0be22aa0703985c0f1f70d237cbf682e5438861c 100755 (executable)
--- a/clawsker
+++ b/clawsker
@@ -72,6 +72,7 @@ sub _ {
     tab_winpos => _('Windows'),
     tab_accounts => _('Accounts'),
     tab_plugins => _('Plugins'),
+    tab_hotkeys => _('Hotkeys'),
     tab_info => _('Info'),
 
     ab_frame => _('Addressbook'),
@@ -279,6 +280,10 @@ my $ACCOUNTRC = 'accountrc';
 # supported and available plugins lists
 my @PLUGINS = qw(AttRemover GPG ManageSieve Libravatar PerlPlugin);
 my @AVPLUGINS = ();
+# loaded hotkeys from load_menurc
+my $HOTKEYS;
+# current tree selection
+my $SELHOTKEY;
 # loaded icons
 my @APPICONS = ();
 
@@ -2120,6 +2125,119 @@ sub new_plugins_page() {
                 $frame{'PerlPlugin'});
 }
 
+use constant {
+    C_LABEL => 0,
+    C_HOTKEY => 1,
+    C_GROUP => 2,
+    C_ACCEL => 3,
+    C_BCOLOR => 4,
+    # cell backgrounds
+    BG_LIGHTER => '#ffffff',
+    BG_DARKER => '#eeeeee'
+};
+
+sub new_hotkeys_list_label {
+    my $renderer = Gtk2::CellRendererText->new ();
+    $renderer->set_property('alignment' => 'left');
+    $renderer->set_property('editable' => FALSE);
+    $renderer->set_property('size-points' => 8);
+    $renderer->set_property('size-set' => TRUE);
+    return $renderer;
+}
+
+sub new_hotkeys_list_hotkey {
+    my $renderer = Gtk2::CellRendererAccel->new ();
+    $renderer->set_property ('accel-mode' => 'gtk');
+    $renderer->set_property ('editable' => TRUE);
+    $renderer->signal_connect ('accel-edited' => sub {
+        my ($w, $path, $key, $mods, $keycode) = @_;
+        my $accel = Gtk2::Accelerator->name ($key, $mods);
+        my ($model, $iter) = $SELHOTKEY->get_selected ();
+        $model->set($iter, C_HOTKEY, "\"$accel\"");
+        my $gkey = $model->get_value ($iter, C_GROUP);
+        my $akey = $model->get_value ($iter, C_ACCEL);
+        $HOTKEYS->{$gkey}->{$akey}->{'key'} = "\"$accel\"";
+    });
+    $renderer->signal_connect ('accel-cleared' => sub {
+        my ($w, $path) = @_;
+        my ($model, $iter) = $SELHOTKEY->get_selected ();
+        $model->set($iter, C_HOTKEY, "\"\"");
+        my $gkey = $model->get_value ($iter, C_GROUP);
+        my $akey = $model->get_value ($iter, C_ACCEL);
+        $HOTKEYS->{$gkey}->{$akey}->{'key'} = "\"\"";
+    });
+    return $renderer;
+}
+
+sub new_hotkeys_list {
+    my ($gkey, $group) = @_;
+    my $store = Gtk2::ListStore->new(
+        qw/Glib::String Glib::String Glib::String Glib::String Glib::String/);
+    my $even = FALSE;
+    foreach my $akey (sort keys %$group) {
+        my $iter = $store->append ();
+        my $hotkey = $group->{$akey}->{'key'};
+        my $label = $akey;
+        $label =~ s/[<>]//g; # <rrsyl> and <IMAPFolder> !?
+        my $bgcol = $even ? BG_DARKER: BG_LIGHTER;
+        $store->set ($iter, C_LABEL, $label, C_HOTKEY, $hotkey,
+            C_GROUP, $gkey, C_ACCEL, $akey, C_BCOLOR, $bgcol);
+        $even = not $even;
+    }
+    my $treeview = Gtk2::TreeView->new_with_model ($store);
+    # labels column
+    $treeview->insert_column_with_data_func (
+        0, _("Menu path"), new_hotkeys_list_label (),
+        sub {
+            my ($col, $renderer, $model, $iter, $data) = @_;
+            $renderer->set_property (
+                'text' => $model->get_value ($iter, C_LABEL));
+            $renderer->set_property (
+                'background' => $model->get_value ($iter, C_BCOLOR));
+        }
+    );
+    # hotkeys column
+    $treeview->insert_column_with_data_func (
+        1, _('Hotkey'), new_hotkeys_list_hotkey (),
+        sub {
+            my ($col, $renderer, $model, $iter, $data) = @_;
+            my $hkey = $model->get_value ($iter, C_HOTKEY);
+            $hkey =~ s/\"//g;
+            my ($acckey, $accmod) = Gtk2::Accelerator->parse ($hkey);
+            $renderer->set_property ('accel-key' => $acckey);
+            $renderer->set_property ('accel-mods' => $accmod);
+            $renderer->set_property (
+                'background' => $model->get_value ($iter, C_BCOLOR));
+        }
+    );
+    # callback for saving current selection
+    my $selection = $treeview->get_selection ();
+    $selection->signal_connect ('changed' => sub { $SELHOTKEY = shift });
+    return $treeview;
+}
+
+sub new_hotkeys_page() {
+    my $swin = Gtk2::ScrolledWindow->new ();
+    my $vbox = Gtk2::VBox->new (FALSE, 5);
+    foreach my $gkey (sort keys %$HOTKEYS) {
+        my $group = $HOTKEYS->{$gkey};
+        # group title
+        my $glabel = Gtk2::Label->new ('<b>' . $gkey . '</b>');
+        $glabel->set_use_markup (TRUE);
+        $glabel->set_alignment (0, 0.5);
+        $glabel->set_padding (5, 1);
+        $vbox->pack_start ($glabel, FALSE, FALSE, 0);
+        # group key list
+        my $keylist = new_hotkeys_list ($gkey, $group);
+        $vbox->pack_start ($keylist, FALSE, FALSE, 0);
+    }
+    $swin->set_border_width (5);
+    $swin->set_shadow_type ('none');
+    $swin->set_policy ('automatic', 'always');
+    $swin->add_with_viewport ($vbox);
+    return $swin;
+}
+
 sub new_info_page() {
     my $t0 = Gtk2::Table->new (7, 2, FALSE);
     my $v = get_toolkit_versions ();
@@ -2375,22 +2493,44 @@ sub load_menurc {
     my $line = 0;
     while (<RCF>) {
         chomp;
-        ++$line;
         if (/^; \(gtk_accel_path "<([A-Za-z]+)>([^"]+)" ([^\)]+)\)$/) {
-            my %data = ('key' => $3, 'enabled' => FALSE);
+            my %data = ('key' => $3, 'enabled' => FALSE, 'line' => $line);
             $groups{$1}{$2} = \%data;
             # say "group -> $1 | path -> $2 | key -> $3";
-        }
-        if (/^\(gtk_accel_path "<([A-Za-z]+)>([^"]+)" ([^\)]+)\)$/) {
-            my %data = ('key' => $3, 'enabled' => TRUE);
+        } elsif (/^\(gtk_accel_path "<([A-Za-z]+)>([^"]+)" ([^\)]+)\)$/) {
+            my %data = ('key' => $3, 'enabled' => TRUE, 'line' => $line);
             $groups{$1}{$2} = \%data;
             # say "group -> $1 | path -> $2 | key -> $3";
         }
+        ++$line;
     }
     close (RCF);
     return \%groups;
 }
 
+sub save_menurc {
+    my ($rc, $groups) = @_;
+    my @lines = ();
+    foreach my $gkey (keys %$groups) {
+        my $group = $groups->{$gkey};
+        foreach my $akey (keys %$group) {
+            my $data = $group->{$akey};
+            my $key = $data->{'key'};
+            my $line = $data->{'line'};
+            $lines[$line] = ($data->{'enabled'})? '': '; ';
+            $lines[$line] .= '(gtk_accel_path "<'
+                    . $gkey . '>' . $akey . '" ' . $key . ')';
+        }
+    }
+    open (RCF, '>:utf8', $rc)
+        or die _("Error: opening '{file}' for writing", file => $rc) . ": $!\n";
+    say RCF '; claws-mail GtkAccelMap rc-file         -*- scheme -*-';
+    say RCF '; this file is an automated accelerator map dump';
+    say RCF ';';
+    foreach (@lines) { say RCF $_ if $_ }
+    close (RCF);
+}
+
 # load current status from disc
 sub load_rc_preferences {
     my $rc = get_rc_filename ();
@@ -2426,9 +2566,19 @@ sub load_ac_preferences {
     return TRUE;
 }
 
+sub load_hk_preferences {
+    my $rc = get_menurc_filename ();
+    return FALSE unless check_rc_file ($rc);
+    $HOTKEYS = load_menurc ($rc);
+    return TRUE;
+}
+
 sub load_preferences {
     return FALSE unless check_claws_not_running ();
-    return (load_rc_preferences () and load_ac_preferences ());
+    return (load_rc_preferences ()
+        and load_ac_preferences ()
+        and load_hk_preferences ()
+    );
 }
 
 # save current preferences to disc
@@ -2475,6 +2625,15 @@ sub save_ac_preferences {
     return TRUE;
 }
 
+sub save_hk_preferences {
+    my $rc = get_menurc_filename ();
+    log_message ("Saving hotkey preferences to $rc\n");
+    return FALSE unless check_rc_file ($rc);
+    return FALSE unless check_claws_not_running ();
+    save_menurc ($rc, $HOTKEYS);
+    return TRUE;
+}
+
 # create notebook
 sub new_notebook {
     my $nb = Gtk2::Notebook->new;
@@ -2486,6 +2645,7 @@ sub new_notebook {
     $nb->append_page (new_winpos_page (), $xl::s{tab_winpos});
     $nb->append_page (new_accounts_page (), $xl::s{tab_accounts});
     $nb->append_page (new_plugins_page (), $xl::s{tab_plugins});
+    $nb->append_page (new_hotkeys_page (), $xl::s{tab_hotkeys});
     $nb->append_page (new_info_page (), $xl::s{tab_info});
 
     return $nb;
@@ -2550,6 +2710,7 @@ sub new_button_box {
     $b_apply->signal_connect (clicked => sub {
         save_preferences ($parent);
         save_ac_preferences ($parent);
+        save_hk_preferences ($parent);
     });
     # $b_undo->signal_connect (clicked => sub { undo_current_changes });
     $b_about->signal_connect (clicked => sub { $adlg->run; $adlg->hide });