diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo index 8e19d5a9609..ac06e9d1f00 100644 Binary files a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/StringResources.resx b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/StringResources.resx index d57792d8378..7f6d85f8edd 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/StringResources.resx +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/StringResources.resx @@ -140,4 +140,31 @@ Uncategorized + + First chord must have a modifier + + + Valid gesture + + + Multi key gesture is not finished + + + Invalid gesture. Sequence is not coherent. + + + Time given for gesture entry expired + + + Failed to add a gesture. First chord should contain a modifier + + + Failed to add a gesture. Gesture is unfinished. Last chord should have a key + + + Failed to add a gesture. Gesture must have atleast one chord + + + Gesture added + \ No newline at end of file diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/Thumbs.db b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/Thumbs.db index 935d92f604f..b3cac4ddc5a 100644 Binary files a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/Thumbs.db and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/Thumbs.db differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/block_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/block_small.png new file mode 100644 index 00000000000..cea7cd0f773 Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/block_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/delete_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/delete_small.png new file mode 100644 index 00000000000..c3134399aeb Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/delete_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/info_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/info_small.png new file mode 100644 index 00000000000..2794af30db5 Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/info_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/plus_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/plus_small.png new file mode 100644 index 00000000000..c78afd1d534 Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/plus_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/search_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/search_small.png new file mode 100644 index 00000000000..e930b6cad72 Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/search_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/tick_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/tick_small.png new file mode 100644 index 00000000000..abc312f1862 Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/tick_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/warning_small.png b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/warning_small.png new file mode 100644 index 00000000000..86668e4e07a Binary files /dev/null and b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Resources/warning_small.png differ diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.addin b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.addin index 35d4e939c74..642c86ced5f 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.addin +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.addin @@ -14,6 +14,6 @@ + class = "ICSharpCode.ShortcutsManagement.Dialogs.ShortcutsManagementOptionsPanel" /> diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj index 7428dac0ac9..44f9d76e0ac 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj @@ -62,6 +62,8 @@ 3.5 + + 3.5 @@ -88,6 +90,10 @@ MSBuild:Compile Designer + + Designer + MSBuild:Compile + Designer MSBuild:Compile @@ -142,11 +148,14 @@ Settings.settings True + - + + MultiKeyGestureTextBox.xaml + ShortcutManagementWindow.xaml @@ -157,6 +166,7 @@ ShortcutsTreeView.xaml + @@ -176,6 +186,13 @@ + + + + + + + Always diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/BoolToVisibilityConverter.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/BoolToVisibilityConverter.cs index f9e3f8719f9..b7bdf4df198 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/BoolToVisibilityConverter.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/BoolToVisibilityConverter.cs @@ -26,12 +26,12 @@ public object Convert(object value, Type targetType, object parameter, CultureIn return (bool)value ? "Visible" : hidden; } - throw new NotImplementedException(); + throw new NotSupportedException(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - throw new NotImplementedException(); + throw new NotSupportedException(); } } } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/GesturesCollectionConverter.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/GesturesCollectionConverter.cs index dec24891388..a9439c878fa 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/GesturesCollectionConverter.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/GesturesCollectionConverter.cs @@ -31,7 +31,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn foreach (var gesture in (ObservableCollection)value) { inputGestureCollection.Add(gesture); } - return new InputGestureCollectionConverter().ConvertToInvariantString(inputGestureCollection).Replace("|", " | "); + return new InputGestureCollectionConverter().ConvertToInvariantString(inputGestureCollection); } return value.ToString(); diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/InputGestureConverter.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/InputGestureConverter.cs index 908e7c3a685..d8431a8f844 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/InputGestureConverter.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Converters/InputGestureConverter.cs @@ -2,6 +2,7 @@ using System.Globalization; using System.Windows.Data; using System.Windows.Input; +using ICSharpCode.Core.Presentation; namespace ICSharpCode.ShortcutsManagement.Converters { @@ -20,6 +21,11 @@ public class InputGestureConverter : IValueConverter /// public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { + if (value is MultiKeyGesture && targetType == typeof(string)) + { + return new MultiKeyGestureConverter().ConvertToInvariantString(value).Replace("+", " + "); + } + if(value is KeyGesture && targetType == typeof(string)) { return new KeyGestureConverter().ConvertToInvariantString(value).Replace("+", " + "); diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs index 92837eec28b..9a7f7010d0b 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; namespace ICSharpCode.ShortcutsManagement.Data @@ -73,17 +72,6 @@ public AddIn(string addInName) Categories = new List(); } - /// - /// Invoke dependency property changed event - /// - /// Name of dependency property from this classs - private void InvokePropertyChanged(string propertyName) - { - if (PropertyChanged != null) { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - /// /// Find shortcut by shortcutId in add-in categories /// @@ -115,6 +103,9 @@ public object Clone() return clonedAddIn; } + /// + /// Sort add-in sub categories + /// public void SortSubEntries() { Categories.Sort((a, b) => a.Name.CompareTo(b.Name)); @@ -129,12 +120,29 @@ public void SortSubEntries() /// public event PropertyChangedEventHandler PropertyChanged; + /// + /// Compare add-in to other instances of + /// + /// Compared object + /// Comparison result public int CompareTo(object obj) { if (obj is ShortcutCategory) return 1; if (obj is Shortcut) return 1; var addInObj = (AddIn)obj; return Name.CompareTo(addInObj.Name); - } + } + + /// + /// Invoke dependency property changed event + /// + /// Name of dependency property from this classs + private void InvokePropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } } } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/GestureFilterMode.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/GestureFilterMode.cs new file mode 100644 index 00000000000..e23ea03b8ef --- /dev/null +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/GestureFilterMode.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace ICSharpCode.ShortcutsManagement.Data +{ + /// + /// Gesture filtering mode + /// + public enum GestureFilterMode + { + /// + /// Match is successful if template gesture strictly matches compared gesture + /// + StrictlyMatches, + + /// + /// Match is successfull if template gesture partly matches compared geture. + /// Template is found in any place within matched gesture + /// + PartlyMatches, + + /// + /// match is successfull if matched gesture starts with provided template + /// + StartsWith + } +} diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/IShortcutTreeEntry.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/IShortcutTreeEntry.cs index 4c8b1e446a9..da6532d5006 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/IShortcutTreeEntry.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/IShortcutTreeEntry.cs @@ -1,24 +1,35 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace ICSharpCode.ShortcutsManagement.Data { public interface IShortcutTreeEntry : IComparable, ICloneable { + /// + /// Shortcut entry name displayed in shortcuts tree + /// string Name { get; set; } + /// + /// Specifies whether shortcut tree entry is visible + /// bool IsVisible { get; set; } + /// + /// Sort shortcut entry sub elements + /// void SortSubEntries(); + /// + /// Search for shortcut in this shortcut entry and sub-elements + /// + /// + /// Shortcut FindShortcut(string shortcutId); } } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/KeyGestureTemplate.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/KeyGestureTemplate.cs deleted file mode 100644 index 3aec34d4426..00000000000 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/KeyGestureTemplate.cs +++ /dev/null @@ -1,163 +0,0 @@ -using System; -using System.Text; -using System.Windows.Input; - -namespace ICSharpCode.ShortcutsManagement.Data -{ - /// - /// Describes full key gesture or part of key gesture - /// - public class KeyGestureTemplate - { - /// - /// Gets the key associated with key gesture template - /// - public Key Key - { - get; - private set; - } - - /// - /// Get modifier keys associated with key gesture template - /// - public ModifierKeys Modifiers - { - get; - private set; - } - - /// - /// Create new instance of from - /// - /// Arguments generated by key event - public KeyGestureTemplate(KeyEventArgs keyEventArgs) - { - var keyboardDevice = (KeyboardDevice)keyEventArgs.Device; - - Key = keyEventArgs.Key; - Modifiers = keyboardDevice.Modifiers; - } - - /// - /// Create new instance of key gesture template from key gesture - /// - /// Key gesture - public KeyGestureTemplate(KeyGesture gesture) - { - Key = gesture.Key; - Modifiers = gesture.Modifiers; - } - - /// - /// Create new instance of key gesture template from key and modifiers - /// - /// The key associated with key gesture template - /// Modifier keys associated with key gesture template - public KeyGestureTemplate(Key key, ModifierKeys modifiers) - { - Key = key; - Modifiers = modifiers; - } - - /// - /// Create key gesture template from key only (without modifiers) - /// - /// The key associated with key gesture template - public KeyGestureTemplate(Key key) - { - Key = key; - Modifiers = ModifierKeys.None; - } - - /// - /// Determines whether key gesture matches this key gesture template - /// - /// Key gesture - /// If true both modifiers and key should match. Otherwice gesture matches to template if template describe only part of shortcut - /// - public bool Matches(KeyGesture gesture, bool strictMatch) - { - if(strictMatch) { - return Key == gesture.Key && Modifiers == gesture.Modifiers; - } - - var keyMatches = Key == gesture.Key; - - // 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 = gesture.Modifiers - (gesture.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}, Key) >= 0) { - return modifierMatches; - } - - return modifierMatches && keyMatches; - } - - public bool MatchesCollection(InputGestureCollection gestures, bool strictMatch) - { - foreach (InputGesture gesture in gestures) - { - if(gesture is KeyGesture && Matches((KeyGesture)gesture, strictMatch)) - { - return true; - } - } - - return false; - } - - /// - /// Returns string that represents - /// - /// String - public override string ToString() - { - var pressedButton = new StringBuilder(); - - // Display modifier - if ((Modifiers & ModifierKeys.Control) > 0) - { - pressedButton.Append("Ctrl + "); - } - if ((Modifiers & ModifierKeys.Windows) > 0) - { - pressedButton.Append("Windows + "); - } - if ((Modifiers & ModifierKeys.Alt) > 0) - { - pressedButton.Append("Alt + "); - } - if ((Modifiers & ModifierKeys.Shift) > 0) - { - pressedButton.Append("Shift + "); - } - - // Filter modifier keys from being displayed twice (example: Control + 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/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs index fea01099784..6be150bf0b1 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs @@ -79,6 +79,11 @@ public bool IsVisible } } + /// + /// Notify observers about property changes + /// + public event PropertyChangedEventHandler PropertyChanged; + /// /// Create new instance of shortcut /// @@ -143,23 +148,10 @@ public object Clone() } /// - /// Invoke dependency property changed event - /// - /// Name of dependency property from this classs - private void InvokePropertyChanged(string propertyName) - { - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - - /// - /// Notify observers about property changes + /// Compare shortcut to other instances of /// - public event PropertyChangedEventHandler PropertyChanged; - - + /// Compared object + /// Comparison result public int CompareTo(object obj) { if (obj is AddIn) return -1; @@ -169,8 +161,25 @@ public int CompareTo(object obj) return Name.CompareTo(shortcutObj.Name); } + /// + /// Returns this instance if searched id matches + /// + /// Searched shortcut id + /// Found shortcut instance or null public Shortcut FindShortcut(string shortcutId) { return Id == shortcutId ? this : null; } + + /// + /// Invoke dependency property changed event + /// + /// Name of dependency property from this classs + private void InvokePropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } } } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs index 3d1cf2f5093..371536cd6bf 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; namespace ICSharpCode.ShortcutsManagement.Data @@ -72,6 +71,11 @@ public List Shortcuts private set; } + /// + /// Notify observers about property changes + /// + public event PropertyChangedEventHandler PropertyChanged; + /// /// Create new instance of category /// @@ -103,6 +107,9 @@ public object Clone() return clonedCategory; } + /// + /// Sort category shortcuts + /// public void SortSubEntries() { SubCategories.Sort((a, b) => a.Name.CompareTo(b.Name)); @@ -140,21 +147,10 @@ public Shortcut FindShortcut(string shortcutId) } /// - /// Invoke dependency property changed event + /// Compare shortcut category to other instances of /// - /// Name of dependency property from this classs - private void InvokePropertyChanged(string propertyName) - { - if (PropertyChanged != null) { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - - /// - /// Notify observers about property changes - /// - public event PropertyChangedEventHandler PropertyChanged; - + /// Compared object + /// Comparison result public int CompareTo(object obj) { if (obj is AddIn) return -1; @@ -163,5 +159,17 @@ public int CompareTo(object obj) var categoryObj = (ShortcutCategory)obj; return Name.CompareTo(categoryObj.Name); } + + /// + /// Invoke dependency property changed event + /// + /// Name of dependency property from this classs + private void InvokePropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + } } } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutsFinder.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutsFinder.cs index 28574e9ad9a..eedca764833 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutsFinder.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutsFinder.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Windows.Input; +using ICSharpCode.Core.Presentation; +using ICSharpCode.ShortcutsManagement.Extensions; namespace ICSharpCode.ShortcutsManagement.Data { @@ -94,31 +97,32 @@ private static bool HideShortcut(ShortcutCategory category, Shortcut filteredSho /// /// Hides add-ins and sub-categories if there are no sub-elements left /// - /// Gesture template (Uncompleted gesture) - /// If false filter gestures which with only partial match - public void FilterGesture(KeyGestureTemplate keyGestureTemplate, bool strictMatch) + /// Gesture template which should match shortcut gesture partly to make it visible + /// Filtering mode + public void FilterGesture(InputGesture inputGestureTemplate, GestureFilterMode mode) { - FilterGesture(new List { keyGestureTemplate }, strictMatch); + FilterGesture(new InputGestureCollection(new[] { inputGestureTemplate }), mode); } /// - /// Filter gestures matching provided key gesture template + /// Filter gestures matching one of provided gesture templates /// /// Hides add-ins and sub-categories if there are no sub-elements left /// - /// Gesture templates collection (Uncompleted gestures) - /// If false filter gestures which with only partial match - public void FilterGesture(ICollection keyGestureTemplateCollection, bool strictMatch) + /// Collection of gesture templates which (atleast one) should match shortcut gesture partly to make it visible + /// Filtering mode + public void FilterGesture(InputGestureCollection inputGestureTemplateCollection, GestureFilterMode mode) { + Debug.WriteLine("Changed to" + new InputGestureCollectionConverter().ConvertToInvariantString(inputGestureTemplateCollection)); foreach (var entry in RootEntries) { var subCategoryIsVisible = false; + // Filter root addin and sub-elements var rootAddIn = entry as AddIn; - if (rootAddIn != null) - { + if (rootAddIn != null) { foreach (var category in rootAddIn.Categories) { - if (FilterGesture(category, keyGestureTemplateCollection, strictMatch)) { + if (FilterGesture(category, inputGestureTemplateCollection, mode)) { subCategoryIsVisible = true; } } @@ -127,16 +131,18 @@ public void FilterGesture(ICollection keyGestureTemplateColl rootAddIn.IsVisible = subCategoryIsVisible; } + // Filter root category and sub-elements var rootCategory = entry as ShortcutCategory; if (rootCategory != null) { - FilterGesture(rootCategory, keyGestureTemplateCollection, strictMatch); + FilterGesture(rootCategory, inputGestureTemplateCollection, mode); } + // Filter root shortcut var rootShortcut = entry as Shortcut; if (rootShortcut != null) { rootShortcut.IsVisible = false; - foreach (var template in keyGestureTemplateCollection) { - if (template.MatchesCollection(new InputGestureCollection(rootShortcut.Gestures), strictMatch)) { + foreach (InputGesture template in inputGestureTemplateCollection) { + if (template.MatchesCollection(new InputGestureCollection(rootShortcut.Gestures), mode)) { rootShortcut.IsVisible = true; break; } @@ -146,17 +152,19 @@ public void FilterGesture(ICollection keyGestureTemplateColl } /// - /// Filter gestures matching one of provided key gesture templates from templates collection + /// Filter gestures matching one of provided gesture templates from templates collection /// /// Category to filter - /// Gesture templates collection (Uncompleted gestures) + /// Collection of gesture templates which (atleast one) should match shortcut gesture partly to make it visible + /// Filtering mode /// - private static bool FilterGesture(ShortcutCategory category, IEnumerable keyGestureTemplateCollection, bool strictMatch) + private static bool FilterGesture(ShortcutCategory category, InputGestureCollection inputGestureTemplateCollection, GestureFilterMode mode) { // Apply filter to sub-categories var isSubElementVisible = false; foreach (var subCategory in category.SubCategories) { - if (FilterGesture(subCategory, keyGestureTemplateCollection, strictMatch)) { + if (FilterGesture(subCategory, inputGestureTemplateCollection, mode)) + { isSubElementVisible = true; } } @@ -164,8 +172,15 @@ private static bool FilterGesture(ShortcutCategory category, IEnumerable 0 && ((KeyGesture)shortcut.Gestures[0]).Key == Key.F5) + { + + } + + if (template.MatchesCollection(new InputGestureCollection(shortcut.Gestures), mode)) + { gestureMatched = true; break; } @@ -221,7 +236,7 @@ public void Filter(string filterString) var rootShortcut = entry as Shortcut; if (rootShortcut != null) { - rootShortcut.IsVisible = rootShortcut.Name.IndexOf(filterString, StringComparison.InvariantCultureIgnoreCase) >= 0; + rootShortcut.IsVisible = filterString == null || rootShortcut.Name.IndexOf(filterString, StringComparison.InvariantCultureIgnoreCase) >= 0; } } } @@ -252,7 +267,8 @@ private static bool Filter(ShortcutCategory category, string filterString, bool? // Filter shortcuts which text match the filter foreach (var shortcut in category.Shortcuts) { - if ((forseMatch.HasValue && forseMatch.Value) || shortcut.Name.IndexOf(filterString, StringComparison.InvariantCultureIgnoreCase) >= 0) { + if ((forseMatch.HasValue && forseMatch.Value) || filterString == null || shortcut.Name.IndexOf(filterString, StringComparison.InvariantCultureIgnoreCase) >= 0) + { shortcut.IsVisible = true; isSubElementVisible = true; } diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml new file mode 100644 index 00000000000..869f1a22b18 --- /dev/null +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml.cs new file mode 100644 index 00000000000..fa20bc82bc6 --- /dev/null +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/MultiKeyGestureTextBox.xaml.cs @@ -0,0 +1,305 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using ICSharpCode.Core; +using ICSharpCode.Core.Presentation; + +namespace ICSharpCode.ShortcutsManagement.Dialogs +{ + /// + /// Notification type enumeration + /// + public enum NotificationType + { + /// + /// A valid gesture is entered so far + /// + Valid, + + /// + /// Gesture is being entered, but is not valid yet + /// + Invalid, + + /// + /// Gesture was successfully added to gestures collection + /// + Added, + + /// + /// Failed to add gesture to gestures collection + /// + Failed, + + /// + /// Notification message is not displayed + /// + None + } + + /// + /// Represents a textbox suited for entering key gestures + /// + public partial class MultiKeyGestureTextBox : UserControl + { + /// + /// Identifies dependency property + /// + public static readonly DependencyProperty TextBoxBorderThicknessProperty = DependencyProperty.Register( + "TextBoxBorderThickness", + typeof(int), + typeof(MultiKeyGestureTextBox), + new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsRender)); + + /// + /// Specifies text box border thickness + /// + public int TextBoxBorderThickness + { + get { + return (int)GetValue(TextBoxBorderThicknessProperty); + } + set { + SetValue(TextBoxBorderThicknessProperty, value); + } + } + + /// + /// Key gesture entered in text box + /// + public KeyGesture Gesture + { + get { + if (enteredKeyGestureSequence == null || enteredKeyGestureSequence.Count == 0) { + return null; + } + + if (enteredKeyGestureSequence.Count == 1) { + return enteredKeyGestureSequence.First(); + } + + return new MultiKeyGesture(enteredKeyGestureSequence); + } + } + + /// + /// Event which is raised when gesture entered in text box changes + /// + public event EventHandler GestureChanged; + + /// + /// Identifies dependency property + /// + public static readonly DependencyProperty NotificationVisibilityProperty = DependencyProperty.Register( + "NotificationVisibility", + typeof(Visibility), + typeof(MultiKeyGestureTextBox), + new FrameworkPropertyMetadata(Visibility.Visible, FrameworkPropertyMetadataOptions.AffectsRender)); + + /// + /// Whether notifications are displayed under textbox control + /// + public Visibility NotificationVisibility + { + get { + return (Visibility)GetValue(NotificationVisibilityProperty); + } + set { + SetValue(NotificationVisibilityProperty, value); + } + } + + /// + /// Identifies dependency property + /// + public static readonly DependencyProperty NotificationTypeProperty = DependencyProperty.Register( + "NotificationType", + typeof(NotificationType), + typeof(MultiKeyGestureTextBox), + new FrameworkPropertyMetadata(NotificationType.None, FrameworkPropertyMetadataOptions.AffectsRender)); + + /// + /// Specifies displayed notification type + /// + public NotificationType NotificationType + { + get { + return (NotificationType)GetValue(NotificationTypeProperty); + } + set { + SetValue(NotificationTypeProperty, value); + } + } + + /// + /// Identifies dependency property + /// + public static readonly DependencyProperty NotificationTextProperty = DependencyProperty.Register( + "NotificationText", + typeof(string), + typeof(MultiKeyGestureTextBox), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)); + + /// + /// Specifies displayed notification text + /// + public string NotificationText + { + get { + return (string)GetValue(NotificationTextProperty); + } + set { + SetValue(NotificationTextProperty, value); + } + } + + /// + /// Last entered chords + /// + private readonly List enteredKeyGestureSequence = new List(); + + /// + /// Time when last successfull chord was entered + /// + private DateTime lastEnterTime = DateTime.Now; + + /// + /// Creates instance of + /// + public MultiKeyGestureTextBox() + { + InitializeComponent(); + } + + /// + /// Displays notifications under gesture text box + /// + /// Notification text + /// Notification type + public void DisplayNotification(string notificationText, NotificationType type) + { + NotificationText = notificationText; + NotificationType = type; + } + + /// + /// Clears all text area, chords and hides notification + /// + public void Clear() + { + enteredKeyGestureSequence.Clear(); + shortcutTextBox.Text = ""; + DisplayNotification("", NotificationType.None); + } + + /// + /// Raised when clicked on "Clear" button to the right from gesture text box + /// + /// + /// + private void clearTextBox_Click(object sender, RoutedEventArgs e) + { + Clear(); + } + + + /// + /// Raised when text inside textbox changes + /// + /// Sender object + /// Event arguments + void shortcutTextBox_TextChanged(object sender, TextChangedEventArgs e) + { + if (GestureChanged != null) { + GestureChanged.Invoke(sender, new EventArgs()); + } + } + + /// + /// Raised before user presses any key inside text box + /// + /// Sender object + /// Event argument + private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e) + { + e.Handled = true; + + // If a key is holded for a longer time key event is raised repeatedly. + // We don't want to handle this kind of events + if (e.IsRepeat) { + return; + } + + // If delete or backspace button is pressed + if (e.Key == Key.Back || e.Key == Key.Delete) { + Clear(); + return; + } + + // Check whether time given for chord entry haven't expired yet + if (DateTime.Now - lastEnterTime > MultiKeyGesture.DelayBetweenGestureInputs) { + if (enteredKeyGestureSequence.Count > 0) { + DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.TimeExpired}"), NotificationType.Invalid); + } + + Clear(); + lastEnterTime = DateTime.Now; + } + + var partialKeyGesture = new PartialKeyGesture(e); + + var lastGesture = enteredKeyGestureSequence.Count > 0 ? enteredKeyGestureSequence.LastOrDefault() : null; + var isLastGestureComplete = lastGesture != null && lastGesture.Key != Key.None; + var isContinuedGesture = lastGesture != null && partialKeyGesture.Modifiers - (partialKeyGesture.Modifiers ^ lastGesture.Modifiers) >= 0; + + // If continuing previous chord + if (!isLastGestureComplete && isContinuedGesture) + { + enteredKeyGestureSequence.RemoveAt(enteredKeyGestureSequence.Count - 1); + } + // If previous chord is unfinished and second chor is already entered + // start from scratch. + else if (!isLastGestureComplete) + { + DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.SequenceIsNotCoherent}"), NotificationType.Invalid); + Clear(); + } + + // If successfully finished another chord give more time + if (partialKeyGesture.Key != Key.None) + { + lastEnterTime = DateTime.Now; + } + + enteredKeyGestureSequence.Add(partialKeyGesture); + + // Create a multi key gesture if entered more than one chord + if (enteredKeyGestureSequence.Count > 0) + { + var multiKeyGesture = new MultiKeyGesture(enteredKeyGestureSequence); + var multiKeyGestureString = new MultiKeyGestureConverter().ConvertToInvariantString(multiKeyGesture); + shortcutTextBox.Text = multiKeyGestureString; + } + else + { + Clear(); + } + + if (enteredKeyGestureSequence[0].Modifiers == ModifierKeys.None) + { + DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.FirstChordIsIncomplete}"), NotificationType.Invalid); + } + else if (partialKeyGesture.Key == Key.None) + { + DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.LastChordIsIncomplete}"), NotificationType.Invalid); + } + else + { + DisplayNotification(StringParser.Parse("${res:ShortcutsManagement.GestureTextBox.GestureIsValid}"), NotificationType.Valid); + } + } + } +} diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/Resources.xaml b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/Resources.xaml index 0d837dda4b7..a34afe9c19a 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/Resources.xaml +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/Resources.xaml @@ -8,8 +8,7 @@ - - + @@ -21,7 +20,7 @@ - + diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutManagementWindow.xaml b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutManagementWindow.xaml index 507d2672602..501e44c9268 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutManagementWindow.xaml +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutManagementWindow.xaml @@ -1,14 +1,21 @@ - + xmlns:Dialogs="clr-namespace:ICSharpCode.ShortcutsManagement.Dialogs" + Title="{Binding Text}" + MinHeight="400" + MinWidth="400" + x:Name="_this"> + + + @@ -19,27 +26,27 @@ - + -