From 41266b43597e2c7043a32b423aaf1301dc5bdac2 Mon Sep 17 00:00:00 2001 From: Sergej Andrejev Date: Tue, 11 Aug 2009 14:12:20 +0000 Subject: [PATCH] More documentation and code refactoring git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/shortcuts@4646 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Editing/CaretNavigationCommandHandler.cs | 7 +- .../Editing/EditingCommandHandler.cs | 7 +- .../Editing/TextAreaDefaultInputHandlers.cs | 10 +- .../Project/Src/Gui/Workbench/WpfWorkbench.cs | 4 +- .../ICSharpCode.Core.Presentation.csproj | 1 + .../Input/GestureCompareMode.cs | 38 ++ .../Input/InputGestureCollectionExtensions.cs | 26 +- .../Input/InputGestureExtensions.cs | 286 +++++------ .../Input/MultiKeyBinding.cs | 46 +- .../Input/MultiKeyGesture.cs | 222 ++++---- .../Input/MultiKeyGestureConverter.cs | 166 +++--- .../Input/ObservableInputGestureCollection.cs | 45 +- .../Input/PartialKeyGesture.cs | 482 +++++++++--------- .../Input/PartialKeyGestureConverter.cs | 226 ++++---- 14 files changed, 802 insertions(+), 764 deletions(-) create mode 100644 src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs index ccfee77629f..7de7c5b34df 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs @@ -73,8 +73,13 @@ static void AddCommandBinding(string routedCommandName, CanExecuteRoutedEventHan SDCommandManager.RegisterCommandBindingInfo(commandBinding); } - static CaretNavigationCommandHandler() + private static bool bindingsRegistered; + + public static void RegisterBindings() { + if(bindingsRegistered) return; + bindingsRegistered = true; + ClassWideBindingGroup = new BindingGroup("CaretNavigationCommandHandler"); classWideInputBindingCategory = new InputBindingCategory("/CaretNavigation", "Caret navigation commands"); SDCommandManager.RegisterInputBindingCategory(classWideInputBindingCategory); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs index bd791d3c4fc..25d013eabb5 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs @@ -82,8 +82,13 @@ static void AddCommandBinding(string routedCommandName, CanExecuteRoutedEventHan SDCommandManager.RegisterCommandBindingInfo(commandBinding); } - static EditingCommandHandler() + private static bool bindingsRegistered; + + public static void RegisterBindings() { + if(bindingsRegistered) return; + bindingsRegistered = true; + ClassWideBindingGroup = new BindingGroup("EditingCommandHandler"); classWideInputBindingCategory = new InputBindingCategory("/EditingCommands", "Editing commands"); SDCommandManager.RegisterInputBindingCategory(classWideInputBindingCategory); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs index 21ccf76f5f8..890ed160f0f 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs @@ -38,12 +38,20 @@ public static BindingGroup ClassWideBindingGroup get; private set; } - static TextAreaDefaultInputHandler() + private static bool bindingsRegistered; + + public static void RegisterBindings() { + if(bindingsRegistered) return; + bindingsRegistered = true; + ClassWideBindingGroup = new BindingGroup("TextAreaDefaultInputHandler"); AddCommandBinding("ApplicationCommands.Undo", CanExecuteUndo, ExecuteUndo); AddCommandBinding("ApplicationCommands.Redo", CanExecuteRedo, ExecuteRedo); + + CaretNavigationCommandHandler.RegisterBindings(); + EditingCommandHandler.RegisterBindings(); } static void AddCommandBinding(string routedCommandName, CanExecuteRoutedEventHandler canExecuteHandler, ExecutedRoutedEventHandler executedHandler) diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index df134e728f5..3fedb2c254a 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -76,7 +76,6 @@ protected override void OnSourceInitialized(EventArgs e) public void Initialize() { - // Use shortened assembly qualified name to not lose user defined gestures // when sharp develop is updated SDCommandManager.DefaultOwnerTypeName = SDCommandManager.GetShortAssemblyQualifiedName(GetType()); @@ -101,6 +100,9 @@ public void Initialize() } } + // Hack: Later on bindings should be created from *.addin file + ICSharpCode.AvalonEdit.Editing.TextAreaDefaultInputHandler.RegisterBindings(); + mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath); toolBars = ToolBarService.CreateToolBars(this, "/SharpDevelop/Workbench/ToolBar"); diff --git a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj index 064c8e0c461..d7263a15e0c 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj +++ b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj @@ -90,6 +90,7 @@ + diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs b/src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs new file mode 100644 index 00000000000..91e3c8f89d0 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/Input/GestureCompareMode.cs @@ -0,0 +1,38 @@ +using System; +using System.Windows.Input; + +namespace ICSharpCode.Core.Presentation +{ + public enum GestureCompareMode + { + /// + /// Match is successfull when all chrods from both instance of match + /// or all gestures in both instance of match + /// + ExactlyMatches, + + /// + /// Match is successfull when two instance of ar conflicting. + /// + /// Either one or another instance starts with the same chors as other one + /// + Conflicting, + + /// + /// Match is successfull when template partly matches compared . + /// Template is found in any place within matched gesture + /// + PartlyMatches, + + + /// + /// Match is successfull when examined starts with the same keys as template + /// + StartsWith, + + /// + /// Match is successfull when examined starts with the same complite chords as template + /// + StartsWithFullChords, + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs b/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs index 56ed5f97ba5..aa579f817e3 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureCollectionExtensions.cs @@ -6,10 +6,18 @@ namespace ICSharpCode.Core.Presentation { /// - /// Description of InputGestureCollectionExtensions. + /// Contains utility methods for work with /// public static class InputGestureCollectionExtensions { + /// + /// Determines whether any item from first is qualified as template for + /// any item from second when examining using specific + /// + /// Collection of examined templates + /// Collection of examined gestures + /// Additional comparing rules. See for details + /// true if first collection contains item which can be qualified as template for any item from second collection; otherwise false public static bool ContainsTemplateForAny(this InputGestureCollection inputGestureTemplateCollection, InputGestureCollection testedInputGestureCollection, GestureCompareMode mode) { if((inputGestureTemplateCollection == null || inputGestureTemplateCollection.Count == 0) && (testedInputGestureCollection == null || testedInputGestureCollection.Count == 0)) { return true; @@ -23,7 +31,14 @@ public static class InputGestureCollectionExtensions return false; } - + /// + /// Determines whether any item from first is qualified as template for + /// provided when examining using specific + /// + /// Collection of examined templates + /// Examined Gesture + /// Additional comparing rules. See for details + /// true if collection contains template which match provided ; otherwise false public static bool ContainsTemplateFor(this InputGestureCollection inputGestureTemplateCollection, InputGesture testedGesture, GestureCompareMode mode) { foreach (InputGesture template in inputGestureTemplateCollection) { if (template.IsTemplateFor(testedGesture, mode)) { @@ -35,9 +50,12 @@ public static class InputGestureCollectionExtensions } /// - /// Sort key gestures within input gesture collection by length and type - /// Shorter gestures should be first so they could be matched first. + /// Sort bindings in according to number of chords each + /// contains. + /// + /// Bindings associated with gestures having more chords should be on top. /// + /// public static void SortByChords(this InputBindingCollection inputGestureCollection) { ArrayList.Adapter(inputGestureCollection).Sort(new ChordsCountComparer()); diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs b/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs index 8d9ff5aabb9..1a442ab8cd6 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/InputGestureExtensions.cs @@ -1,174 +1,134 @@ -/* - * Created by SharpDevelop. - * User: Administrator - * Date: 6/26/2009 - * Time: 1:13 AM - * - * To change this template use Tools | Options | Coding | Edit Standard Headers. - */ using System; using System.Windows.Input; using System.Collections.Generic; namespace ICSharpCode.Core.Presentation -{ - public enum GestureCompareMode - { - ExactlyMatches, - - Conflicting, - - /// - /// Match is successfull if template gesture partly matches compared geture. - /// Template is found in any place within matched gesture - /// - PartlyMatches, - - PartlyMatchesFullChords, - - - /// - /// match is successfull if matched gesture starts with provided template - /// - StartsWith, - - StartsWithFullChords, - } - +{ /// - /// Description of InputGestureExtensions. + /// Contains utility methods for work with /// public static class InputGestureExtensions { - - /// - /// Returns true whether compared gesture matches input gesture template - /// - /// Input gesture template - /// Compared input gesture - /// Match mode - /// Returns true if template matches compared geture - public static bool IsTemplateFor(this InputGesture inputGestureTemplate, InputGesture inputGesture, GestureCompareMode mode) - { - if(mode == GestureCompareMode.Conflicting) { - return - inputGestureTemplate.IsTemplateFor(inputGesture, GestureCompareMode.StartsWithFullChords) - || inputGesture.IsTemplateFor(inputGestureTemplate, GestureCompareMode.StartsWithFullChords); - } - - var multiKeyGesture = inputGesture as MultiKeyGesture; - var multiKeyGestureTemplate = inputGestureTemplate as MultiKeyGesture; - var partialKeyGesture = inputGesture as PartialKeyGesture; - var partialKeyGestureTemplate = inputGestureTemplate as PartialKeyGesture; - var keyGesture = inputGesture as KeyGesture; - var keyGestureTemplate = inputGestureTemplate as KeyGesture; - - // Create partial key gestures from key gestures - if(multiKeyGesture == null && partialKeyGesture == null && keyGesture != null) { - partialKeyGesture = new PartialKeyGesture(keyGesture); - } - - if(multiKeyGestureTemplate == null && partialKeyGestureTemplate == null && keyGestureTemplate != null) { - partialKeyGestureTemplate = new PartialKeyGesture(keyGestureTemplate); - } - - // Create multi key gestures from gestures - if(multiKeyGesture == null && partialKeyGesture != null) { - multiKeyGesture = new MultiKeyGesture(new [] { partialKeyGesture }); - } - - if(multiKeyGestureTemplate == null && partialKeyGestureTemplate != null) { - multiKeyGestureTemplate = new MultiKeyGesture(new [] { partialKeyGestureTemplate }); - } - - if(multiKeyGesture == null - || multiKeyGestureTemplate == null - || multiKeyGesture.Chords == null - || multiKeyGestureTemplate.Chords == null - || multiKeyGestureTemplate.Chords.Count == 0 - || multiKeyGesture.Chords.Count == 0 - || (mode == GestureCompareMode.ExactlyMatches && multiKeyGestureTemplate.Chords.Count != multiKeyGesture.Chords.Count)) { - return false; - } - - // Stores N previous chords - var previousChords = new LinkedList(); - - // Search whether chord sequece matches template sequenc in any place - foreach (PartialKeyGesture chord in multiKeyGesture.Chords) - { - // Accumulates previous chords - previousChords.AddLast(chord); - if (previousChords.Count > multiKeyGestureTemplate.Chords.Count) - { - previousChords.RemoveFirst(); - } - - // Only start comparing with template when needed amount of previous chords where collected - if (previousChords.Count == multiKeyGestureTemplate.Chords.Count) - { - var multiKeyGestureTemplateEnumerator = multiKeyGestureTemplate.Chords.GetEnumerator(); - var previousChordsEnumerator = previousChords.GetEnumerator(); - - multiKeyGestureTemplateEnumerator.Reset(); - - // Compare two chord sequences in a loop - var multiKeyGesturesMatch = true; - - var i = 0; - while (previousChordsEnumerator.MoveNext() && multiKeyGestureTemplateEnumerator.MoveNext()) - { - var template = multiKeyGestureTemplateEnumerator.Current; - var gesture = previousChordsEnumerator.Current; - - if (((mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.PartlyMatches) && i == previousChords.Count - 1) - || (mode == GestureCompareMode.PartlyMatches && i == 0)) { - - if(!(template.Modifiers == (gesture.Modifiers & template.Modifiers) && (template.Key == Key.None || template.Key == gesture.Key))) { - multiKeyGesturesMatch = false; - break; - } - } else if (template.Modifiers != gesture.Modifiers || template.Key != gesture.Key) { - multiKeyGesturesMatch = false; - break; - } - - i++; - } - - if(multiKeyGesturesMatch) - { - return true; - } - - if (mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.StartsWithFullChords) - { - break; - } - } - } - - return false; - } - - - /// - /// Determines whether this instance of matches any of provided templates - /// - /// This input gesture - /// Collection of input gestures templates which (at least one of them) should match this input gesture to return true - /// Matching mode - /// True if this gsture matches templates collection, otherwise false - public static bool IsTemplateForAny(this InputGesture thisGesture, InputGestureCollection inputGestureTemplateCollection, GestureCompareMode mode) - { - foreach (InputGesture gesture in inputGestureTemplateCollection) { - if (thisGesture.IsTemplateFor(gesture, mode)) - { - return true; - } - } - - return false; - } + /// + /// Determines whether provided is qualified as template for + /// another instance of when examining using specific + /// + /// Examined input gesture template + /// Examined input gesture + /// Additional comparing rules. See for details + /// true if template matches compared geture; otherwise false + public static bool IsTemplateFor(this InputGesture inputGestureTemplate, InputGesture inputGesture, GestureCompareMode mode) + { + if(mode == GestureCompareMode.Conflicting) { + return inputGestureTemplate.IsTemplateFor(inputGesture, GestureCompareMode.StartsWithFullChords) || inputGesture.IsTemplateFor(inputGestureTemplate, GestureCompareMode.StartsWithFullChords); + } + + var multiKeyGesture = inputGesture as MultiKeyGesture; + var multiKeyGestureTemplate = inputGestureTemplate as MultiKeyGesture; + var partialKeyGesture = inputGesture as PartialKeyGesture; + var partialKeyGestureTemplate = inputGestureTemplate as PartialKeyGesture; + var keyGesture = inputGesture as KeyGesture; + var keyGestureTemplate = inputGestureTemplate as KeyGesture; + + // Create partial key gestures from key gestures + if(multiKeyGesture == null && partialKeyGesture == null && keyGesture != null) { + partialKeyGesture = new PartialKeyGesture(keyGesture); + } + + if(multiKeyGestureTemplate == null && partialKeyGestureTemplate == null && keyGestureTemplate != null) { + partialKeyGestureTemplate = new PartialKeyGesture(keyGestureTemplate); + } + + // Create multi key gestures from gestures + if(multiKeyGesture == null && partialKeyGesture != null) { + multiKeyGesture = new MultiKeyGesture(new [] { partialKeyGesture }); + } + + if(multiKeyGestureTemplate == null && partialKeyGestureTemplate != null) { + multiKeyGestureTemplate = new MultiKeyGesture(new [] { partialKeyGestureTemplate }); + } + + if(multiKeyGesture == null + || multiKeyGestureTemplate == null + || multiKeyGesture.Chords == null + || multiKeyGestureTemplate.Chords == null + || multiKeyGestureTemplate.Chords.Count == 0 + || multiKeyGesture.Chords.Count == 0 + || (mode == GestureCompareMode.ExactlyMatches && multiKeyGestureTemplate.Chords.Count != multiKeyGesture.Chords.Count)) { + return false; + } + + // Stores N previous chords + var previousChords = new LinkedList(); + + // Search whether chord sequece matches template sequenc in any place + foreach (PartialKeyGesture chord in multiKeyGesture.Chords) { + // Accumulates previous chords + previousChords.AddLast(chord); + if (previousChords.Count > multiKeyGestureTemplate.Chords.Count) { + previousChords.RemoveFirst(); + } + + // Only start comparing with template when needed amount of previous chords where collected + if (previousChords.Count == multiKeyGestureTemplate.Chords.Count) { + var multiKeyGestureTemplateEnumerator = multiKeyGestureTemplate.Chords.GetEnumerator(); + var previousChordsEnumerator = previousChords.GetEnumerator(); + + multiKeyGestureTemplateEnumerator.Reset(); + + // Compare two chord sequences in a loop + var multiKeyGesturesMatch = true; + + var i = 0; + while (previousChordsEnumerator.MoveNext() && multiKeyGestureTemplateEnumerator.MoveNext()) { + var template = multiKeyGestureTemplateEnumerator.Current; + var gesture = previousChordsEnumerator.Current; + + if (((mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.PartlyMatches) && i == previousChords.Count - 1) + || (mode == GestureCompareMode.PartlyMatches && i == 0)) { + + if(!(template.Modifiers == (gesture.Modifiers & template.Modifiers) && (template.Key == Key.None || template.Key == gesture.Key))) { + multiKeyGesturesMatch = false; + break; + } + } else if (template.Modifiers != gesture.Modifiers || template.Key != gesture.Key) { + multiKeyGesturesMatch = false; + break; + } + + i++; + } + + if(multiKeyGesturesMatch) { + return true; + } + + if (mode == GestureCompareMode.StartsWith || mode == GestureCompareMode.StartsWithFullChords) { + break; + } + } + } + + return false; + } + + + /// + /// Determines whether this instance of qualifies as template for any of examined gestures + /// + /// Examined input gesture template + /// Collection of examined gestures + /// Additional comparing rules. See for details + /// true if template matches one of the compared getures; otherwise false + public static bool IsTemplateForAny(this InputGesture thisGesture, InputGestureCollection examinedGestures, GestureCompareMode mode) + { + foreach (InputGesture gesture in examinedGestures) { + if (thisGesture.IsTemplateFor(gesture, mode)) { + return true; + } + } + + return false; + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs index 402f3831c6e..0ecfa3c8bcb 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyBinding.cs @@ -4,27 +4,27 @@ namespace ICSharpCode.Core.Presentation { - /// - /// Represents input binding which can be invoked by - /// - public class MultiKeyBinding : InputBinding - { - /// - /// Instance of - /// - [TypeConverter(typeof(MultiKeyGestureConverter))] - public override InputGesture Gesture - { - get { return base.Gesture as MultiKeyGesture; } - set - { - if (!(value is MultiKeyGesture)) - { - throw new ArgumentException(); - } - - base.Gesture = value; - } - } - } + /// + /// Represents input binding which can be invoked by + /// + public class MultiKeyBinding : InputBinding + { + /// + /// Gets or sets instance of + /// + [TypeConverter(typeof(MultiKeyGestureConverter))] + public override InputGesture Gesture + { + get { + return base.Gesture as MultiKeyGesture; + } + set { + if (!(value is MultiKeyGesture)) { + throw new ArgumentException(); + } + + base.Gesture = value; + } + } + } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs index f11096c47c2..b568d9eb617 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGesture.cs @@ -6,119 +6,113 @@ namespace ICSharpCode.Core.Presentation { - /// - /// Specifies gesture consisting from multiple key gestures - /// - [TypeConverter(typeof(MultiKeyGestureConverter))] - public class MultiKeyGesture : KeyGesture - { - private static readonly List allGestures = new List(); - - // Set sequence indexes of all sequential key gestures to 0 - private static void ResetAllGestures() - { - foreach (var gesture in allGestures) - { - gesture.currentGestureIndex = 0; - } - } - - private readonly ReadOnlyCollection chords; - private int currentGestureIndex; - private DateTime lastGestureInput; - - /// - /// Maximum delay between multi-key gesture chords - /// - public static TimeSpan DelayBetweenChords - { - get; set; - } - - static MultiKeyGesture() - { + /// + /// Describes gesture containing multiple chords + /// + [TypeConverter(typeof(MultiKeyGestureConverter))] + public class MultiKeyGesture : KeyGesture + { + private static readonly List allGestures = new List(); + + // Set sequence indexes of all sequential key gestures to 0 + private static void ResetAllGestures() + { + foreach (var gestureWrapper in allGestures) { + if(gestureWrapper.Target != null) { + ((MultiKeyGesture)gestureWrapper.Target).currentGestureIndex = 0; + } + } + } + + private readonly ReadOnlyCollection chords; + private int currentGestureIndex; + private DateTime lastGestureInput; + + /// + /// Maximum delay between pressing chords + /// + public static TimeSpan DelayBetweenChords + { + get; set; + } + + static MultiKeyGesture() + { DelayBetweenChords = TimeSpan.FromSeconds(2); - } - - /// - /// Creates instance of from list of partial key gestures - /// - /// Sequence of partial key gestures - public MultiKeyGesture(IList gestures) - : base(Key.None, ModifierKeys.None) - { - if(gestures == null || gestures.Count == 0) - { - throw new ArgumentException("Must specify atleast one gesture"); - } - - this.chords = new ReadOnlyCollection(gestures); - - allGestures.Add(this); - } - - /// - /// Sequence of partial key gestures which describe this sequential key gesture - /// - public ICollection Chords - { - get - { - return chords; - } - } - - /// - /// Determines whether key event arguments matches this instance of - /// - /// The target - /// Input event arguments - /// True if the event data matches this ; otherwise, false. - public override bool Matches(object targetElement, InputEventArgs inputEventArgs) - { - var keyEventArgs = inputEventArgs as KeyEventArgs; - - if (keyEventArgs == null) - { - return false; - } - - if (keyEventArgs.IsRepeat) - { - return false; - } - - // Checks wheter it is not too long from last match - var isOnTime = (DateTime.Now - lastGestureInput) <= DelayBetweenChords; - - // If strict match is on time - var strictMatch = chords[currentGestureIndex].StrictlyMatches(targetElement, inputEventArgs); - if (strictMatch && (currentGestureIndex == 0 || isOnTime)) - { - currentGestureIndex++; - lastGestureInput = DateTime.Now; - - inputEventArgs.Handled = true; - - // Check whether this is last gesture in sequence - if(currentGestureIndex == chords.Count) - { - ResetAllGestures(); - return true; - } - - return false; - } - - // If partial match is on time allow continue without reseting current gesture index - var partialMatch = chords[currentGestureIndex].Matches(targetElement, inputEventArgs); - if (partialMatch && currentGestureIndex > 0 && isOnTime) - { - return false; - } - - currentGestureIndex = 0; - return false; - } - } + } + + /// + /// Creates instance of from list of partial key gestures + /// + /// Sequence of partial key gestures + public MultiKeyGesture(IList gestures) + : base(Key.None, ModifierKeys.None) + { + if(gestures == null || gestures.Count == 0) { + throw new ArgumentException("Must specify atleast one gesture"); + } + + this.chords = new ReadOnlyCollection(gestures); + + allGestures.Add(new WeakReference(this)); + } + + /// + /// Sequence of partial key gestures which builds this + /// + public ICollection Chords + { + get { + return chords; + } + } + + /// + /// Determines whether key event arguments matches this instance of + /// + /// The target + /// Input event arguments + /// true if the event data matches this ; otherwise false + public override bool Matches(object targetElement, InputEventArgs inputEventArgs) + { + var keyEventArgs = inputEventArgs as KeyEventArgs; + + if (keyEventArgs == null) { + return false; + } + + if (keyEventArgs.IsRepeat) { + return false; + } + + // Checks wheter it is not too long from last match + var isOnTime = (DateTime.Now - lastGestureInput) <= DelayBetweenChords; + + // If strict match is on time + var strictMatch = chords[currentGestureIndex].StrictlyMatches(targetElement, inputEventArgs); + if (strictMatch && (currentGestureIndex == 0 || isOnTime)) { + currentGestureIndex++; + lastGestureInput = DateTime.Now; + + inputEventArgs.Handled = true; + + // Check whether this is last gesture in sequence + if(currentGestureIndex == chords.Count) { + ResetAllGestures(); + return true; + } + + return false; + } + + // If partial match is on time allow continue without reseting current gesture index + var partialMatch = chords[currentGestureIndex].Matches(targetElement, inputEventArgs); + if (partialMatch && currentGestureIndex > 0 && isOnTime) { + return false; + } + + currentGestureIndex = 0; + return false; + } + } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs index c145dabbfee..639f81199e4 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/MultiKeyGestureConverter.cs @@ -6,95 +6,91 @@ namespace ICSharpCode.Core.Presentation { - /// - /// Converts instance to and from other types - /// - public class MultiKeyGestureConverter : TypeConverter - { - private readonly PartialKeyGestureConverter partialKeyGestureConverter = new PartialKeyGestureConverter(); - - /// - /// Determines whether object of specified type can be converted to instance of - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// The type being evaluated for conversion. - /// True if this converter can perform the operation; otherwise, false. + /// + /// Converts instance to and from other types + /// + public class MultiKeyGestureConverter : TypeConverter + { + private readonly PartialKeyGestureConverter partialKeyGestureConverter = new PartialKeyGestureConverter(); + + /// + /// Determines whether object of specified type can be converted to instance of + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// The type being evaluated for conversion. + /// True if this converter can perform the operation; otherwise, false. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if(sourceType == typeof(string)) - { - return true; + if(sourceType == typeof(string)) { + return true; } - - return base.CanConvertFrom(context, sourceType); + + return base.CanConvertFrom(context, sourceType); } - - /// - /// Determines whether an instance of can be converted to the specified type, using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// The type being evaluated for conversion. - /// True if this converter can perform the operation; otherwise, false. - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, destinationType); - } - - /// - /// Attempts to convert a to the specified type, using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// Culture specific information. - /// The object to convert - /// The type wich instance of is being converted to. - /// The converted object, or an empty string if value is a null reference - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value == null && destinationType == typeof(string)) - { - return String.Empty; - } - - var MultiKeyGesture = value as MultiKeyGesture; - if (MultiKeyGesture != null && destinationType == typeof(string)) - { - var partialKeyGestureStrings = MultiKeyGesture.Chords.Select(gesture => (string)partialKeyGestureConverter.ConvertTo(context, culture, gesture, typeof(string))).ToArray(); - var MultiKeyGestureString = string.Join(",", partialKeyGestureStrings); - - return MultiKeyGestureString; - } - - return base.ConvertFrom(context, culture, value); - } - - /// - /// Attempts to convert the specified object to a , using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// Culture specific information. - /// The object to convert - /// The converted object. - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + + /// + /// Determines whether an instance of can be converted to the specified type, using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// The type being evaluated for conversion. + /// True if this converter can perform the operation; otherwise, false. + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { - var gestureString = value as string; - if (gestureString != null) { - var keyGestures = new List(); - - var keyGestureStrings = gestureString.Split(','); - foreach (var keyGestureString in keyGestureStrings) { - var partialKeyGesture = (PartialKeyGesture)new PartialKeyGestureConverter().ConvertFrom(context, culture, keyGestureString); - keyGestures.Add(partialKeyGesture); - } - - return new MultiKeyGesture(keyGestures); - } - - return base.ConvertFrom(context, culture, value); + if (destinationType == typeof(string)) { + return true; + } + + return base.CanConvertFrom(context, destinationType); + } + + /// + /// Attempts to convert a to the specified type, using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// Culture specific information. + /// The object to convert + /// The type wich instance of is being converted to. + /// The converted object, or an empty string if value is a null reference + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value == null && destinationType == typeof(string)) { + return String.Empty; + } + + var MultiKeyGesture = value as MultiKeyGesture; + if (MultiKeyGesture != null && destinationType == typeof(string)) { + var partialKeyGestureStrings = MultiKeyGesture.Chords.Select(gesture => (string)partialKeyGestureConverter.ConvertTo(context, culture, gesture, typeof(string))).ToArray(); + var MultiKeyGestureString = string.Join(",", partialKeyGestureStrings); + + return MultiKeyGestureString; + } + + return base.ConvertFrom(context, culture, value); + } + + /// + /// Attempts to convert the specified object to a , using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// Culture specific information. + /// The object to convert + /// The converted object. + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + var gestureString = value as string; + if (gestureString != null) { + var keyGestures = new List(); + + var keyGestureStrings = gestureString.Split(','); + foreach (var keyGestureString in keyGestureStrings) { + var partialKeyGesture = (PartialKeyGesture)new PartialKeyGestureConverter().ConvertFrom(context, culture, keyGestureString); + keyGestures.Add(partialKeyGesture); + } + + return new MultiKeyGesture(keyGestures); + } + + return base.ConvertFrom(context, culture, value); } - } + } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs b/src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs index 2c037e294d2..4a27f63bedf 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/ObservableInputGestureCollection.cs @@ -1,9 +1,3 @@ -/* - * Created by SharpDevelop. - * User: Sergej Andrejev - * Date: 7/17/2009 - * Time: 8:56 AM - */ using System; using System.Collections; using System.Collections.Generic; @@ -14,33 +8,40 @@ namespace ICSharpCode.Core.Presentation { /// - /// Description of ObservableInputBindingCollection. + /// Represents observable collection of /// public class ObservableInputGestureCollection : IList, INotifyCollectionChanged, IEnumerable, ICollection { private ObservableCollection observedInputGestures; + /// + /// Creates new instance of + /// public ObservableInputGestureCollection() { observedInputGestures = new ObservableCollection(); observedInputGestures.CollectionChanged += observedInputGestures_CollectionChanged; } + /// public void Add(InputGesture item) { observedInputGestures.Add(item); } + /// public void Insert(int index, InputGesture item) { observedInputGestures.Insert(index, item); } + /// public void RemoveAt(int index) { observedInputGestures.RemoveAt(index); } + /// public InputGesture this[int index] { get { @@ -51,6 +52,7 @@ public void RemoveAt(int index) } } + /// public bool IsReadOnly { get { @@ -58,6 +60,7 @@ public bool IsReadOnly } } + /// public int Count { get { @@ -65,57 +68,74 @@ public int Count } } + /// public bool Remove(InputGesture item) { return observedInputGestures.Remove(item); } + /// public void Clear() { observedInputGestures.Clear(); } + /// public bool Contains(InputGesture item) { return observedInputGestures.Contains(item); } - public void AddRange(InputGestureCollection items) + /// + /// Add all instances from another + /// + /// Collection of gestures + public void AddRange(InputGestureCollection gestures) { - foreach(InputGesture item in items) { + foreach(InputGesture item in gestures) { Add(item); } } - public void AddRange(IEnumerable items) + /// + /// Add all instances from enumerable collection + /// + /// Collection of gestures + public void AddRange(IEnumerable gestures) { - foreach(InputGesture item in items) { + foreach(InputGesture item in gestures) { Add(item); } } + /// public void CopyTo(InputGesture[] array, int arrayIndex) { observedInputGestures.CopyTo(array, arrayIndex); } + /// public IEnumerator GetEnumerator() { return observedInputGestures.GetEnumerator(); } + /// System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return observedInputGestures.GetEnumerator(); } + /// public int IndexOf(InputGesture value) { return observedInputGestures.IndexOf(value); } + /// public event NotifyCollectionChangedEventHandler CollectionChanged; + /// private void observedInputGestures_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if(CollectionChanged != null) { @@ -123,6 +143,9 @@ private void observedInputGestures_CollectionChanged(object sender, NotifyCollec } } + /// + /// Gets containing all items from this observable collection + /// public InputGestureCollection InputGesturesCollection { get { diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs b/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs index 01d7e7d1b0d..e74f460e018 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGesture.cs @@ -5,247 +5,243 @@ namespace ICSharpCode.Core.Presentation { - /// - /// Describes full key gesture or part of a key gesture - /// - /// This class is is designed to react to key events even it descibes only part of them - /// For example if event argument holds modifiers Ctrl, Shift and key C then partial template - /// with single modifier Ctrl and a key C will match this event - /// - [TypeConverter(typeof(PartialKeyGestureConverter))] - public class PartialKeyGesture : KeyGesture - { - private readonly Key _key; - private readonly ModifierKeys _modifiers; - - /// - /// Key associated with partial key gesture - /// - public new Key Key - { - get - { - return _key; - } - } - - /// - /// Modifier keys associated with partial key gesture - /// - public new ModifierKeys Modifiers - { - get - { - return _modifiers; - } - } - - /// - /// Create new instance of from - /// - /// Arguments generated by key event - public PartialKeyGesture(KeyEventArgs keyEventArgs) - : base(Key.None, ModifierKeys.None) - { - var keyboardDevice = (KeyboardDevice)keyEventArgs.Device; - - var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key; - var enteredModifiers = keyboardDevice.Modifiers; - - if(Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, - Key.LeftShift, Key.RightShift, - Key.LeftCtrl, Key.RightCtrl, - Key.LWin, Key.RWin}, enteredKey) >= 0) { - _key = Key.None; - _modifiers = enteredModifiers; - } else { - _key = enteredKey; - _modifiers = enteredModifiers; - } - } - - /// - /// Create new instance of from - /// - /// Key gesture - public PartialKeyGesture(KeyGesture gesture) - : base(Key.None, ModifierKeys.None) - { - var partialKeyGesture = gesture as PartialKeyGesture; - - if (partialKeyGesture != null) { - _key = partialKeyGesture.Key; - _modifiers = partialKeyGesture.Modifiers; - } else if (gesture is MultiKeyGesture) { - throw new ArgumentException("Can not create partial key gesture from multi-key gesture"); - } else { - _key = gesture.Key; - _modifiers = gesture.Modifiers; - } - } - - /// - /// Create new instance of having key and modifiers - /// - /// The key associated with partial key gesture - /// Modifier keys associated with partial key gesture - public PartialKeyGesture(Key key, ModifierKeys modifiers) - : base(Key.None, ModifierKeys.None) - { - _key = key; - _modifiers = modifiers; - } - - /// - /// Create new instance of having only key and no modifiers - /// - /// The key associated with partial key gesture - public PartialKeyGesture(Key key) - : base(Key.None, ModifierKeys.None) - { - _key = key; - _modifiers = ModifierKeys.None; - } - - /// - /// Create new instance of having only key and no modifiers - /// - /// Modifier keys associated with partial key gesture - public PartialKeyGesture(ModifierKeys modifiers) - : base(Key.None, ModifierKeys.None) - { - _key = Key.None; - _modifiers = modifiers; - } - - - /// - /// Determines whether key gesture strictly matches this key gesture template - /// (That is key and modifier both match key event arguments) - /// - /// The target - /// Input event arguments - /// True if the event data matches this ; otherwise, false. - public bool StrictlyMatches(object targetElement, InputEventArgs args) - { - var keyEventArgs = args as KeyEventArgs; - if(keyEventArgs == null) - { - return false; - } - - var keyboard = (KeyboardDevice)keyEventArgs.Device; - - // If system key is pressed - if (keyEventArgs.Key == Key.System) - { - return keyboard.Modifiers == Modifiers && keyEventArgs.SystemKey == Key; - } - - return keyboard.Modifiers == Modifiers && keyEventArgs.Key == Key; - } - - /// - /// Determines whether key event arguments matches this instance of - /// - /// The target - /// Input event arguments - /// True if event data matches parial event arguments otherwise false - public override bool Matches(object targetElement, InputEventArgs inputEventArgs) - { - var keyEventArgs = inputEventArgs as KeyEventArgs; - if(keyEventArgs == null) - { - return false; - } - - var keyboard = (KeyboardDevice)keyEventArgs.Device; - - // When system key (Alt) is pressed real key is moved to SystemKey property - var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key; - - var keyMatches = Key == enteredKey; - - // Determine whether template contains only part of modifier keys contained in - // gesture. For example if template contains Control modifier, but gesture contains - // Control and Alt true will be returned - var modifierMatches = keyboard.Modifiers - (keyboard.Modifiers ^ Modifiers) >= 0; - - // Template contains no modifiers compare only keys - if (Modifiers == ModifierKeys.None) - { - return keyMatches; - } - - // If template has modifiers but key is one of modifier keys return true if - // modifiers match. This is used because when user presses modifier key it is - // presented in Key property and Modifiers property - if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, - Key.LeftShift, Key.RightShift, - Key.LeftCtrl, Key.RightCtrl, - Key.LWin, Key.RWin, - Key.System}, enteredKey) >= 0) - { - return modifierMatches; - } - - return modifierMatches && keyMatches; - } - - public bool IsFull - { - get { - if(Key == Key.None) { - return false; - } - - // and function keys are valid without modifier - if (Key >= Key.F1 && Key <= Key.F24) { - return true; - } - - // Modifiers alone are not valid - if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, - Key.LeftShift, Key.RightShift, - Key.LeftCtrl, Key.RightCtrl, - Key.LWin, Key.RWin, - Key.System}, Key) > -1) { - return false; - } - - // All other gestures must have modifier (except shift alone because it would mean uppercase) - if((Modifiers & (ModifierKeys.Windows | ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.None) { - return true; - } - - return false; - } - } - - /// - /// Returns string that represents - /// - /// String - public override string ToString() - { - var pressedButton = new StringBuilder(); - - if (Modifiers != ModifierKeys.None) - { - pressedButton.AppendFormat("{0}+", new ModifierKeysConverter().ConvertToInvariantString(Modifiers)); - } - - // Filter modifier keys from being displayed twice (example: Ctrl + LeftCtrl) - if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, - Key.LeftShift, Key.RightShift, - Key.LeftCtrl, Key.RightCtrl, - Key.LWin, Key.RWin, - Key.System}, Key) < 0) - { - pressedButton.Append(new KeyConverter().ConvertToInvariantString(Key)); - } - - return pressedButton.ToString(); - } - } + /// + /// Describes full key gesture or part of a key gesture + /// + /// This class is is designed to react to key events even it descibes only part of them + /// For example if event argument holds modifiers Ctrl, Shift and key C then partial template + /// with single modifier Ctrl and a key C will match this event + /// + [TypeConverter(typeof(PartialKeyGestureConverter))] + public class PartialKeyGesture : KeyGesture + { + private readonly Key _key; + private readonly ModifierKeys _modifiers; + + /// + /// Gets key associated with partial key gesture + /// + public new Key Key + { + get { + return _key; + } + } + + /// + /// Gets modifier keys associated with partial key gesture + /// + public new ModifierKeys Modifiers + { + get { + return _modifiers; + } + } + + /// + /// Create new instance of from + /// + /// Arguments generated by key event + public PartialKeyGesture(KeyEventArgs keyEventArgs) + : base(Key.None, ModifierKeys.None) + { + var keyboardDevice = (KeyboardDevice)keyEventArgs.Device; + + var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key; + var enteredModifiers = keyboardDevice.Modifiers; + + if(Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, + Key.LeftShift, Key.RightShift, + Key.LeftCtrl, Key.RightCtrl, + Key.LWin, Key.RWin}, enteredKey) >= 0) { + _key = Key.None; + _modifiers = enteredModifiers; + } else { + _key = enteredKey; + _modifiers = enteredModifiers; + } + } + + /// + /// Create new instance of from + /// + /// Key gesture + public PartialKeyGesture(KeyGesture gesture) + : base(Key.None, ModifierKeys.None) + { + var partialKeyGesture = gesture as PartialKeyGesture; + + if (partialKeyGesture != null) { + _key = partialKeyGesture.Key; + _modifiers = partialKeyGesture.Modifiers; + } else if (gesture is MultiKeyGesture) { + throw new ArgumentException("Can not create partial key gesture from multi-key gesture"); + } else { + _key = gesture.Key; + _modifiers = gesture.Modifiers; + } + } + + /// + /// Create new instance of having key and modifiers + /// + /// The key associated with partial key gesture + /// Modifier keys associated with partial key gesture + public PartialKeyGesture(Key key, ModifierKeys modifiers) + : base(Key.None, ModifierKeys.None) + { + _key = key; + _modifiers = modifiers; + } + + /// + /// Create new instance of having only key and no modifiers + /// + /// The key associated with partial key gesture + public PartialKeyGesture(Key key) + : base(Key.None, ModifierKeys.None) + { + _key = key; + _modifiers = ModifierKeys.None; + } + + /// + /// Create new instance of having only key and no modifiers + /// + /// Modifier keys associated with partial key gesture + public PartialKeyGesture(ModifierKeys modifiers) + : base(Key.None, ModifierKeys.None) + { + _key = Key.None; + _modifiers = modifiers; + } + + + /// + /// Determines whether input event supporting data strictly (all modifiers and keys) matches this instance of + /// + /// The target + /// Input event arguments + /// true if event data matches partial gesture; otherwise false + public bool StrictlyMatches(object targetElement, InputEventArgs args) + { + var keyEventArgs = args as KeyEventArgs; + if(keyEventArgs == null) { + return false; + } + + var keyboard = (KeyboardDevice)keyEventArgs.Device; + + // If system key is pressed + if (keyEventArgs.Key == Key.System) { + return keyboard.Modifiers == Modifiers && keyEventArgs.SystemKey == Key; + } + + return keyboard.Modifiers == Modifiers && keyEventArgs.Key == Key; + } + + /// + /// Determines whether input event arguments partly matches (part of modifiers or/and a key) this instance of + /// + /// The target + /// Input event arguments + /// true if event data matches partial gesture; otherwise false + public override bool Matches(object targetElement, InputEventArgs inputEventArgs) + { + var keyEventArgs = inputEventArgs as KeyEventArgs; + if(keyEventArgs == null) { + return false; + } + + var keyboard = (KeyboardDevice)keyEventArgs.Device; + + // When system key (Alt) is pressed real key is moved to SystemKey property + var enteredKey = keyEventArgs.Key == Key.System ? keyEventArgs.SystemKey : keyEventArgs.Key; + + var keyMatches = Key == enteredKey; + + // Determine whether template contains only part of modifier keys contained in + // gesture. For example if template contains Control modifier, but gesture contains + // Control and Alt true will be returned + var modifierMatches = keyboard.Modifiers - (keyboard.Modifiers ^ Modifiers) >= 0; + + // Template contains no modifiers compare only keys + if (Modifiers == ModifierKeys.None) { + return keyMatches; + } + + // If template has modifiers but key is one of modifier keys return true if + // modifiers match. This is used because when user presses modifier key it is + // presented in Key property and Modifiers property + if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, + Key.LeftShift, Key.RightShift, + Key.LeftCtrl, Key.RightCtrl, + Key.LWin, Key.RWin, + Key.System}, enteredKey) >= 0) { + return modifierMatches; + } + + return modifierMatches && keyMatches; + } + + /// + /// Gets value indicating whether this InputGesture is completed + /// + /// Incomplete gestures are ones which have only modifiers or only + /// keys assigned + /// + public bool IsFull + { + get { + if(Key == Key.None) { + return false; + } + + // and function keys are valid without modifier + if (Key >= Key.F1 && Key <= Key.F24) { + return true; + } + + // Modifiers alone are not valid + if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, + Key.LeftShift, Key.RightShift, + Key.LeftCtrl, Key.RightCtrl, + Key.LWin, Key.RWin, + Key.System}, Key) > -1) { + return false; + } + + // All other gestures must have modifier (except shift alone because it would mean uppercase) + if((Modifiers & (ModifierKeys.Windows | ModifierKeys.Control | ModifierKeys.Alt)) != ModifierKeys.None) { + return true; + } + + return false; + } + } + + /// + /// Creates string that represents + /// + /// String representation of this object + public override string ToString() + { + var pressedButton = new StringBuilder(); + + if (Modifiers != ModifierKeys.None) { + pressedButton.AppendFormat("{0}+", new ModifierKeysConverter().ConvertToInvariantString(Modifiers)); + } + + // Filter modifier keys from being displayed twice (example: Ctrl + LeftCtrl) + if (Array.IndexOf(new[] { Key.LeftAlt, Key.RightAlt, + Key.LeftShift, Key.RightShift, + Key.LeftCtrl, Key.RightCtrl, + Key.LWin, Key.RWin, + Key.System}, Key) < 0) { + pressedButton.Append(new KeyConverter().ConvertToInvariantString(Key)); + } + + return pressedButton.ToString(); + } + } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs b/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs index 0b53e954b53..7e7cdf6b23f 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Input/PartialKeyGestureConverter.cs @@ -6,127 +6,119 @@ namespace ICSharpCode.Core.Presentation { - /// - /// Converts instance to and from other types - /// - public class PartialKeyGestureConverter : TypeConverter - { - private readonly KeyConverter keyConverter = new KeyConverter(); - private readonly ModifierKeysConverter modidierKeysConverter = new ModifierKeysConverter(); - - /// - /// Determines whether object of specified type can be converted to instance of - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// The type being evaluated for conversion. - /// True if this converter can perform the operation; otherwise, false. - public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + /// + /// Converts instance to and from other types + /// + public class PartialKeyGestureConverter : TypeConverter + { + private readonly KeyConverter keyConverter = new KeyConverter(); + private readonly ModifierKeysConverter modidierKeysConverter = new ModifierKeysConverter(); + + /// + /// Determines whether object of specified type can be converted to instance of + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// The type being evaluated for conversion. + /// True if this converter can perform the operation; otherwise, false. + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { - if(sourceType == typeof(string)) - { - return true; + if(sourceType == typeof(string)) { + return true; } - - return base.CanConvertFrom(context, sourceType); + + return base.CanConvertFrom(context, sourceType); } - - /// - /// Determines whether an instance of can be converted to the specified type, using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// The type being evaluated for conversion. - /// True if this converter can perform the operation; otherwise, false. - public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) - { - if (destinationType == typeof(string)) - { - return true; - } - - return base.CanConvertFrom(context, destinationType); - } - - /// - /// Attempts to convert a to the specified type, using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// Culture specific information. - /// The object to convert - /// The type wich instance of is being converted to. - /// The converted object, or an empty string if value is a null reference - public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) - { - if (value == null && destinationType == typeof(string)) - { - return String.Empty; - } - - if(value is PartialKeyGesture && destinationType == typeof(string)) - { - var partialKeyGesture = value as PartialKeyGesture; - - var modifierString = (string)new ModifierKeysConverter().ConvertTo(context, culture, partialKeyGesture.Modifiers, typeof(string)); - var keyString = (string)new KeyConverter().ConvertTo(context, culture, partialKeyGesture.Key, typeof(string)); - - var sb = new StringBuilder(); - sb.Append(modifierString); - if(!string.IsNullOrEmpty(keyString) && !string.IsNullOrEmpty(modifierString)) - { - sb.Append("+"); - } - sb.Append(keyString); - - return sb.ToString(); - } - - return base.ConvertTo(context, culture, value, destinationType); - } - - /// - /// Attempts to convert the specified object to a , using the specified context. - /// - /// A format context that provides information about the environment from which this converter is being invoked. - /// Culture specific information. - /// The object to convert - /// The converted object. + + /// + /// Determines whether an instance of can be converted to the specified type, using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// The type being evaluated for conversion. + /// True if this converter can perform the operation; otherwise, false. + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) { + return true; + } + + return base.CanConvertFrom(context, destinationType); + } + + /// + /// Attempts to convert a to the specified type, using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// Culture specific information. + /// The object to convert + /// The type wich instance of is being converted to. + /// The converted object, or an empty string if value is a null reference + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (value == null && destinationType == typeof(string)) { + return String.Empty; + } + + if(value is PartialKeyGesture && destinationType == typeof(string)) { + var partialKeyGesture = value as PartialKeyGesture; + + var modifierString = (string)new ModifierKeysConverter().ConvertTo(context, culture, partialKeyGesture.Modifiers, typeof(string)); + var keyString = (string)new KeyConverter().ConvertTo(context, culture, partialKeyGesture.Key, typeof(string)); + + var sb = new StringBuilder(); + sb.Append(modifierString); + if(!string.IsNullOrEmpty(keyString) && !string.IsNullOrEmpty(modifierString)) { + sb.Append("+"); + } + sb.Append(keyString); + + return sb.ToString(); + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + /// + /// Attempts to convert the specified object to a , using the specified context. + /// + /// A format context that provides information about the environment from which this converter is being invoked. + /// Culture specific information. + /// The object to convert + /// The converted object. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { - var gestureString = value as string; - if (gestureString != null) - { - var keysStart = gestureString.LastIndexOf('+'); - if (keysStart > 0) - { - var modifierKeysString = gestureString.Substring(0, keysStart); - var keyString = gestureString.Substring(keysStart + 1); - - var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, modifierKeysString); - var key = (Key)keyConverter.ConvertFrom(context, culture, keyString); - - return new PartialKeyGesture(key, modifierKeys); - } - - try - { - var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, gestureString); - - return new PartialKeyGesture(modifierKeys); - } - catch (NotSupportedException) - { } - - - try - { - var key = (Key)keyConverter.ConvertFrom(context, culture, gestureString); - - return new PartialKeyGesture(key); - } - catch (NotSupportedException) - { } - } - - return base.ConvertFrom(context, culture, value); + var gestureString = value as string; + if (gestureString != null) { + var keysStart = gestureString.LastIndexOf('+'); + if (keysStart > 0) { + var modifierKeysString = gestureString.Substring(0, keysStart); + var keyString = gestureString.Substring(keysStart + 1); + + var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, modifierKeysString); + var key = (Key)keyConverter.ConvertFrom(context, culture, keyString); + + return new PartialKeyGesture(key, modifierKeys); + } + + try { + var modifierKeys = (ModifierKeys)modidierKeysConverter.ConvertFrom(context, culture, gestureString); + + return new PartialKeyGesture(modifierKeys); + } + catch (NotSupportedException) + { } + + + try + { + var key = (Key)keyConverter.ConvertFrom(context, culture, gestureString); + + return new PartialKeyGesture(key); + } + catch (NotSupportedException) + { } + } + + return base.ConvertFrom(context, culture, value); } - } + } }