From a467f466cc2462bd60e7de41476bf021d614d254 Mon Sep 17 00:00:00 2001 From: Sergej Andrejev Date: Mon, 20 Jul 2009 13:17:56 +0000 Subject: [PATCH] TextArea input bindings, input binding groups and search using BindingInfoTemplate (one unit test is broken) git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/shortcuts@4502 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- AddIns/ICSharpCode.SharpDevelop.addin | 1 - .../Project/Gui/SearchAndReplaceDialog.cs | 75 +++- .../Project/SearchAndReplace.addin | 8 +- .../Project/SearchAndReplace.csproj | 4 + .../ShortcutsManagementOptionsPanel.xaml.cs | 7 +- .../ICSharpCode.AvalonEdit.Tests.csproj | 4 + .../Editing/CaretNavigationCommandHandler.cs | 15 +- .../Editing/EditingCommandHandler.cs | 27 +- .../Editing/TextAreaDefaultInputHandlers.cs | 74 +++- .../Editing/TextAreaInputHandler.cs | 35 +- .../Project/Src/Commands/MenuItemBuilders.cs | 13 +- .../Core/Project/Src/Util/ExtensionMethods.cs | 4 + .../CommandsService/BindingGroup.cs | 125 +++--- .../CommandsService/BindingGroupCollection.cs | 33 +- .../CommandsService/BindingInfoTemplate.cs | 48 +++ .../CommandsService/CommandBindingInfo.cs | 48 +-- .../CommandsService/CommandManager.cs | 367 +++++++----------- .../CommandsService/CommandsService.cs | 6 +- .../CommandsService/IBindingInfo.cs | 65 ++++ .../CommandsService/InputBindingInfo.cs | 174 ++++++--- .../ObservableInputGestureCollection.cs | 131 +++++++ .../UserDefinedGesturesManager.cs | 81 ++++ .../CommandsService/UserGesturesProfile.cs | 25 +- .../ICSharpCode.Core.Presentation.csproj | 3 + .../Menu/MenuCommand.cs | 19 +- 25 files changed, 892 insertions(+), 500 deletions(-) create mode 100644 src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingInfoTemplate.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/CommandsService/IBindingInfo.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/CommandsService/ObservableInputGestureCollection.cs diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin index 0631075401..b6ac2df33e 100644 --- a/AddIns/ICSharpCode.SharpDevelop.addin +++ b/AddIns/ICSharpCode.SharpDevelop.addin @@ -124,7 +124,6 @@ - diff --git a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplaceDialog.cs b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplaceDialog.cs index 8995109ba0..da22e2e022 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplaceDialog.cs +++ b/src/AddIns/Misc/SearchAndReplace/Project/Gui/SearchAndReplaceDialog.cs @@ -8,12 +8,16 @@ using System; using System.Drawing; using System.Windows.Forms; +using System.Windows.Input; using ICSharpCode.Core; using ICSharpCode.Core.WinForms; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.Core.Presentation; +using SDCommandManager = ICSharpCode.Core.Presentation.CommandManager; + namespace SearchAndReplace { public enum SearchAndReplaceMode { @@ -87,16 +91,12 @@ namespace SearchAndReplace SetSearchAndReplaceMode(); FormLocationHelper.Apply(this, "ICSharpCode.SharpDevelop.Gui.SearchAndReplaceDialog.Location", false); - // Register shortcuts in "search & replace" dialog - GesturePlaceHolderRegistry.RegisterUpdateHandler("SDSearchAndReplace.Find", delegate { - searchKeyboardShortcut = GesturePlaceHolderRegistry.GetGestures("SDSearchAndReplace.Find")[0]; - }); - GesturePlaceHolderRegistry.RegisterUpdateHandler("SDSearchAndReplace.Replace", delegate { - replaceKeyboardShortcut = GesturePlaceHolderRegistry.GetGestures("SDSearchAndReplace.Find")[0]; - }); + // TODO: Check how this realy should work + var searchKeys = GetKeyBoardShortcut("SDSearchAndReplace.Find"); + searchKeyboardShortcut = searchKeys.Length > 0 ? searchKeys[0] : Keys.None; - GesturePlaceHolderRegistry.InvokeUpdateHandlers("SDSearchAndReplace.Find"); - GesturePlaceHolderRegistry.InvokeUpdateHandlers("SDSearchAndReplace.FindReplace"); + var replaceKeys = GetKeyBoardShortcut("SDSearchAndReplace.Replace"); + replaceKeyboardShortcut = replaceKeys.Length > 0 ? replaceKeys[0] : Keys.None; } protected override void OnClosing(System.ComponentModel.CancelEventArgs e) @@ -105,7 +105,7 @@ namespace SearchAndReplace Instance = null; } - protected override void OnKeyDown(KeyEventArgs e) + protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e) { if (e.KeyData == Keys.Escape) { Close(); @@ -162,7 +162,62 @@ namespace SearchAndReplace } } } + return new Keys[] { Keys.None }; } + + Keys[] GetKeyBoardShortcut(string routedCommandName) + { + var gestureCollection = SDCommandManager.FindInputGestures(new BindingInfoTemplate { RoutedCommandName = routedCommandName}); + var keyCollection = new Keys[gestureCollection.Count]; + + var i = 0; + foreach(InputGesture gesture in gestureCollection) { + var keyGesture = gesture as KeyGesture; + if(!(keyGesture is MultiKeyGesture)) { // I can't imagine presenting these in WinForms + keyCollection[i++] = ConvertInputGestureToKeys(keyGesture); + } + } + + return keyCollection; + } + + Keys ConvertInputGestureToKeys(KeyGesture gesture) + { + var formsKey = Keys.None; + + var key = Key.None; + var modifiers = System.Windows.Input.ModifierKeys.None; + var partialGesture = gesture as PartialKeyGesture; + var multiKeyGesture = gesture as MultiKeyGesture; + + if(partialGesture != null) { + key = partialGesture.Key; + modifiers = partialGesture.Modifiers; + } else if(!(gesture is MultiKeyGesture)) { + key = gesture.Key; + modifiers = gesture.Modifiers; + } + + if(key != Key.None || modifiers != System.Windows.Input.ModifierKeys.None) { + formsKey |= (Keys)KeyInterop.VirtualKeyFromKey(key); + + if((modifiers & System.Windows.Input.ModifierKeys.Alt) == System.Windows.Input.ModifierKeys.Alt) { + formsKey |= Keys.Alt; + } + + if((modifiers & System.Windows.Input.ModifierKeys.Control) == System.Windows.Input.ModifierKeys.Control) { + formsKey |= Keys.Control; + } + + if((modifiers & System.Windows.Input.ModifierKeys.Shift) == System.Windows.Input.ModifierKeys.Shift) { + formsKey |= Keys.Shift; + } + + // What about "Windows" key? + } + + return formsKey; + } } } diff --git a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.addin b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.addin index 7c11629894..5c17791705 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.addin +++ b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.addin @@ -12,14 +12,14 @@ - + - + @@ -27,10 +27,6 @@ - - - - diff --git a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj index 5f315d1c68..ee2b4d7e46 100644 --- a/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj +++ b/src/AddIns/Misc/SearchAndReplace/Project/SearchAndReplace.csproj @@ -127,6 +127,10 @@ ICSharpCode.Core False + + {7E4A7172-7FF5-48D0-B719-7CD959DD1AC9} + ICSharpCode.Core.Presentation + {857CA1A3-FC88-4BE0-AB6A-D1EE772AB288} ICSharpCode.Core.WinForms diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs index a9bd584c54..2691d08720 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs @@ -193,7 +193,7 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs } } - var inputBindingInfos = CommandManager.FindInputBindingInfos(null, null, null, null); + var inputBindingInfos = CommandManager.FindInputBindingInfos(new BindingInfoTemplate()); foreach (var inputBindingInfo in inputBindingInfos) { // Get shortcut entry text. Normaly shortcut entry text is equal to routed command text @@ -210,7 +210,7 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs // Strip this sign from shortcut entry text shortcutText = Regex.Replace(shortcutText, @"&([^\s])", @"$1"); - var shortcutGestures = new InputGestureCollection(inputBindingInfo.DefaultGestures); + var shortcutGestures = inputBindingInfo.DefaultGestures.GetInputGestureCollection(); if(SelectedProfile != null && SelectedProfile[inputBindingInfo.Identifier] != null) { shortcutGestures = new InputGestureCollection(SelectedProfile[inputBindingInfo.Identifier]); } @@ -254,10 +254,7 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs } } - shortcutsMap.ForEach(b => b.Value.IsModifyed = true); - UserDefinedGesturesManager.CurrentProfile = SelectedProfile; - CommandManager.InvokeInputBindingUpdateHandlers(); profiles.ForEach(p => p.Save()); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj index 80c76fa2eb..d83119fc73 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit.Tests/ICSharpCode.AvalonEdit.Tests.csproj @@ -82,6 +82,10 @@ + + {FFA7988E-7348-4669-9E9D-27E629C873A2} + ICSharpCode.Core.Presentation.Tests + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1} ICSharpCode.AvalonEdit diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs index 9cf44bab7e..6792f20b85 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretNavigationCommandHandler.cs @@ -23,7 +23,10 @@ namespace ICSharpCode.AvalonEdit.Editing { static class CaretNavigationCommandHandler { - static BindingGroup bindingGroup; + public static BindingGroup ClassWideBindingGroup + { + get; private set; + } /// /// Creates a new for the text area. @@ -31,7 +34,7 @@ namespace ICSharpCode.AvalonEdit.Editing public static TextAreaInputHandler Create(TextArea textArea) { TextAreaInputHandler handler = new TextAreaInputHandler(textArea); - handler.BindingGroup = bindingGroup; + handler.BindingGroup = ClassWideBindingGroup; // TODO: DELETE // handler.CommandBindings.AddRange(CommandBindings); @@ -53,8 +56,8 @@ namespace ICSharpCode.AvalonEdit.Editing { var inputBinding = new InputBindingInfo(); inputBinding.OwnerTypeName = typeof(TextArea).GetShortAssemblyQualifiedName(); - inputBinding.DefaultGestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFrom(gesturesString); - inputBinding.Groups.Add(bindingGroup); + inputBinding.DefaultGestures.AddRange((InputGestureCollection)new InputGestureCollectionConverter().ConvertFrom(gesturesString)); + inputBinding.Groups.Add(ClassWideBindingGroup); inputBinding.RoutedCommandName = routedCommandName; SDCommandManager.RegisterInputBinding(inputBinding); } @@ -66,14 +69,14 @@ namespace ICSharpCode.AvalonEdit.Editing commandBinding.ExecutedEventHandler = executedHandler; commandBinding.CanExecuteEventHandler = canExecuteHandler; commandBinding.IsLazy = false; - commandBinding.Groups.Add(bindingGroup); + commandBinding.Groups.Add(ClassWideBindingGroup); commandBinding.RoutedCommandName = routedCommandName; SDCommandManager.RegisterCommandBinding(commandBinding); } static CaretNavigationCommandHandler() { - bindingGroup = new BindingGroup(); + ClassWideBindingGroup = new BindingGroup(); AddBinding("EditingCommands.MoveLeftByCharacter", "Left", null, OnMoveCaret(CaretMovementType.CharLeft)); AddBinding("EditingCommands.SelectLeftByCharacter", "Shift+Left", null, OnMoveCaretExtendSelection(CaretMovementType.CharLeft)); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs index f85578fc1c..fb41de3676 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/EditingCommandHandler.cs @@ -31,7 +31,10 @@ namespace ICSharpCode.AvalonEdit.Editing /// static class EditingCommandHandler { - static BindingGroup bindingGroup; + public static BindingGroup ClassWideBindingGroup + { + get; private set; + } /// /// Creates a new for the text area. @@ -39,19 +42,7 @@ namespace ICSharpCode.AvalonEdit.Editing public static TextAreaInputHandler Create(TextArea textArea) { TextAreaInputHandler handler = new TextAreaInputHandler(textArea); - handler.BindingGroup = bindingGroup; - - // TODO: REMOVE - - // var groups = new BindingGroupCollection { bindingGroup }; - - // var commandBindings = SDCommandManager.FindCommandBindings(null, null, null, groups); - // handler.CommandBindings.AddRange(commandBindings.Cast()); // Todo: fix later - - // var inputBindings = SDCommandManager.FindInputBindings(null, null, null, groups); - // handler.InputBindings.AddRange(inputBindings.Cast()); // Todo: fix later - - + handler.BindingGroup = ClassWideBindingGroup; return handler; } @@ -69,8 +60,8 @@ namespace ICSharpCode.AvalonEdit.Editing { var inputBinding = new InputBindingInfo(); inputBinding.OwnerTypeName = typeof(TextArea).GetShortAssemblyQualifiedName(); - inputBinding.DefaultGestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFrom(gesturesString); - inputBinding.Groups.Add(bindingGroup); + inputBinding.DefaultGestures.AddRange((InputGestureCollection)new InputGestureCollectionConverter().ConvertFrom(gesturesString)); + inputBinding.Groups.Add(ClassWideBindingGroup); inputBinding.Categories.AddRange(SDCommandManager.GetInputBindingCategoryCollection("/MainMenu/Edit", true)); inputBinding.RoutedCommandName = routedCommandName; SDCommandManager.RegisterInputBinding(inputBinding); @@ -83,14 +74,14 @@ namespace ICSharpCode.AvalonEdit.Editing commandBinding.ExecutedEventHandler = executedHandler; commandBinding.CanExecuteEventHandler = canExecuteHandler; commandBinding.IsLazy = false; - commandBinding.Groups.Add(bindingGroup); + commandBinding.Groups.Add(ClassWideBindingGroup); commandBinding.RoutedCommandName = routedCommandName; SDCommandManager.RegisterCommandBinding(commandBinding); } static EditingCommandHandler() { - bindingGroup = new BindingGroup(); + ClassWideBindingGroup = new BindingGroup(); AddCommandBinding("ApplicationCommands.Delete", CanDelete, OnDelete(ApplicationCommands.NotACommand)); AddBinding("EditingCommands.Delete", "Delete", null, OnDelete(EditingCommands.SelectRightByCharacter)); diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs index d42c1e12b0..e945d99092 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaDefaultInputHandlers.cs @@ -8,6 +8,8 @@ using System; using System.Windows.Input; using ICSharpCode.AvalonEdit.Document; +using ICSharpCode.Core.Presentation; +using SDCommandManager=ICSharpCode.Core.Presentation.CommandManager; namespace ICSharpCode.AvalonEdit.Editing { @@ -31,32 +33,76 @@ namespace ICSharpCode.AvalonEdit.Editing /// public ITextAreaInputHandler MouseSelection { get; private set; } + public static BindingGroup ClassWideBindingGroup + { + get; private set; + } + + static TextAreaDefaultInputHandler() + { + ClassWideBindingGroup = new BindingGroup(); + AddCommandBinding("ApplicationCommands.Undo", CanExecuteUndo, ExecuteUndo); + AddCommandBinding("ApplicationCommands.Redo", CanExecuteRedo, ExecuteRedo); + } + + static void AddBinding(string routedCommandName, string gesturesString, CanExecuteRoutedEventHandler canExecuteHandler, ExecutedRoutedEventHandler executedHandler) + { + AddCommandBinding(routedCommandName, canExecuteHandler, executedHandler); + AddInputBinding(routedCommandName, gesturesString); + } + + static void AddInputBinding(string routedCommandName, string gesturesString) + { + var inputBinding = new InputBindingInfo(); + inputBinding.OwnerTypeName = typeof(TextArea).GetShortAssemblyQualifiedName(); + inputBinding.DefaultGestures.AddRange((InputGestureCollection)new InputGestureCollectionConverter().ConvertFrom(gesturesString)); + inputBinding.Groups.Add(ClassWideBindingGroup); + inputBinding.Categories.AddRange(SDCommandManager.GetInputBindingCategoryCollection("/MainMenu/Edit", true)); + inputBinding.RoutedCommandName = routedCommandName; + SDCommandManager.RegisterInputBinding(inputBinding); + } + + static void AddCommandBinding(string routedCommandName, CanExecuteRoutedEventHandler canExecuteHandler, ExecutedRoutedEventHandler executedHandler) + { + var commandBinding = new CommandBindingInfo(); + commandBinding.OwnerTypeName = typeof(TextArea).GetShortAssemblyQualifiedName(); + commandBinding.ExecutedEventHandler = executedHandler; + commandBinding.CanExecuteEventHandler = canExecuteHandler; + commandBinding.IsLazy = false; + commandBinding.Groups.Add(ClassWideBindingGroup); + commandBinding.RoutedCommandName = routedCommandName; + SDCommandManager.RegisterCommandBinding(commandBinding); + } + /// /// Creates a new TextAreaDefaultInputHandler instance. /// public TextAreaDefaultInputHandler(TextArea textArea) : base(textArea) { + BindingGroup = ClassWideBindingGroup; + this.NestedInputHandlers.Add(CaretNavigation = CaretNavigationCommandHandler.Create(textArea)); this.NestedInputHandlers.Add(Editing = EditingCommandHandler.Create(textArea)); this.NestedInputHandlers.Add(MouseSelection = new SelectionMouseHandler(textArea)); - this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, ExecuteUndo, CanExecuteUndo)); - this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, ExecuteRedo, CanExecuteRedo)); + // TODO: DELETE + + // this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo, ExecuteUndo, CanExecuteUndo)); + // this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo, ExecuteRedo, CanExecuteRedo)); } #region Undo / Redo - UndoStack GetUndoStack() + static UndoStack GetUndoStack(TextArea textArea) { - TextDocument document = this.TextArea.Document; - if (document != null) - return document.UndoStack; + if (textArea != null && textArea.Document != null) + return textArea.Document.UndoStack; else return null; } - void ExecuteUndo(object sender, ExecutedRoutedEventArgs e) + static void ExecuteUndo(object sender, ExecutedRoutedEventArgs e) { - var undoStack = GetUndoStack(); + var undoStack = GetUndoStack(sender as TextArea); if (undoStack != null) { if (undoStack.CanUndo) undoStack.Undo(); @@ -64,18 +110,18 @@ namespace ICSharpCode.AvalonEdit.Editing } } - void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e) + static void CanExecuteUndo(object sender, CanExecuteRoutedEventArgs e) { - var undoStack = GetUndoStack(); + var undoStack = GetUndoStack(sender as TextArea); if (undoStack != null) { e.Handled = true; e.CanExecute = undoStack.CanUndo; } } - void ExecuteRedo(object sender, ExecutedRoutedEventArgs e) + static void ExecuteRedo(object sender, ExecutedRoutedEventArgs e) { - var undoStack = GetUndoStack(); + var undoStack = GetUndoStack(sender as TextArea); if (undoStack != null) { if (undoStack.CanRedo) undoStack.Redo(); @@ -83,9 +129,9 @@ namespace ICSharpCode.AvalonEdit.Editing } } - void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e) + static void CanExecuteRedo(object sender, CanExecuteRoutedEventArgs e) { - var undoStack = GetUndoStack(); + var undoStack = GetUndoStack(sender as TextArea); if (undoStack != null) { e.Handled = true; e.CanExecute = undoStack.CanRedo; diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs index e4e386bbf4..5da94fb3fa 100644 --- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs +++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/TextAreaInputHandler.cs @@ -51,14 +51,14 @@ namespace ICSharpCode.AvalonEdit.Editing readonly TextArea textArea; bool isAttached; - private BindingGroup m_bindingGroup; + private BindingGroup _bindingGroup; public BindingGroup BindingGroup { get { - return m_bindingGroup; + return _bindingGroup; } set { - m_bindingGroup = value; + _bindingGroup = value; } } @@ -179,12 +179,11 @@ namespace ICSharpCode.AvalonEdit.Editing BindingGroup.AttachTo(textArea); } - // TODO: REMOVE + textArea.CommandBindings.AddRange(commandBindings); + textArea.InputBindings.AddRange(inputBindings); - // textArea.CommandBindings.AddRange(commandBindings); - // textArea.InputBindings.AddRange(inputBindings); - //foreach (ITextAreaInputHandler handler in nestedInputHandlers) - // handler.Attach(); + foreach (ITextAreaInputHandler handler in nestedInputHandlers) + handler.Attach(); } /// @@ -194,16 +193,20 @@ namespace ICSharpCode.AvalonEdit.Editing throw new InvalidOperationException("Input handler is not attached"); isAttached = false; - BindingGroup.DetachFrom(textArea); + // Detach binding from textarea + if(BindingGroup != null) { + BindingGroup.DetachFrom(textArea); + } - // TODO: REMOVE + // Detach binding to specified input and command bindings + foreach (CommandBinding b in commandBindings) + textArea.CommandBindings.Remove(b); + foreach (InputBinding b in inputBindings) + textArea.InputBindings.Remove(b); - // foreach (CommandBinding b in commandBindings) - // textArea.CommandBindings.Remove(b); - // foreach (InputBinding b in inputBindings) - // textArea.InputBindings.Remove(b); - // foreach (ITextAreaInputHandler handler in nestedInputHandlers) - // handler.Detach(); + // Detach nested handlers + foreach (ITextAreaInputHandler handler in nestedInputHandlers) + handler.Detach(); } #endregion } diff --git a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs index a2c75ee850..6e87f81f3b 100644 --- a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs +++ b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs @@ -243,8 +243,12 @@ namespace ICSharpCode.SharpDevelop.Commands CommandManager.RegisterInputBinding(inputBindingInfo); } - var updatedGestures = CommandManager.FindInputGestures(CommandManager.DefaultContextName, null, routedCommandName, null); + var gesturesTemplate = new BindingInfoTemplate(); + gesturesTemplate.OwnerTypeName = CommandManager.DefaultContextName; + gesturesTemplate.RoutedCommandName = routedCommandName; + var updatedGestures = CommandManager.FindInputGestures(gesturesTemplate); var updatedGesturesText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); + items[i].InputGestureText = updatedGesturesText; items[i].Command = CommandManager.GetRoutedUICommand(routedCommandName); items[i].Header = StringParser.Parse(tool.ToString()); @@ -535,7 +539,7 @@ namespace ICSharpCode.SharpDevelop.Commands var inputBindingInfo = new InputBindingInfo(); inputBindingInfo.OwnerTypeName = CommandManager.DefaultContextName; inputBindingInfo.RoutedCommandName = routedCommandName; - inputBindingInfo.DefaultGestures = gestures; + inputBindingInfo.DefaultGestures.AddRange(gestures); var categoryPath = "/MainMenu/View" + (Category == padContent.Category && padContent.Category != "Main" ? "/" + padContent.Class : ""); @@ -554,7 +558,10 @@ namespace ICSharpCode.SharpDevelop.Commands item.Command = CommandManager.GetRoutedUICommand(routedCommandName); - var updatedGestures = CommandManager.FindInputGestures(CommandManager.DefaultContextName, null, routedCommandName, null); + var gesturesTemplate = new BindingInfoTemplate(); + gesturesTemplate.OwnerTypeName = CommandManager.DefaultContextName; + gesturesTemplate.RoutedCommandName = routedCommandName; + var updatedGestures = CommandManager.FindInputGestures(gesturesTemplate); var updatedGesturesText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); item.InputGestureText = updatedGesturesText; diff --git a/src/Main/Core/Project/Src/Util/ExtensionMethods.cs b/src/Main/Core/Project/Src/Util/ExtensionMethods.cs index 1407500813..ccc39c0656 100644 --- a/src/Main/Core/Project/Src/Util/ExtensionMethods.cs +++ b/src/Main/Core/Project/Src/Util/ExtensionMethods.cs @@ -19,6 +19,10 @@ namespace ICSharpCode.Core /// true if item is found; otherwise false public static bool ContainsAnyFromCollection(this ICollection thisCollection, ICollection otherCollection) { + if(otherCollection == null) { + throw new ArgumentNullException("otherCollection"); + } + foreach(var thisCollectionItem in thisCollection) { if(otherCollection.Contains(thisCollectionItem)) { return true; diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroup.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroup.cs index 896314467a..7217ed5f3e 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroup.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroup.cs @@ -1,11 +1,3 @@ -/* - * Created by SharpDevelop. - * User: Administrator - * Date: 7/13/2009 - * Time: 5:10 PM - * - * To change this template use Tools | Options | Coding | Edit Standard Headers. - */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -25,8 +17,7 @@ namespace ICSharpCode.Core.Presentation private ObservableCollection _inputBindings; private ObservableCollection _commandBindings; - private List _attachedNamedInstances = new List(); - private List _attachedInstances = new List(); + private HashSet _attachedInstances = new HashSet(); private List _nestedGroups = new List(); @@ -44,89 +35,72 @@ namespace ICSharpCode.Core.Presentation get; set; } - public bool IsAttachedTo(UIElement instance) + public static bool IsActive(IBindingInfo bindingInfo) { - return _attachedInstances.Contains(instance); + if(bindingInfo.OwnerInstances != null && bindingInfo.Groups != null && bindingInfo.Groups.Count > 0) { + return bindingInfo.Groups.IsAttachedToAny(bindingInfo.OwnerInstances); + } + + return true; } - public bool IsAttachedTo(string instanceName) + public bool IsAttachedTo(UIElement instance) { - return _attachedNamedInstances.Contains(instanceName); + return _attachedInstances.Contains(instance); } public void AttachTo(UIElement instance) { - if(!_attachedInstances.Contains(instance)) { - AttachToWithoutInvoke(instance); - } - } - - public void AttachTo(string instanceName) - { - if(!_attachedNamedInstances.Contains(instanceName)) { - AttachToWithoutInvoke(instanceName); - } + AttachToWithoutInvoke(instance); + InvokeBindingUpdateHandlers(instance); } private void AttachToWithoutInvoke(UIElement instance) { - if(!_attachedInstances.Contains(instance)) { - _attachedInstances.Add(instance); - - foreach(var nestedGroup in _nestedGroups) { - nestedGroup.AttachToWithoutInvoke(instance); - } - } - } - - private void AttachToWithoutInvoke(string instanceName) - { - if(!_attachedNamedInstances.Contains(instanceName)) { - _attachedNamedInstances.Add(instanceName); - - foreach(var nestedGroup in _nestedGroups) { - nestedGroup.AttachToWithoutInvoke(instanceName); - } - } + _attachedInstances.Add(instance); + + foreach(var nestedGroup in _nestedGroups) { + nestedGroup.AttachToWithoutInvoke(instance); + } } public void DetachFromWithoutInvoke(UIElement instance) { - if(_attachedInstances.Contains(instance)) { - _attachedInstances.Remove(instance); - - foreach(var nestedGroup in _nestedGroups) { - nestedGroup.DetachFrom(instance); - } - } - } - - public void DetachFromWithoutInvoke(string instanceName) - { - if(_attachedNamedInstances.Contains(instanceName)) { - _attachedNamedInstances.Remove(instanceName); - - foreach(var nestedGroup in _nestedGroups) { - nestedGroup.DetachFrom(instanceName); - } - } + _attachedInstances.Remove(instance); + + foreach(var nestedGroup in _nestedGroups) { + nestedGroup.DetachFrom(instance); + } } public void DetachFrom(UIElement instance) { - if(_attachedInstances.Contains(instance)) { - DetachFromWithoutInvoke(instance); - } + DetachFromWithoutInvoke(instance); + InvokeBindingUpdateHandlers(instance); } - public void DetachFrom(string instanceName) + private void InvokeBindingUpdateHandlers(UIElement instance) { - if(_attachedNamedInstances.Contains(instanceName)) { - DetachFromWithoutInvoke(instanceName); - - CommandManager.InvokeCommandBindingUpdateHandlers(null, instanceName); - CommandManager.InvokeInputBindingUpdateHandlers(null, instanceName); + var i = 0; + + // Invoke class wide and instance update handlers + var instanceNames = CommandManager.GetUIElementNameCollection(instance); + var typeNames = CommandManager.GetUITypeNameCollection(instance.GetType()); + + var bindingInfoTemplates = new BindingInfoTemplate[instanceNames.Count + typeNames.Count + 2]; + bindingInfoTemplates[i++] = new BindingInfoTemplate { OwnerInstances = new[] { instance }}; + bindingInfoTemplates[i++] = new BindingInfoTemplate { OwnerTypes = new[] { instance.GetType() }}; + + foreach(var instanceName in instanceNames) { + bindingInfoTemplates[i++] = new BindingInfoTemplate { OwnerInstanceName = instanceName }; } + + foreach(var typeName in typeNames) { + bindingInfoTemplates[i++] = new BindingInfoTemplate { OwnerTypeName = typeName }; + } + + CommandManager.InvokeCommandBindingUpdateHandlers(bindingInfoTemplates); + CommandManager.InvokeInputBindingUpdateHandlers(bindingInfoTemplates); } public List NestedGroups @@ -139,22 +113,19 @@ namespace ICSharpCode.Core.Presentation public ICollection FlatNestedGroups { get { - var foundNestedGroups = new List(); + var foundNestedGroups = new HashSet(); FlattenNestedGroups(this, foundNestedGroups); - return foundNestedGroups.AsReadOnly(); + return foundNestedGroups; } } - internal void FlattenNestedGroups(BindingGroup rootGroup, ICollection foundGroups) + internal void FlattenNestedGroups(BindingGroup rootGroup, HashSet foundGroups) { - if(!foundGroups.Contains(rootGroup)) { - foundGroups.Add(rootGroup); - } + foundGroups.Add(rootGroup); foreach(var nestedGroup in NestedGroups) { - if(!foundGroups.Contains(nestedGroup)) { - foundGroups.Add(nestedGroup); + if(foundGroups.Add(nestedGroup)) { FlattenNestedGroups(nestedGroup, foundGroups); } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroupCollection.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroupCollection.cs index 30852f45e5..7e91c0c9bd 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroupCollection.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingGroupCollection.cs @@ -1,16 +1,9 @@ -/* - * Created by SharpDevelop. - * User: Administrator - * Date: 7/14/2009 - * Time: 1:20 PM - * - * To change this template use Tools | Options | Coding | Edit Standard Headers. - */ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; +using System.Windows; using ICSharpCode.Core; @@ -33,19 +26,22 @@ namespace ICSharpCode.Core.Presentation public BindingGroupCollection FlatNesteGroups { get { - var flatGroups = new BindingGroupCollection(); + var flatGroups = new HashSet(); foreach(var bindingGroup in this) { bindingGroup.FlattenNestedGroups(bindingGroup, flatGroups); } - return flatGroups; + var flatBindingGroupCollection = new BindingGroupCollection(); + flatBindingGroupCollection.AddRange(flatGroups); + + return flatBindingGroupCollection; } } - public bool IsAttachedTo(string instanceName) + public bool IsAttachedTo(UIElement instance) { foreach(var bindingGroup in FlatNesteGroups) { - if(bindingGroup.IsAttachedTo(instanceName)) { + if(bindingGroup.IsAttachedTo(instance)) { return true; } } @@ -53,6 +49,19 @@ namespace ICSharpCode.Core.Presentation return false; } + public bool IsAttachedToAny(ICollection instances) + { + if(instances != null && instances.Count > 0) { + foreach(var instance in instances) { + if(IsAttachedTo(instance)) { + return true; + } + } + } + + return false; + } + public int Count { get { return _bindingGroups.Count; diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingInfoTemplate.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingInfoTemplate.cs new file mode 100644 index 0000000000..0b9468c22b --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/BindingInfoTemplate.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// Description of BindingInfoTemplate. + /// + public struct BindingInfoTemplate : IBindingInfo + { + public string OwnerInstanceName + { + get; set; + } + + public ICollection OwnerInstances + { + get; set; + } + + public string OwnerTypeName + { + get; set; + } + + public ICollection OwnerTypes + { + get; set; + } + + public string RoutedCommandName + { + get; set; + } + + public RoutedUICommand RoutedCommand + { + get; set; + } + + public BindingGroupCollection Groups + { + get; set; + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs index ae038fc288..56bd3b415d 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs @@ -11,14 +11,13 @@ namespace ICSharpCode.Core.Presentation /// /// Stores details about /// - public class CommandBindingInfo + public class CommandBindingInfo : IBindingInfo { /// /// Creates new instance of /// public CommandBindingInfo() { - IsModifyed = true; OldCommandBindings = new CommandBindingCollection(); ActiveCommandBindings = new CommandBindingCollection(); @@ -45,22 +44,18 @@ namespace ICSharpCode.Core.Presentation get; private set; } - public bool IsActive - { - get { - if(OwnerInstanceName != null && Groups != null && Groups.Count > 0) { - return Groups.IsAttachedTo(OwnerInstanceName); - } - - return true; - } - } + private string routedCommandName; /// /// Name of the routed command which will be invoked when this binding is triggered /// public string RoutedCommandName { - get; set; + get { + return routedCommandName; + } + set { + routedCommandName = value; + } } /// @@ -217,7 +212,7 @@ namespace ICSharpCode.Core.Presentation public ICollection OwnerInstances { get { if(_ownerInstanceName != null) { - return CommandManager.GetNamedUIElement(_ownerInstanceName); + return CommandManager.GetNamedUIElementCollection(_ownerInstanceName); } return null; @@ -256,12 +251,17 @@ namespace ICSharpCode.Core.Presentation public ICollection OwnerTypes { get { if(_ownerTypeName != null) { - return CommandManager.GetNamedUIType(_ownerTypeName); + return CommandManager.GetNamedUITypeCollection(_ownerTypeName); } return null; } } + + public bool IsRegistered + { + get; set; + } private BindingsUpdatedHandler defaultCommandBindingHandler; @@ -273,7 +273,7 @@ namespace ICSharpCode.Core.Presentation get { if(defaultCommandBindingHandler == null && OwnerTypeName != null) { defaultCommandBindingHandler = delegate { - if(OwnerTypes != null && IsModifyed) { + if(RoutedCommand != null && OwnerTypes != null && IsRegistered) { GenerateCommandBindings(); foreach(var ownerType in OwnerTypes) { @@ -285,13 +285,11 @@ namespace ICSharpCode.Core.Presentation System.Windows.Input.CommandManager.RegisterClassCommandBinding(ownerType, binding); } } - - IsModifyed = false; } }; } else if(defaultCommandBindingHandler == null && OwnerInstanceName != null) { defaultCommandBindingHandler = delegate { - if(OwnerInstances != null && IsModifyed) { + if(RoutedCommand != null && OwnerInstances != null && IsRegistered) { GenerateCommandBindings(); foreach(var ownerInstance in OwnerInstances) { @@ -301,8 +299,6 @@ namespace ICSharpCode.Core.Presentation ownerInstance.CommandBindings.AddRange(ActiveCommandBindings); } - - IsModifyed = false; } }; } @@ -323,14 +319,6 @@ namespace ICSharpCode.Core.Presentation get; set; } - /// - /// Indicates whether was modified. When modified - /// s are re-generated - /// - public bool IsModifyed { - get; set; - } - /// /// Re-generate from /// @@ -340,7 +328,7 @@ namespace ICSharpCode.Core.Presentation ActiveCommandBindings = new CommandBindingCollection(); - if(IsActive) { + if(BindingGroup.IsActive(this)) { var commandBinding = new CommandBinding(RoutedCommand); commandBinding.CanExecute += GenerateCanExecuteEventHandler; commandBinding.Executed += GenerateExecutedEventHandler; diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs index aed0c3aa71..4d4d4c439d 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs @@ -30,24 +30,24 @@ namespace ICSharpCode.Core.Presentation } // Binding infos - private static List commandBindings = new List(); - private static List inputBidnings = new List(); + private static HashSet commandBindings = new HashSet(); + private static HashSet inputBidnings = new HashSet(); // Commands private static Dictionary routedCommands = new Dictionary(); internal static Dictionary commands = new Dictionary(); - // Command binding update hanlers - private static Dictionary> classCommandBindingUpdateHandlers = new Dictionary>(); - private static Dictionary> instanceCommandBindingUpdateHandlers = new Dictionary>(); + // Binding update handlers + private static Dictionary> inputBindingUpdatedHandlers = new Dictionary>(); + private static Dictionary> commandBindingUpdatedHandlers = new Dictionary>(); - // Input binding update handlers - private static Dictionary> classInputBindingUpdateHandlers = new Dictionary>(); - private static Dictionary> instanceInputBindingUpdateHandlers = new Dictionary>(); - // Named instances and types - private static Dictionary> namedUIInstances = new Dictionary>(); - private static Dictionary> namedUITypes = new Dictionary>(); + private static Dictionary> namedUIInstances = new Dictionary>(); + private static Dictionary> namedUITypes = new Dictionary>(); + + // Reverse named instances and types (used to search for instance name by type) + private static Dictionary> reverseNamedUIInstances = new Dictionary>(); + private static Dictionary> reverseNamedUITypes = new Dictionary>(); // Categories public static List InputBindingCategories = new List(); @@ -60,23 +60,19 @@ namespace ICSharpCode.Core.Presentation public static void RegisterNamedUIElement(string instanceName, UIElement element) { if(!namedUIInstances.ContainsKey(instanceName)){ - namedUIInstances.Add(instanceName, new List()); + namedUIInstances.Add(instanceName, new HashSet()); } - var namedUIInstanceCollection = namedUIInstances[instanceName]; + if(!reverseNamedUIInstances.ContainsKey(element)) { + reverseNamedUIInstances.Add(element, new HashSet()); + } - if(!namedUIInstanceCollection.Contains(element)) { - namedUIInstanceCollection.Add(element); - + if(namedUIInstances[instanceName].Add(element)) { + reverseNamedUIInstances[element].Add(instanceName); // If there are some bindings and update handlers already registered, // but owner is not loaded then invoke those bindings - if(instanceCommandBindingUpdateHandlers.ContainsKey(instanceName)) { - InvokeCommandBindingUpdateHandlers(null, instanceName); - } - - if(instanceInputBindingUpdateHandlers.ContainsKey(instanceName)) { - InvokeInputBindingUpdateHandlers(null, instanceName); - } + InvokeCommandBindingUpdateHandlers(new BindingInfoTemplate { OwnerInstanceName = instanceName }); + InvokeInputBindingUpdateHandlers(new BindingInfoTemplate { OwnerInstanceName = instanceName }); } } @@ -85,12 +81,20 @@ namespace ICSharpCode.Core.Presentation /// /// Instance name /// - public static ICollection GetNamedUIElement(string instanceName) + public static ICollection GetNamedUIElementCollection(string instanceName) { - List instance; - namedUIInstances.TryGetValue(instanceName, out instance); + HashSet instances; + namedUIInstances.TryGetValue(instanceName, out instances); - return instance; + return instances ?? new HashSet(); + } + + public static ICollection GetUIElementNameCollection(UIElement instance) + { + HashSet names; + reverseNamedUIInstances.TryGetValue(instance, out names); + + return names ?? new HashSet(); } /// @@ -101,22 +105,20 @@ namespace ICSharpCode.Core.Presentation public static void RegisterNamedUIType(string typeName, Type type) { if(!namedUITypes.ContainsKey(typeName)){ - namedUITypes.Add(typeName, new List()); + namedUITypes.Add(typeName, new HashSet()); } - var namedUITypeCollection = namedUITypes[typeName]; - if(!namedUITypeCollection.Contains(type)) { - namedUITypeCollection.Add(type); + if(!reverseNamedUITypes.ContainsKey(type)) { + reverseNamedUITypes.Add(type, new HashSet()); + } + + if(namedUITypes[typeName].Add(type)) { + reverseNamedUITypes[type].Add(typeName); // If any update handlers where assigned to the type and type was not // loaded yet then invoke update handlers - if(classCommandBindingUpdateHandlers.ContainsKey(typeName)) { - InvokeCommandBindingUpdateHandlers(typeName, null); - } - - if(classInputBindingUpdateHandlers.ContainsKey(typeName)) { - InvokeInputBindingUpdateHandlers(typeName, null); - } + InvokeCommandBindingUpdateHandlers(new BindingInfoTemplate { OwnerTypeName = typeName }); + InvokeInputBindingUpdateHandlers(new BindingInfoTemplate { OwnerTypeName = typeName }); } } @@ -125,12 +127,20 @@ namespace ICSharpCode.Core.Presentation /// /// Type name /// Type - public static List GetNamedUIType(string typeName) + public static ICollection GetNamedUITypeCollection(string typeName) { - List instance; + HashSet instance; namedUITypes.TryGetValue(typeName, out instance); - return instance; + return instance ?? new HashSet(); + } + + public static ICollection GetUITypeNameCollection(Type type) + { + HashSet typeNames; + reverseNamedUITypes.TryGetValue(type, out typeNames); + + return typeNames ?? new HashSet(); } /// @@ -210,28 +220,37 @@ namespace ICSharpCode.Core.Presentation /// Input binding parameters public static void RegisterInputBinding(InputBindingInfo inputBindingInfo) { - var similarInputBinding = FindInputBindingInfos(inputBindingInfo.OwnerTypeName, inputBindingInfo.OwnerInstanceName, inputBindingInfo.RoutedCommandName, null).FirstOrDefault(); + var similarBindingTemplate = new BindingInfoTemplate(); + similarBindingTemplate.OwnerTypeName = inputBindingInfo.OwnerTypeName; + similarBindingTemplate.OwnerInstanceName = inputBindingInfo.OwnerInstanceName; + similarBindingTemplate.RoutedCommandName = inputBindingInfo.RoutedCommandName; + var similarInputBinding = FindInputBindingInfos(similarBindingTemplate).FirstOrDefault(); if(similarInputBinding != null) { foreach(InputGesture gesture in inputBindingInfo.DefaultGestures) { - if(!similarInputBinding.DefaultGestures.ContainsTemplateFor(gesture, GestureCompareMode.ExactlyMatches)) { + var existingGesture = new InputGestureCollection(similarInputBinding.DefaultGestures.ToList()); + if(!existingGesture.ContainsTemplateFor(gesture, GestureCompareMode.ExactlyMatches)) { similarInputBinding.DefaultGestures.Add(gesture); } } similarInputBinding.Categories.AddRange(inputBindingInfo.Categories); similarInputBinding.Groups.AddRange(inputBindingInfo.Groups); - - similarInputBinding.IsModifyed = true; - similarInputBinding.DefaultInputBindingHandler.Invoke(); } else { - if(inputBindingInfo.OwnerInstanceName != null || inputBindingInfo.OwnerTypeName != null) { - RegisterDefaultInputBindingHandler(inputBindingInfo); - } else { + if(inputBindingInfo.OwnerInstanceName == null && inputBindingInfo.OwnerTypeName == null) { throw new ArgumentException("Binding owner must be specified"); } + var registeredBindingTemplate = new BindingInfoTemplate(); + registeredBindingTemplate.OwnerInstanceName = inputBindingInfo.OwnerInstanceName; + registeredBindingTemplate.OwnerTypeName = inputBindingInfo.OwnerTypeName; + registeredBindingTemplate.RoutedCommandName = inputBindingInfo.RoutedCommandName; + inputBidnings.Add(inputBindingInfo); + inputBindingInfo.IsRegistered = true; + + RegisterInputBindingsUpdateHandler(registeredBindingTemplate, inputBindingInfo.DefaultInputBindingHandler); + InvokeInputBindingUpdateHandlers(registeredBindingTemplate); } } @@ -239,9 +258,9 @@ namespace ICSharpCode.Core.Presentation /// Unregister input binding /// /// Input binding parameters - public static void UnregisterInputBinding(InputBindingInfo inputBindingInfo) + public static void UnregisterInputBinding(BindingInfoTemplate template) { - var similarInputBindingInfos = FindInputBindingInfos(inputBindingInfo.OwnerTypeName, inputBindingInfo.OwnerInstanceName, inputBindingInfo.RoutedCommandName, null); + var similarInputBindingInfos = FindInputBindingInfos(template); foreach(var similarInputBindingInfo in similarInputBindingInfos) { inputBidnings.Remove(similarInputBindingInfo); @@ -271,39 +290,26 @@ namespace ICSharpCode.Core.Presentation } } - /// - /// Find input input binding infos which satisfy provided arguments - /// - /// Null arguments are ignored - /// - /// Context class full name - /// Unregister binding assigned to specific context instance - /// Routed UI command name - public static ICollection FindInputBindingInfos(string ownerTypeName, string ownerInstanceName, string routedCommandName, BindingGroupCollection bindingGroups) + public static IEnumerable FindInputBindingInfos(params BindingInfoTemplate[] templates) { - var foundBindings = new List(); - - foreach(var binding in inputBidnings) { - if(binding.RoutedCommandName == "AvalonEditCommands.ConvertToUppercase") - { - - } - - if( (ownerInstanceName == null || binding.OwnerInstanceName == ownerInstanceName) - && (ownerTypeName == null || binding.OwnerTypeName == ownerTypeName) - && (routedCommandName == null || binding.RoutedCommandName == routedCommandName) - && (bindingGroups == null || bindingGroups.ContainsAnyFromCollection(binding.Groups)) - ) { - foundBindings.Add(binding); + return FindBindingInfos(inputBidnings, templates).Cast(); + } + + private static IEnumerable FindBindingInfos(ICollection bindingInfos, params BindingInfoTemplate[] templates) + { + foreach(var binding in bindingInfos) { + foreach(var template in templates) { + if(template.IsTemplateFor(binding)) { + yield return binding; + continue; + } } } - - return foundBindings; } - public static InputBindingCollection FindInputBindings(string ownerTypeName, string ownerInstanceName, string routedCommandName, BindingGroupCollection bindingGroups) + public static InputBindingCollection FindInputBindings(params BindingInfoTemplate[] templates) { - var inputBindingInfoCollection = FindInputBindingInfos(ownerTypeName, ownerInstanceName, routedCommandName, bindingGroups); + var inputBindingInfoCollection = FindInputBindingInfos(templates); var inputBindingCollection = new InputBindingCollection(); foreach(var bindingInfo in inputBindingInfoCollection) { @@ -369,15 +375,20 @@ namespace ICSharpCode.Core.Presentation /// /// Command binding parameters public static void RegisterCommandBinding(CommandBindingInfo commandBindingInfo) { - commandBindingInfo.GenerateCommandBindings(); - - if(commandBindingInfo.OwnerInstanceName != null || commandBindingInfo.OwnerTypeName != null) { - RegisterDefaultCommandBindingHandler(commandBindingInfo); - } else { + if(commandBindingInfo.OwnerInstanceName == null && commandBindingInfo.OwnerTypeName == null) { throw new ArgumentException("Binding owner must be specified"); } + + var registeredBindingTemplate = new BindingInfoTemplate(); + registeredBindingTemplate.OwnerInstanceName = commandBindingInfo.OwnerInstanceName; + registeredBindingTemplate.OwnerTypeName = commandBindingInfo.OwnerTypeName; + registeredBindingTemplate.RoutedCommandName = commandBindingInfo.RoutedCommandName; commandBindings.Add(commandBindingInfo); + commandBindingInfo.IsRegistered = true; + + RegisterInputBindingsUpdateHandler(registeredBindingTemplate, commandBindingInfo.DefaultCommandBindingHandler); + InvokeInputBindingUpdateHandlers(registeredBindingTemplate); } /// @@ -385,7 +396,11 @@ namespace ICSharpCode.Core.Presentation /// /// Command binding parameters public static void UnregisterCommandBinding(CommandBindingInfo commandBindingInfo) { - var similarCommandBindingInfos = FindCommandBindingInfos(commandBindingInfo.OwnerTypeName, commandBindingInfo.OwnerInstanceName, commandBindingInfo.RoutedCommandName, null); + var template = new BindingInfoTemplate(); + template.OwnerTypeName = commandBindingInfo.OwnerTypeName; + template.OwnerInstanceName = commandBindingInfo.OwnerInstanceName; + template.RoutedCommandName = commandBindingInfo.RoutedCommandName; + var similarCommandBindingInfos = FindCommandBindingInfos(template); foreach(var similarCommandBindingInfo in similarCommandBindingInfos) { commandBindings.Remove(similarCommandBindingInfo); @@ -415,130 +430,64 @@ namespace ICSharpCode.Core.Presentation } } - #region Register bindings update handler - - /// - /// Register command binding update handler which is triggered when input bindings associated - /// with specified type change - /// - /// Owner type name - /// Update handler - public static void RegisterClassCommandBindingsUpdateHandler(string ownerTypeName, BindingsUpdatedHandler handler) + #region Update handlers + + private static void RegisterBindingsUpdateHandler(Dictionary> bindingUpdateHandlersDictionary, IBindingInfo template, BindingsUpdatedHandler handler) { - if(!classCommandBindingUpdateHandlers.ContainsKey(ownerTypeName)) { - classCommandBindingUpdateHandlers.Add(ownerTypeName, new List()); + if(!bindingUpdateHandlersDictionary.ContainsKey(template)) { + bindingUpdateHandlersDictionary.Add(template, new HashSet()); } - if(!classCommandBindingUpdateHandlers[ownerTypeName].Contains(handler)) { - classCommandBindingUpdateHandlers[ownerTypeName].Add(handler); - } + bindingUpdateHandlersDictionary[template].Add(handler); } /// /// Register command binding update handler which is triggered when input bindings associated - /// with specified instance change - /// - /// Owner instance name - /// Update handler - public static void RegisterInstanceCommandBindingsUpdateHandler(string instanceName, BindingsUpdatedHandler handler) - { - if(!instanceCommandBindingUpdateHandlers.ContainsKey(instanceName)) { - instanceCommandBindingUpdateHandlers.Add(instanceName, new List()); - } - - instanceCommandBindingUpdateHandlers[instanceName].Add(handler); - } - - /// - /// Register input binding update handler which is triggered when input bindings associated /// with specified type change /// /// Owner type name /// Update handler - public static void RegisterClassInputBindingsUpdateHandler(string ownerTypeName, BindingsUpdatedHandler handler) + public static void RegisterCommandBindingsUpdateHandler(IBindingInfo template, BindingsUpdatedHandler handler) { - if(!classInputBindingUpdateHandlers.ContainsKey(ownerTypeName)) { - classInputBindingUpdateHandlers.Add(ownerTypeName, new List()); - } - - if(!classInputBindingUpdateHandlers[ownerTypeName].Contains(handler)) { - classInputBindingUpdateHandlers[ownerTypeName].Add(handler); - } + RegisterBindingsUpdateHandler(commandBindingUpdatedHandlers, template, handler); } + /// - /// Register input binding update handler which is triggered when input bindings associated - /// with specified instance change + /// Register command binding update handler which is triggered when input bindings associated + /// with specified type change /// - /// Owner instance name + /// Owner type name /// Update handler - public static void RegisterInstanceInputBindingsUpdateHandler(string instanceName, BindingsUpdatedHandler handler) + public static void RegisterInputBindingsUpdateHandler(IBindingInfo template, BindingsUpdatedHandler handler) { - if(!instanceInputBindingUpdateHandlers.ContainsKey(instanceName)) { - instanceInputBindingUpdateHandlers.Add(instanceName, new List()); - } - - instanceInputBindingUpdateHandlers[instanceName].Add(handler); + RegisterBindingsUpdateHandler(inputBindingUpdatedHandlers, template, handler); } - - #endregion - - #region Invoke binding update handlers - private static void InvokeBindingUpdateHandlers(Dictionary> updateHandlerDictionary, string ownertName) + private static void InvokeBindingUpdateHandlers(Dictionary> updateHandlerDictionary, params BindingInfoTemplate[] templates) { - if(ownertName != null && updateHandlerDictionary[ownertName] != null) { - foreach(var handler in updateHandlerDictionary[ownertName]) { - if(handler != null) { - handler.Invoke(); + foreach(var updateHandlerPair in updateHandlerDictionary) { + foreach(var template in templates) { + if(template.IsTemplateFor(updateHandlerPair.Key)) { + foreach(var handler in updateHandlerPair.Value) { + if(handler != null) { + handler.Invoke(); + } + } } } } } - private static void InvokeAllBindingUpdateHandlers(System.Collections.IDictionary updateHandlers) + public static void InvokeCommandBindingUpdateHandlers(params BindingInfoTemplate[] templates) { - foreach(DictionaryEntry updateHandlerPair in updateHandlers) { - var handlers = (List)updateHandlerPair.Value; - - if(handlers != null) { - foreach(var handler in handlers) { - if(handler != null) { - handler.Invoke(); - } - } - } - } + InvokeBindingUpdateHandlers(commandBindingUpdatedHandlers, templates); } - public static void InvokeCommandBindingUpdateHandlers() { - InvokeAllBindingUpdateHandlers(classCommandBindingUpdateHandlers); - InvokeAllBindingUpdateHandlers(instanceCommandBindingUpdateHandlers); - } - - public static void InvokeInputBindingUpdateHandlers() { - InvokeAllBindingUpdateHandlers(classInputBindingUpdateHandlers); - InvokeAllBindingUpdateHandlers(instanceInputBindingUpdateHandlers); - } - - /// - /// Invoke all inbut binding update handlers - /// - public static void InvokeInputBindingUpdateHandlers(string ownertTypeName, string ownerInstanceName) + public static void InvokeInputBindingUpdateHandlers(params BindingInfoTemplate[] templates) { - InvokeBindingUpdateHandlers(classInputBindingUpdateHandlers, ownertTypeName); - InvokeBindingUpdateHandlers(instanceInputBindingUpdateHandlers, ownerInstanceName); + InvokeBindingUpdateHandlers(inputBindingUpdatedHandlers, templates); } - - /// - /// Invoke all command binding update handlers - /// - public static void InvokeCommandBindingUpdateHandlers(string ownertTypeName, string ownerInstanceName) - { - InvokeBindingUpdateHandlers(classCommandBindingUpdateHandlers, ownertTypeName); - InvokeBindingUpdateHandlers(instanceCommandBindingUpdateHandlers, ownerInstanceName); - } - #endregion /// @@ -546,7 +495,7 @@ namespace ICSharpCode.Core.Presentation /// /// Add-in public static void LoadAddinCommands(AddIn addIn) { - foreach(var binding in commandBindings) { + foreach(CommandBindingInfo binding in commandBindings) { if(binding.AddIn != addIn) continue; if(binding.CommandTypeName != null && !commands.ContainsKey(binding.CommandTypeName)){ @@ -588,26 +537,14 @@ namespace ICSharpCode.Core.Presentation /// Context class full name /// Context class full name /// Collection of managed command bindings - public static ICollection FindCommandBindingInfos(string ownerTypeName, string ownerInstanceName, string routedCommandName, BindingGroupCollection bindingGroups) + public static IEnumerable FindCommandBindingInfos(params BindingInfoTemplate[] templates) { - var foundBindings = new List(); - - foreach(var binding in commandBindings) { - if( (ownerInstanceName == null || binding.OwnerInstanceName == ownerInstanceName) - && (ownerTypeName == null || binding.OwnerTypeName == ownerTypeName) - && (routedCommandName == null || binding.RoutedCommandName == routedCommandName) - && (bindingGroups == null || bindingGroups.ContainsAnyFromCollection(binding.Groups)) - ) { - foundBindings.Add(binding); - } - } - - return foundBindings; + return FindBindingInfos(commandBindings, templates).Cast(); } - public static CommandBindingCollection FindCommandBindings(string ownerTypeName, string ownerInstanceName, string routedCommandName, BindingGroupCollection bindingGroups) + public static CommandBindingCollection FindCommandBindings(params BindingInfoTemplate[] templates) { - var commandBindingInfoCollection = FindCommandBindingInfos(ownerTypeName, ownerInstanceName, routedCommandName, bindingGroups); + var commandBindingInfoCollection = FindCommandBindingInfos(templates); var commandBindingCollection = new CommandBindingCollection(); foreach(var bindingInfo in commandBindingInfoCollection) { commandBindingCollection.AddRange(bindingInfo.ActiveCommandBindings); @@ -625,12 +562,12 @@ namespace ICSharpCode.Core.Presentation /// Get gestures assigned only to specific context /// Routed UI command name /// Gesture - public static InputGestureCollection FindInputGestures(string ownerTypeName, string ownerInstanceName, string routedCommandName, BindingGroupCollection bindingGroups) { - var bindings = FindInputBindingInfos(ownerTypeName, ownerInstanceName, routedCommandName, bindingGroups); + public static InputGestureCollection FindInputGestures(params BindingInfoTemplate[] templates) { + var bindings = FindInputBindingInfos(templates); var gestures = new InputGestureCollection(); foreach(InputBindingInfo bindingInfo in bindings) { - if(bindingInfo.ActiveGestures != null && bindingInfo.IsActive) { + if(bindingInfo.ActiveGestures != null) { foreach(InputGesture gesture in bindingInfo.ActiveGestures) { if(!gestures.ContainsTemplateFor(gesture, GestureCompareMode.ExactlyMatches)) { gestures.Add(gesture); @@ -700,42 +637,6 @@ namespace ICSharpCode.Core.Presentation InputBindingCategories.Add(category); } - /// - /// Register default command binding update hander which will keep instance or type command - /// bindings upated - /// - /// Command binding info - private static void RegisterDefaultCommandBindingHandler(CommandBindingInfo commandBindingInfo) - { - if(commandBindingInfo.DefaultCommandBindingHandler != null) { - commandBindingInfo.DefaultCommandBindingHandler.Invoke(); - } - - if(commandBindingInfo.OwnerInstanceName != null) { - RegisterInstanceCommandBindingsUpdateHandler(commandBindingInfo.OwnerInstanceName, commandBindingInfo.DefaultCommandBindingHandler); - } else if(commandBindingInfo.OwnerTypeName != null) { - RegisterClassCommandBindingsUpdateHandler(commandBindingInfo.OwnerTypeName, commandBindingInfo.DefaultCommandBindingHandler); - } - } - - - /// - /// Register default input binding update hander which will keep instance or type command - /// bindings upated - /// - /// Input binding info - private static void RegisterDefaultInputBindingHandler(InputBindingInfo inputBindingInfo) - { - if(inputBindingInfo.DefaultInputBindingHandler != null) { - inputBindingInfo.DefaultInputBindingHandler.Invoke(); - } - - if(inputBindingInfo.OwnerInstanceName != null) { - RegisterInstanceInputBindingsUpdateHandler(inputBindingInfo.OwnerInstanceName, inputBindingInfo.DefaultInputBindingHandler); - } else if(inputBindingInfo.OwnerTypeName != null) { - RegisterClassInputBindingsUpdateHandler(inputBindingInfo.OwnerTypeName, inputBindingInfo.DefaultInputBindingHandler); - } - } } public static class TypeExtensions diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs index 7ee6e606a1..21fee96d82 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs @@ -161,7 +161,7 @@ namespace ICSharpCode.Core.Presentation var descriptors = AddInTree.BuildItems(path, caller, false); foreach(var desc in descriptors) { var commandBindingInfoName = new StringBuilder(); - + // If routed with such name is not registered register routed command with text same as name if(CommandManager.GetRoutedUICommand(desc.Command) == null) { var commandText = string.IsNullOrEmpty(desc.CommandText) ? desc.Command : desc.CommandText; @@ -200,7 +200,7 @@ namespace ICSharpCode.Core.Presentation inputBindingInfo.AddIn = desc.Codon.AddIn; inputBindingInfo.RoutedCommandName = desc.Command; - inputBindingInfo.DefaultGestures = gestures; + inputBindingInfo.DefaultGestures.AddRange(gestures); if(!string.IsNullOrEmpty(desc.CommandText)) { inputBindingInfo.RoutedCommandText = desc.CommandText; @@ -234,7 +234,7 @@ namespace ICSharpCode.Core.Presentation inputBindingInfo.AddIn = desc.Codon.AddIn; inputBindingInfo.RoutedCommandName = desc.Command; - inputBindingInfo.DefaultGestures = gestures; + inputBindingInfo.DefaultGestures.AddRange(gestures); if(!string.IsNullOrEmpty(desc.CommandText)) { inputBindingInfo.RoutedCommandText = desc.CommandText; diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/IBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/IBindingInfo.cs new file mode 100644 index 0000000000..a87fd607a8 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/IBindingInfo.cs @@ -0,0 +1,65 @@ +/* + * Created by SharpDevelop. + * User: Sergej Andrejev + * Date: 7/17/2009 + * Time: 10:55 AM + */ +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; + +namespace ICSharpCode.Core.Presentation +{ + public interface IBindingInfo + { + string OwnerInstanceName + { + get; set; + } + + ICollection OwnerInstances + { + get; + } + + string OwnerTypeName + { + get; set; + } + + ICollection OwnerTypes + { + get; + } + + string RoutedCommandName + { + get; + } + + RoutedUICommand RoutedCommand + { + get; + } + + BindingGroupCollection Groups + { + get; + } + } + + + public static class IBindingInfoExtensions + { + public static bool IsTemplateFor(this IBindingInfo template, IBindingInfo binding) + { + return (template.OwnerInstanceName == null || template.OwnerInstanceName == binding.OwnerInstanceName) + && (template.OwnerInstances == null || (binding.OwnerInstances != null && template.OwnerInstances.ContainsAnyFromCollection(binding.OwnerInstances))) + && (template.OwnerTypeName == null || template.OwnerTypeName == binding.OwnerTypeName) + && (template.OwnerTypes == null || (binding.OwnerTypes != null && template.OwnerTypes.ContainsAnyFromCollection(binding.OwnerTypes))) + && (template.RoutedCommandName == null || template.RoutedCommandName == binding.RoutedCommandName) + && (template.RoutedCommand == null || template.RoutedCommand == binding.RoutedCommand); + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs index 82d02bd399..b0c5e187b3 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs @@ -3,58 +3,33 @@ using System.Windows; using System.Windows.Input; using System.Collections.Generic; using System.Collections.Specialized; +using System.Collections.ObjectModel; namespace ICSharpCode.Core.Presentation { /// /// Stores details about input binding /// - public class InputBindingInfo + public class InputBindingInfo : IBindingInfo { /// /// Creates new instance of /// public InputBindingInfo() { - IsModifyed = true; OldInputBindings = new InputBindingCollection(); ActiveInputBindings = new InputBindingCollection(); - DefaultGestures = new InputGestureCollection(); + DefaultGestures = new ObservableInputGestureCollection(); Categories = new InputBindingCategoryCollection(); Groups = new BindingGroupCollection(); Groups.CollectionChanged += Groups_CollectionChanged; } - private void Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - if(e.OldItems != null) { - foreach(BindingGroup oldGroup in e.OldItems) { - oldGroup.InputBindings.Remove(this); - } - } - - if(e.NewItems != null) { - foreach(BindingGroup oldGroup in e.NewItems) { - oldGroup.InputBindings.Add(this); - } - } - } - public BindingGroupCollection Groups { get; private set; } - public bool IsActive - { - get { - if(OwnerInstanceName != null && Groups != null && Groups.Count > 0) { - return Groups.IsAttachedTo(OwnerInstanceName); - } - - return true; - } - } - public string _ownerInstanceName; /// @@ -69,11 +44,15 @@ namespace ICSharpCode.Core.Presentation return _ownerInstanceName; } set { + var backup = _ownerInstanceName; + if(_ownerInstanceName != null || _ownerTypeName != null) { throw new ArgumentException("This binding already has an owner"); } _ownerInstanceName = value; + + SetActiveGesturesChanged(RoutedCommandName, _ownerTypeName, OwnerTypeName); } } @@ -87,7 +66,7 @@ namespace ICSharpCode.Core.Presentation public ICollection OwnerInstances { get { if(_ownerInstanceName != null) { - return CommandManager.GetNamedUIElement(_ownerInstanceName); + return CommandManager.GetNamedUIElementCollection(_ownerInstanceName); } return null; @@ -103,16 +82,20 @@ namespace ICSharpCode.Core.Presentation /// If this attribute is used , and /// can not be set /// - public string OwnerTypeName{ + public string OwnerTypeName + { get { return _ownerTypeName; } set { + var backup = _ownerTypeName; + if(_ownerInstanceName != null || _ownerTypeName != null) { throw new ArgumentException("This binding already has an owner"); } _ownerTypeName = value; + SetActiveGesturesChanged(RoutedCommandName, OwnerInstanceName, _ownerTypeName); } } @@ -126,7 +109,7 @@ namespace ICSharpCode.Core.Presentation public ICollection OwnerTypes { get { if(_ownerTypeName != null) { - return CommandManager.GetNamedUIType(_ownerTypeName); + return CommandManager.GetNamedUITypeCollection(_ownerTypeName); } return null; @@ -150,17 +133,38 @@ namespace ICSharpCode.Core.Presentation get; set; } - private InputGestureCollection _defaultGestures; + private ObservableInputGestureCollection _defaultGestures; /// /// Gestures which triggers this binding /// - public InputGestureCollection DefaultGestures { + public ObservableInputGestureCollection DefaultGestures { get { return _defaultGestures; } set { _defaultGestures = value; + + if(value != null) + { + _defaultGestures.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e) { + // Check for active profile but no custom shortcut + if(UserDefinedGesturesManager.CurrentProfile == null) { + var innerArgs = new InputBindingGesturesChangedArgs(); + innerArgs.InputBindingIdentifier = Identifier; + + ActiveGesturesChanged(this, innerArgs); + } + }; + } + + if(routedCommandName != null && (_ownerInstanceName != null || _ownerTypeName != null)) { + var args = new InputBindingGesturesChangedArgs(); + args.InputBindingIdentifier = Identifier; + if(UserDefinedGesturesManager.CurrentProfile == null) { + ActiveGesturesChanged(this, args); + } + } } } @@ -171,18 +175,27 @@ namespace ICSharpCode.Core.Presentation get { if(UserDefinedGesturesManager.CurrentProfile == null || UserDefinedGesturesManager.CurrentProfile[Identifier] == null) { - return DefaultGestures; + return DefaultGestures.GetInputGestureCollection(); } return UserDefinedGesturesManager.CurrentProfile[Identifier]; } } + private string routedCommandName; + /// /// Name of the routed command which will be invoked when this binding is triggered /// public string RoutedCommandName { - get; set; + get { + return routedCommandName; + } + set { + var backup = routedCommandName; + routedCommandName = value; + SetActiveGesturesChanged(backup, OwnerInstanceName, OwnerTypeName); + } } /// @@ -201,23 +214,67 @@ namespace ICSharpCode.Core.Presentation get; private set; } + + public bool IsRegistered + { + get; set; + } + + public event ActiveInputBindingsChangedHandler ActiveInputBindingsChanged; + /// - /// Indicates whether was modified. When modified - /// s are re-generated + /// New input bindings are assigned to owner when is modified /// - public bool IsModifyed { + public InputBindingCollection ActiveInputBindings + { get; set; } + public InputBindingIdentifier Identifier { + get { + var identifier = new InputBindingIdentifier(); + identifier.OwnerInstanceName = OwnerInstanceName; + identifier.OwnerTypeName = OwnerTypeName; + identifier.RoutedCommandName = RoutedCommandName; + + return identifier; + } + } + + private void Groups_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if(e.OldItems != null) { + foreach(BindingGroup oldGroup in e.OldItems) { + oldGroup.InputBindings.Remove(this); + } + } + + if(e.NewItems != null) { + foreach(BindingGroup oldGroup in e.NewItems) { + oldGroup.InputBindings.Add(this); + } + } + } + + private void ActiveGesturesChanged(object sender, InputBindingGesturesChangedArgs args) + { + var template = new BindingInfoTemplate(); + template.OwnerInstanceName = OwnerInstanceName; + template.OwnerTypeName = OwnerTypeName; + template.RoutedCommandName = RoutedCommandName; + + CommandManager.InvokeInputBindingUpdateHandlers(template); + } + /// /// Re-generate from /// - public void GenerateInputBindings() + private void GenerateInputBindings() { OldInputBindings = ActiveInputBindings; ActiveInputBindings = new InputBindingCollection(); - if(ActiveGestures != null && IsActive) { + if(ActiveGestures != null && BindingGroup.IsActive(this)) { foreach(InputGesture gesture in ActiveGestures) { var inputBinding = new InputBinding(RoutedCommand, gesture); ActiveInputBindings.Add(inputBinding); @@ -236,7 +293,7 @@ namespace ICSharpCode.Core.Presentation get { if(defaultInputBindingHandler == null && OwnerTypeName != null) { defaultInputBindingHandler = delegate { - if(OwnerTypes != null && IsModifyed) { + if(RoutedCommand != null && OwnerTypes != null && IsRegistered) { GenerateInputBindings(); foreach(var ownerType in OwnerTypes) { @@ -251,12 +308,14 @@ namespace ICSharpCode.Core.Presentation CommandManager.OrderClassInputBindingsByChords(ownerType); } - IsModifyed = false; + if(ActiveInputBindingsChanged != null) { + ActiveInputBindingsChanged.Invoke(this); + } } }; } else if(defaultInputBindingHandler == null && OwnerInstanceName != null){ defaultInputBindingHandler = delegate { - if(OwnerInstances != null && IsModifyed) { + if(RoutedCommand != null && OwnerInstances != null && IsRegistered) { GenerateInputBindings(); foreach(var ownerInstance in OwnerInstances) { @@ -268,8 +327,6 @@ namespace ICSharpCode.Core.Presentation CommandManager.OrderInstanceInputBindingsByChords(ownerInstance); } - - IsModifyed = false; } }; } @@ -289,22 +346,19 @@ namespace ICSharpCode.Core.Presentation get; set; } - /// - /// New input bindings are assigned to owner when is modified - /// - public InputBindingCollection ActiveInputBindings + private void SetActiveGesturesChanged(string oldRoutedCommandName, string oldOwnerInstanceName, string oldOwnerTypeName) { - get; set; - } - - public InputBindingIdentifier Identifier { - get { - var identifier = new InputBindingIdentifier(); - identifier.OwnerInstanceName = OwnerInstanceName; - identifier.OwnerTypeName = OwnerTypeName; - identifier.RoutedCommandName = RoutedCommandName; + if(oldRoutedCommandName != null && (oldOwnerInstanceName != null || oldOwnerTypeName != null)) { + var oldIdentifier = new InputBindingIdentifier(); + oldIdentifier.OwnerInstanceName = oldOwnerInstanceName; + oldIdentifier.OwnerTypeName = oldOwnerTypeName; + oldIdentifier.RoutedCommandName = oldRoutedCommandName; - return identifier; + UserDefinedGesturesManager.RemoveActiveGesturesChangedHandler(oldIdentifier, ActiveGesturesChanged); + } + + if(RoutedCommandName != null && (OwnerInstanceName != null || OwnerTypeName != null)) { + UserDefinedGesturesManager.AddActiveGesturesChangedHandler(Identifier, ActiveGesturesChanged); } } } @@ -324,4 +378,6 @@ namespace ICSharpCode.Core.Presentation get; set; } } + + public delegate void ActiveInputBindingsChangedHandler(InputBindingInfo inputBindingInfo); } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/ObservableInputGestureCollection.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/ObservableInputGestureCollection.cs new file mode 100644 index 0000000000..3e084cb37b --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/ObservableInputGestureCollection.cs @@ -0,0 +1,131 @@ +/* + * Created by SharpDevelop. + * User: Sergej Andrejev + * Date: 7/17/2009 + * Time: 8:56 AM + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Windows.Input; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// Description of ObservableInputBindingCollection. + /// + public class ObservableInputGestureCollection : IList, IEnumerable, ICollection + { + private ObservableCollection observedInputGestures; + + 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 { + return observedInputGestures[index]; + } + set { + observedInputGestures[index] = value; + } + } + + public bool IsReadOnly + { + get { + return false; + } + } + + public int Count + { + get { + return observedInputGestures.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 InputGestureCollection GetInputGestureCollection() + { + return new InputGestureCollection(observedInputGestures); + } + + public void AddRange(InputGestureCollection items) + { + foreach(InputGesture item in items) { + Add(item); + } + } + + public void AddRange(IEnumerable items) + { + foreach(InputGesture item in items) { + 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) { + CollectionChanged.Invoke(sender, e); + } + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserDefinedGesturesManager.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserDefinedGesturesManager.cs index 3a49d37a94..1178d663c5 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserDefinedGesturesManager.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserDefinedGesturesManager.cs @@ -21,6 +21,8 @@ namespace ICSharpCode.Core.Presentation Directory.CreateDirectory(_userGestureProfilesDirectory); } } + + CurrentProfileChanged += CurrentProfile_CurrentProfileChanged; } /// @@ -36,6 +38,35 @@ namespace ICSharpCode.Core.Presentation private static UserGesturesProfile _currentProfile; private static bool _isCurrentProfileLoaded; + public static event UserGestureProfileChangedHandler CurrentProfileChanged; + private static Dictionary> ActiveGesturesChangedHandlers = new Dictionary>(); + + public static void AddActiveGesturesChangedHandler(InputBindingIdentifier identifier, InputBindingGesturesChangedHandler handler) + { + if(!ActiveGesturesChangedHandlers.ContainsKey(identifier)) { + ActiveGesturesChangedHandlers.Add(identifier, new HashSet()); + } + + ActiveGesturesChangedHandlers[identifier].Add(handler); + } + + public static void RemoveActiveGesturesChangedHandler(InputBindingIdentifier identifier, InputBindingGesturesChangedHandler handler) + { + if(ActiveGesturesChangedHandlers.ContainsKey(identifier)) { + ActiveGesturesChangedHandlers[identifier].Remove(handler); + } + } + + private static void InvokeActiveGesturesChangedHandlers(InputBindingIdentifier identifier) + { + var args = new InputBindingGesturesChangedArgs { InputBindingIdentifier = identifier }; + if(ActiveGesturesChangedHandlers.ContainsKey(identifier)) { + foreach(var handler in ActiveGesturesChangedHandlers[identifier]) { + handler.Invoke(typeof(UserDefinedGesturesManager), args); + } + } + } + public static UserGesturesProfile CurrentProfile { get { @@ -48,6 +79,12 @@ namespace ICSharpCode.Core.Presentation profile.Load(); _currentProfile = profile; + + if(CurrentProfileChanged != null) { + var args = new UserGestureProfileChangedArgs(); + args.NewProfile = profile; + CurrentProfileChanged.Invoke(typeof(UserDefinedGesturesManager), args); + } } _isCurrentProfileLoaded = true; @@ -56,8 +93,16 @@ namespace ICSharpCode.Core.Presentation return _currentProfile; } set { + var currentProfileBackup = _currentProfile; _currentProfile = value; + if(_currentProfile != currentProfileBackup && CurrentProfileChanged != null) { + var args = new UserGestureProfileChangedArgs(); + args.NewProfile = _currentProfile; + args.OldProfile = currentProfileBackup; + CurrentProfileChanged.Invoke(typeof(UserDefinedGesturesManager), args); + } + var currentProfilePath = value != null ? value.Path : null; if(currentProfilePath != null) { @@ -69,5 +114,41 @@ namespace ICSharpCode.Core.Presentation _isCurrentProfileLoaded = true; } } + + private static void CurrentProfile_CurrentProfileChanged(object sender, UserGestureProfileChangedArgs args) { + var identifiers = new HashSet(); + + if(args.OldProfile != null) { + foreach(var gesture in args.OldProfile) { + identifiers.Add(gesture.Key); + } + } + + if(args.NewProfile != null) { + foreach(var gesture in args.NewProfile) { + identifiers.Add(gesture.Key); + } + } + + foreach(var identifier in identifiers) { + InvokeActiveGesturesChangedHandlers(identifier); + } + } + } + + public class UserGestureProfileChangedArgs + { + public UserGesturesProfile OldProfile + { + get; set; + } + + public UserGesturesProfile NewProfile + { + get; set; + } } + + public delegate void UserGestureProfileChangedHandler(object sender, UserGestureProfileChangedArgs args); + } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserGesturesProfile.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserGesturesProfile.cs index 1fa1a42f5c..674dd5d147 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserGesturesProfile.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/UserGesturesProfile.cs @@ -10,10 +10,10 @@ using System; using System.Xml; using System.Windows.Input; using System.Collections.Generic; +using System.Collections.ObjectModel; namespace ICSharpCode.Core.Presentation { - /// /// Description of UserGesturesProfile. /// @@ -141,8 +141,17 @@ namespace ICSharpCode.Core.Presentation xmlDocument.Save(Path); } + public event InputBindingGesturesChangedHandler InputBindingGesturesChanged; + public void Clear() { + if(InputBindingGesturesChanged != null) { + var identifiers = new List(); + foreach(var userDefinedGesture in userDefinedGestures) { + InputBindingGesturesChanged.Invoke(this, new InputBindingGesturesChangedArgs { InputBindingIdentifier = userDefinedGesture.Key}); + } + } + userDefinedGestures.Clear(); } @@ -172,6 +181,10 @@ namespace ICSharpCode.Core.Presentation /// Gesture assigned to this input binding private void SetInputBindingGestures(InputBindingIdentifier identifier, InputGestureCollection inputGestureCollection) { + if(InputBindingGesturesChanged != null) { + InputBindingGesturesChanged.Invoke(this, new InputBindingGesturesChangedArgs { InputBindingIdentifier = identifier}); + } + userDefinedGestures[identifier] = inputGestureCollection; } @@ -196,4 +209,14 @@ namespace ICSharpCode.Core.Presentation return profile; } } + + public class InputBindingGesturesChangedArgs + { + public InputBindingIdentifier InputBindingIdentifier + { + get; set; + } + } + + public delegate void InputBindingGesturesChangedHandler(object sender, InputBindingGesturesChangedArgs args); } diff --git a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj index c770330022..024757e1cf 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj +++ b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj @@ -69,14 +69,17 @@ + + + diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs index 1e1cd494fb..0cd88359e2 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs @@ -130,20 +130,27 @@ namespace ICSharpCode.Core.Presentation var routedCommand = CommandManager.GetRoutedUICommand(routedCommandName); if(routedCommand != null) { this.Command = routedCommand; - } else - { - Console.WriteLine(routedCommandName); } // Register input bindings update handler BindingsUpdatedHandler gesturesUpdateHandler = delegate { - var updatedGestures = CommandManager.FindInputGestures(null, null, routedCommandName, null); + var gesturesTemplate = new BindingInfoTemplate(); + gesturesTemplate.RoutedCommandName = routedCommandName; + var updatedGestures = CommandManager.FindInputGestures(gesturesTemplate); this.InputGestureText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); }; - gesturesUpdateHandler.Invoke(); - CommandManager.RegisterClassInputBindingsUpdateHandler(CommandManager.DefaultContextName, gesturesUpdateHandler); + + var bindingTemplate = new BindingInfoTemplate(); + if(codon.Properties.Contains("ownerinstance")) { + bindingTemplate.OwnerInstanceName = codon.Properties["ownerinstance"]; + } else if(codon.Properties.Contains("ownertype")) { + bindingTemplate.OwnerTypeName = codon.Properties["ownertype"]; + } + bindingTemplate.RoutedCommandName = routedCommandName; + + CommandManager.RegisterInputBindingsUpdateHandler(bindingTemplate, gesturesUpdateHandler); } } }