diff options
author | Jeffrey Stedfast <jeff@xamarin.com> | 2012-03-31 04:01:00 +0400 |
---|---|---|
committer | Jeffrey Stedfast <jeff@xamarin.com> | 2012-03-31 04:01:00 +0400 |
commit | f2ea3136862aa4712e6a4c56e71281aa7cba186f (patch) | |
tree | 89e961168f1fe3e1adf51be31aad335f3eecf6a4 | |
parent | 03b759a57317b15749138de4cb050d0233da1b1a (diff) |
[Ide] Warn user when he/she enters bad keybinding combo
Also revert KeyboardShortcut back into a struct to save space (soptimization ftw)
and fixed Mac keybinding menu strings to upper-case the character keys.
6 files changed, 137 insertions, 90 deletions
diff --git a/main/src/addins/MacPlatform/MacMainMenu.cs b/main/src/addins/MacPlatform/MacMainMenu.cs index 8d5fef4832..28697a9830 100644 --- a/main/src/addins/MacPlatform/MacMainMenu.cs +++ b/main/src/addins/MacPlatform/MacMainMenu.cs @@ -245,6 +245,8 @@ namespace MonoDevelop.MacIntegration System.Console.WriteLine("WARNING: Could not map key ({0})", key); return false; } + } else { + charCode = (ushort) char.ToUpper ((char) charCode); } } diff --git a/main/src/core/Mono.Texteditor/Mono.TextEditor/GtkWorkarounds.cs b/main/src/core/Mono.Texteditor/Mono.TextEditor/GtkWorkarounds.cs index 9a90d7af0b..589209d96d 100644 --- a/main/src/core/Mono.Texteditor/Mono.TextEditor/GtkWorkarounds.cs +++ b/main/src/core/Mono.Texteditor/Mono.TextEditor/GtkWorkarounds.cs @@ -746,20 +746,29 @@ namespace Mono.TextEditor static extern void gtksharp_container_override_forall (IntPtr gtype, ForallDelegate cb); } - public class KeyboardShortcut : IEquatable<KeyboardShortcut> + public struct KeyboardShortcut : IEquatable<KeyboardShortcut> { - public KeyboardShortcut (Gdk.Key key, Gdk.ModifierType mod) + public static readonly KeyboardShortcut Empty = new KeyboardShortcut ((Gdk.Key) 0, (Gdk.ModifierType) 0); + + Gdk.ModifierType modifier; + Gdk.Key key; + + public KeyboardShortcut (Gdk.Key key, Gdk.ModifierType modifier) { - Modifier = mod; - Key = key; + this.modifier = modifier; + this.key = key; } public Gdk.Key Key { - get; private set; + get { return key; } } public Gdk.ModifierType Modifier { - get; private set; + get { return modifier; } + } + + public bool IsEmpty { + get { return Key == (Gdk.Key) 0; } } public override bool Equals (object obj) diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/Command.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/Command.cs index 11b5fa93bd..5bac1ff279 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/Command.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/Command.cs @@ -42,6 +42,7 @@ namespace MonoDevelop.Components.Commands string description; IconId icon; string accelKey; + KeyBinding binding; string category; bool disabledVisible; internal string AccelPath; @@ -75,14 +76,30 @@ namespace MonoDevelop.Components.Commands public string AccelKey { get { return accelKey; } set { - string binding = accelKey; - accelKey = value == string.Empty ? null : value; + if (string.IsNullOrEmpty (value)) + value = null; - if (KeyBindingChanged != null && accelKey != binding) - KeyBindingChanged (this, new KeyBindingChangedEventArgs (this, binding)); + if (value == accelKey) + return; + + var oldKeyBinding = binding; + + if (value != null) + KeyBinding.TryParse (value, out binding); + else + binding = null; + + accelKey = value; + + if (KeyBindingChanged != null) + KeyBindingChanged (this, new KeyBindingChangedEventArgs (this, oldKeyBinding)); } } + public KeyBinding KeyBinding { + get { return binding; } + } + public bool DisabledVisible { get { return disabledVisible; } set { disabledVisible = value; } @@ -102,7 +119,7 @@ namespace MonoDevelop.Components.Commands } public class KeyBindingChangedEventArgs { - public KeyBindingChangedEventArgs (Command command, string oldKeyBinding) + public KeyBindingChangedEventArgs (Command command, KeyBinding oldKeyBinding) { OldKeyBinding = oldKeyBinding; Command = command; @@ -112,12 +129,12 @@ namespace MonoDevelop.Components.Commands get; private set; } - public string OldKeyBinding { + public KeyBinding OldKeyBinding { get; private set; } - public string NewKeyBinding { - get { return Command.AccelKey; } + public KeyBinding NewKeyBinding { + get { return Command.KeyBinding; } } } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs index 1f1aa85d2a..8dcfef6051 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/CommandManager.cs @@ -35,6 +35,7 @@ using System.Collections.Generic; using MonoDevelop.Components.Commands.ExtensionNodes; using Mono.TextEditor; using Mono.Addins; +using MonoDevelop.Core; namespace MonoDevelop.Components.Commands { @@ -47,6 +48,7 @@ namespace MonoDevelop.Components.Commands uint statusUpdateWait = 500; DateTime lastUserInteraction; KeyboardShortcut[] chords; + string chord; Dictionary<object,Command> cmds = new Dictionary<object,Command> (); Hashtable handlerInfo = new Hashtable (); @@ -251,6 +253,20 @@ namespace MonoDevelop.Components.Commands return cset; } + bool isEnabled = true; + + /// <summary> + /// Gets or sets a value indicating whether the command manager is enabled. When disabled, all commands are disabled. + /// </summary> + public bool IsEnabled { + get { + return isEnabled; + } + set { + isEnabled = value; + } + } + bool CanUseBinding (KeyboardShortcut[] chords, KeyboardShortcut[] accels, out KeyBinding binding) { if (chords != null) { @@ -265,11 +281,11 @@ namespace MonoDevelop.Components.Commands foreach (var accel in accels) { if (bindings.ChordExists (accel)) { // Chords take precedence over bindings with the same shortcut. - binding = new KeyBinding (null, accel); + binding = new KeyBinding (accel); continue; } - binding = new KeyBinding (null, accel); + binding = new KeyBinding (accel); if (bindings.BindingExists (binding)) return true; } @@ -280,19 +296,7 @@ namespace MonoDevelop.Components.Commands return false; } - bool isEnabled = true; - - /// <summary> - /// Gets or sets a value indicating whether the command manager is enabled. When disabled, all commands are disabled. - /// </summary> - public bool IsEnabled { - get { - return isEnabled; - } - set { - isEnabled = value; - } - } + public event EventHandler<KeyBindingFailedEventArgs> KeyBindingFailed; [GLib.ConnectBefore] void OnKeyPressed (object o, Gtk.KeyPressEventArgs e) @@ -318,13 +322,29 @@ namespace MonoDevelop.Components.Commands commands = bindings.Commands (binding); e.RetVal = true; chords = null; + chord = null; } else if (bindings.AnyChordExists (accels)) { + chord = KeyBindingManager.AccelLabelFromKey (e.Event); e.RetVal = true; chords = accels; return; + } else if (chords != null) { + // Note: The user has entered a valid chord but the accel was invalid. + if (KeyBindingFailed != null) { + string accel = KeyBindingManager.AccelLabelFromKey (e.Event); + + KeyBindingFailed (this, new KeyBindingFailedEventArgs (GettextCatalog.GetString ("The key combination ({0}, {1}) is not a command.", chord, accel))); + } + + e.RetVal = true; + chords = null; + chord = null; + return; } else { e.RetVal = false; chords = null; + chord = null; + NotifyKeyPressed (e); return; } @@ -2241,5 +2261,15 @@ namespace MonoDevelop.Components.Commands public Gdk.Key Key { get; internal set; } public Gdk.ModifierType Modifiers { get; internal set; } } + + public class KeyBindingFailedEventArgs : EventArgs + { + public string Message { get; private set; } + + public KeyBindingFailedEventArgs (string message) + { + Message = message; + } + } } diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/KeyBindingManager.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/KeyBindingManager.cs index 5fd3b43680..78c078b119 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/KeyBindingManager.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Commands/KeyBindingManager.cs @@ -213,6 +213,13 @@ namespace MonoDevelop.Components.Commands return accel + KeyToString (shortcuts[0].Key); } + public static string AccelLabelFromKey (Gdk.EventKey raw) + { + bool complete; + + return AccelLabelFromKey (raw, out complete); + } + static string AccelLabelFromKey (Gdk.Key key, Gdk.ModifierType modifier, out bool complete) { string accel = ModifierToString (modifier); @@ -395,14 +402,14 @@ namespace MonoDevelop.Components.Commands public static string BindingToDisplayLabel (KeyBinding binding, bool concise) { - string label = string.Empty; - - if (binding.Chord != null) - label += ModifierToDisplayLabel (binding.Chord.Modifier, concise) + KeyToDisplayLabel (binding.Chord.Key) + (isMac ? " " : "|"); + string label; - label += ModifierToDisplayLabel (binding.Accel.Modifier, concise) + KeyToDisplayLabel (binding.Accel.Key); + if (!binding.Chord.IsEmpty) + label = ModifierToDisplayLabel (binding.Chord.Modifier, concise) + KeyToDisplayLabel (binding.Chord.Key) + (isMac ? " " : "|"); + else + label = string.Empty; - return label; + return label + ModifierToDisplayLabel (binding.Accel.Modifier, concise) + KeyToDisplayLabel (binding.Accel.Key); } static string KeyToDisplayLabel (Gdk.Key key) @@ -489,6 +496,8 @@ namespace MonoDevelop.Components.Commands if ((mod = ModifierMask (str)) == Gdk.ModifierType.None) { if (str.Length > 1) key = (Gdk.Key) Gdk.Key.Parse (typeof (Gdk.Key), str); + else if (str[0] >= 'a' && str[0] <= 'z') + key = (Gdk.Key) str[0] - 32; else key = (Gdk.Key) str[0]; @@ -595,14 +604,14 @@ namespace MonoDevelop.Components.Commands if (ChordChanged (oldKeyBinding, newKeyBinding)) { // keep track of valid modes - if (oldKeyBinding != null && oldKeyBinding.Chord != null) { + if (oldKeyBinding != null && !oldKeyBinding.Chord.IsEmpty) { if ((refs = chords[oldKeyBinding.Chord] - 1) == 0) chords.Remove (oldKeyBinding.Chord); else chords[oldKeyBinding.Chord] = refs; } - if (newKeyBinding != null && newKeyBinding.Chord != null) { + if (newKeyBinding != null && !newKeyBinding.Chord.IsEmpty) { if (!chords.ContainsKey (newKeyBinding.Chord)) chords.Add (newKeyBinding.Chord, 1); else @@ -631,20 +640,6 @@ namespace MonoDevelop.Components.Commands } } - void SetBinding (Command command, string oldBinding, string newBinding) - { - KeyBinding oldKeyBinding; - KeyBinding newKeyBinding; - - if (!KeyBinding.TryParse (oldBinding, out oldKeyBinding)) - oldKeyBinding = null; - - if (!KeyBinding.TryParse (newBinding, out newKeyBinding)) - newKeyBinding = null; - - SetBinding (command, oldKeyBinding, newKeyBinding); - } - void OnKeyBindingChanged (object o, KeyBindingChangedEventArgs args) { SetBinding (args.Command, args.OldKeyBinding, args.NewKeyBinding); @@ -662,7 +657,7 @@ namespace MonoDevelop.Components.Commands return; } - SetBinding (command, null, command.AccelKey); + SetBinding (command, null, command.KeyBinding); command.KeyBindingChanged += OnKeyBindingChanged; commands.Add (command); } @@ -680,23 +675,19 @@ namespace MonoDevelop.Components.Commands command.KeyBindingChanged -= OnKeyBindingChanged; commands.Remove (command); - if (string.IsNullOrEmpty (command.AccelKey)) - return; - - KeyBinding binding; - if (!KeyBinding.TryParse (command.AccelKey, out binding)) + if (command.KeyBinding == null) return; - list = bindings[binding]; + list = bindings[command.KeyBinding]; list.Remove (command); if (list.Count == 0) - bindings.Remove (binding); + bindings.Remove (command.KeyBinding); - if (binding.Chord != null && chords.ContainsKey (binding.Chord)) { - if ((refs = chords[binding.Chord] - 1) == 0) - chords.Remove (binding.Chord); + if (!command.KeyBinding.Chord.IsEmpty && chords.ContainsKey (command.KeyBinding.Chord)) { + if ((refs = chords[command.KeyBinding.Chord] - 1) == 0) + chords.Remove (command.KeyBinding.Chord); else - chords[binding.Chord] = refs; + chords[command.KeyBinding.Chord] = refs; } } @@ -705,7 +696,7 @@ namespace MonoDevelop.Components.Commands /// public List<Command> Commands (KeyBinding binding) { - if (!BindingExists (binding)) + if (binding == null || !BindingExists (binding)) return null; return bindings[binding]; @@ -857,7 +848,7 @@ namespace MonoDevelop.Components.Commands #endregion } - public class KeyBinding + public class KeyBinding : IEquatable<KeyBinding> { public KeyBinding (KeyboardShortcut chord, KeyboardShortcut accel) { @@ -865,6 +856,12 @@ namespace MonoDevelop.Components.Commands Accel = accel; } + public KeyBinding (KeyboardShortcut accel) + { + Chord = KeyboardShortcut.Empty; + Accel = accel; + } + public static bool TryParse (string str, out KeyBinding binding) { Gdk.ModifierType chordModifier; @@ -877,13 +874,8 @@ namespace MonoDevelop.Components.Commands return false; } + KeyboardShortcut chord = new KeyboardShortcut ((Gdk.Key) chordKey, chordModifier); KeyboardShortcut accel = new KeyboardShortcut ((Gdk.Key) key, modifier); - KeyboardShortcut chord; - - if (chordKey != 0) - chord = new KeyboardShortcut ((Gdk.Key) chordKey, chordModifier); - else - chord = null; binding = new KeyBinding (chord, accel); @@ -900,35 +892,26 @@ namespace MonoDevelop.Components.Commands public override int GetHashCode () { - int code = Accel.GetHashCode (); - - if (Chord != null) - return Chord.GetHashCode () ^ code; - - return code; + return Chord.GetHashCode () ^ Accel.GetHashCode (); } public override bool Equals (object obj) { - KeyBinding binding = obj as KeyBinding; - - if (binding == null) - return false; - - if (Chord == null) - return binding.Chord == null && Accel.Equals (binding.Accel); - - if (binding.Chord == null) - return false; - - return Chord.Equals (binding.Chord) && Accel.Equals (binding.Accel); + return obj is KeyBinding && Equals ((KeyBinding) obj); } + #region IEquatable[KeyBinding] implementation + public bool Equals (KeyBinding other) + { + return Chord.Equals (other.Chord) && Accel.Equals (other.Accel); + } + #endregion + public override string ToString () { string chord; - if (Chord != null) + if (!Chord.IsEmpty) chord = KeyBindingManager.AccelLabelFromKey (Chord.Key, Chord.Modifier) + "|"; else chord = string.Empty; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs index 2b44b55cfd..14aeb99283 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide/Ide.cs @@ -151,6 +151,7 @@ namespace MonoDevelop.Ide commandService.CommandTargetScanStarted += CommandServiceCommandTargetScanStarted; commandService.CommandTargetScanFinished += CommandServiceCommandTargetScanFinished; + commandService.KeyBindingFailed += KeyBindingFailed; KeyBindingService.LoadBindingsFromExtensionPath ("/MonoDevelop/Ide/KeyBindingSchemes"); KeyBindingService.LoadCurrentBindings ("MD2"); @@ -279,6 +280,11 @@ namespace MonoDevelop.Ide }; AutoTestService.NotifyEvent ("MonoDevelop.Ide.IdeStart"); } + + static void KeyBindingFailed (object sender, KeyBindingFailedEventArgs e) + { + Ide.IdeApp.Workbench.StatusBar.ShowMessage (e.Message); + } //this method is MIT/X11, 2009, Michael Hutchinson / (c) Novell public static void OpenFiles (IEnumerable<FileOpenInformation> files) |