From d7f200ab017c45944efecad2e275aee2c5f69a87 Mon Sep 17 00:00:00 2001 From: Sergej Andrejev Date: Tue, 16 Jun 2009 20:29:40 +0000 Subject: [PATCH] Add support of bindings associated with whole type. Add named types and instances. Named instances and types can be used before the instance or class associated with the name is loaded git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/shortcuts@4314 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- AddIns/ICSharpCode.SharpDevelop.addin | 4 +- .../AvalonEdit.AddIn/Src/CodeEditor.cs | 21 +- .../ShortcutsManagement.suo | Bin 93696 -> 93696 bytes .../ShortcutsManagementOptionsPanel.xaml.cs | 11 +- .../Project/Src/Commands/MenuItemBuilders.cs | 18 +- .../Gui/Workbench/Layouts/AvalonPadContent.cs | 19 +- .../Layouts/AvalonWorkbenchWindow.cs | 20 +- .../Project/Src/Gui/Workbench/WpfWorkbench.cs | 25 +- .../Command/CommandBindingDescriptor.cs | 14 +- .../Command/InputBindingDescriptor.cs | 14 +- .../Project/Src/AddInTree/AddIn/Runtime.cs | 6 + .../CommandsService/CommandBindingInfo.cs | 138 +++- .../CommandsService/CommandsRegistry.cs | 694 ++++++++++++------ .../CommandsService/CommandsService.cs | 33 +- .../CommandsService/InputBindingInfo.cs | 246 +++++-- .../Menu/MenuCommand.cs | 18 +- .../ToolBar/ToolBarButton.cs | 3 +- 17 files changed, 859 insertions(+), 425 deletions(-) diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin index dd7eec13d8..c1ea3018ba 100644 --- a/AddIns/ICSharpCode.SharpDevelop.addin +++ b/AddIns/ICSharpCode.SharpDevelop.addin @@ -130,7 +130,9 @@ command="SDBuildCommands.BuildSolution" class="ICSharpCode.SharpDevelop.Project.Commands.Build" gestures="F8" - category="Building" /> + category="Building" + owner-instance="ICSharpCode.SharpDevelop.Gui.ClassBrowser.ClassBrowserPad" + /> yd7@GA1!0(#x@@kPAA(s(?F0PN{p=5%(NNXYLk93j>&X3sg1bwJxh=+G?~f0 z^UOWxIp@CTocH57-W!VdhBCNEGFcd71%wrZM8YrdyV71Ims&==C9RfUq88U{>cJQ= zE-pWR=Mrd$8L7cT^0;37yofMO4_=j%&>JOVr&0z9ID8=ky(Ss&Dre<7AR7bPevMvB zlcmTXJkc(FG7;uTGDze`BH|)RPfUd&yiiOe8;t1zJwK^`3k+;I4XlY6RHCW#CUzOO z=w)gxjTpk9(S>8O6FrMvdNEBOG0209ufU_R3~1ZJUN%7-`rTKuV?PSrnHIc>`pXF7 zzexT?>i>k_H*Es_VrmMn&N@fgO8<>uSKMLkW}@F&#XpP7S!CKpY>4Jm(AOo}Sd_5V zBp88uVj2jIyd~kVgoEvu@wDH}(^p1ISp9e^w%Kli4x#QnG}>~x%RVLft!~f&K00Mq zTC^9NTl|IF!6v~ccyrA|GYlThO;pt#u#bCF9e}IzQn7q>-TWCi5h}nXUJs5W%kVxP zd;Ag(rknX_S`y$`az0vHPvhyd6u6DHq?6p5G7R%A@TIB$1oeg%5|mFg&r8v`Eyal+ z59Z)d##Z!N+jv`c515L@v*d=Dq|R3O|t5dlopS{%$$6^ls<`7j|tJH-Md%SVedc8qs+lyEcAnCdJ|- z#&~e!IHZ&@<0VV;RFtElXZqQ@6QctnKUo?3dwlY>a}LL*H~)I;`>PvUvhn<;4Y3O+ z^ZZhs49mh*;VG+-U~{+`EUUoc*aGyHdt#m^dmoB|Vhl}N*5H*29d~XGXdr__&NQ5< zlzOW@+7uerrs1LL&3Hk{#9(y*if2sixGfJ(j`#5oYgQP}xFziWm01z9U&n3soyudZ zfpy?Hd*U~W*?!hSZv$&(dsqj1g1L#=&zh+{e=MEtCYG^u!mDKGFzeDqEFo{6kA&YsmLN%*m#c1p3;O!ox2JF}{5Er$U zCVZWcgzuRg*mE!qubY-gxr~PnN-|z^I5BkDjJ+ML*yCtaKTd>He(K2Y0Vc7i_BR+f zkfi>p0iv;SorPPxe*>kJY^CysqXvLa(YE~^tlhgr&5nZD-V?=mLC!?a370;LCaovT zMjnGFCM3ueF66wXkzh zCix+b&C>*!LT^_5P~Qbz*j>S&Ru~|awyO|k{lz^$yDVeiV3v`wDB|-8!d2WmP-@ZH zB4%Rnt?Rnj2!aQPD`W%ch!SC+vp6;pGZUYHTemK9Bp7H-flkZ}?#FBY$-wrKT>fs> zN|K*0v&qBS$r(-Td*qfTc91pU+dJcW+q7y^EmYcO&bLeRu=EAN>`o+Ajo{sDboApDSUitw76DZ!4?SvePn z_7VLuLHI`SzohT0gtMRbU#IUN;W5G+gdqYa&`Fp-AVDYS(x@p+i91*I$Z%aJ?x;CN zffw-VJ@1^{^Sz(#f|zzHvu=NT~O`G zFzO%GL!m}1w#%5Bo&ZPuqZTNHzB*X%TLH3f321#*kkEPD=r<<8zchVz7z4Z7-3$(K zM@BqO5`!xCZ4w`J4LA+6MJ8_4U21^?ieWbv9Vo|sd-R-SDdF_yZ@*Rq{`HT*h~!HF zNgYatEPqxyTmfz!zbmP?jc{HKBtyJvOoJ4(z7pH#gi@U-xLL>eJx*|gj#Bpl74vWE z$U>_~cDG$z?q8MzKZ@s{eozZSS>`se@hjBW12?}h>3i8gmc<6d!~Dlep<9E099W9p zY%LaqYUkzPL}+TkRi|nI?ql2iZnaxW(VthfYQ`eCimtWRzDn4jFQL^Q`g}!^9g308 zro*n`WXPeu4Mz@TD^C(Ps&1=-E$Ub${1$C_&&;>V|D0z7>|eWG-Che%Ef}2$eGU3* z;G(WHVl6dT18%&iq^X{rlz@$AbFhAkPJQwTIE5drN#PSA1Nh7!7krh=C!emSHmdMe el0Ac{0epDfEp=rB{KaPh$yY~cq#XPX$o~Z$BAkT) delta 2194 zcmY*a4Nz276n^LJd&`r3yDXwcfGaGDfTRmbIEJ`R&6GpBI5yKXPJ`7nrDfK<8Ldg_TsG+SX1@3C{qDKvo^$Rw z=LIgRfs1NalbkqRlB8@x8sR8mK0YF^Qe8BfiI?Pw%B_Kc0j}E`!PT|w%IoaP7ht0` z|03L~oY6H_FNmkNuRAEnPKAMg_;NVZ{C%_4}lR%C|NEN2+!7Z)@x=f?nEK6v*s`WS`99Ggu zh@GTcNNy&ag(SE1+pVhu0JK0)t$5+S&6%oTp5ZqW=Yn2BoCumQRrs!oNJ+RQX`6j4 z(O10uucSNU5(O(T{NU`=sr;qX_43}9barhlB=cTRx(pg#8uu0UdZ!0hc4JGp6t892 zxsv&}jP8H|Sva%sZanpP5f02a8?16+B-_p6Y9SZzn6wni(4R9p($@e}0HeO&Vsl1w zFTbAuGhlUd8wQrlz{$%-qU*>77EJ&jZolDDon+`YxZ{B@(ADdvdmVu{Kl>e5PpiQG zL+MzWlNeJnb-D>wrORgQ0PN0d!4Ka`=Ea4r0FyZ^902UU>p`pBw&GoYSF3z%TQw|H zB`HZ7v~*Bujn4Snr*-kf{2$r@&I&LXF zH7jD7XWScbJVgsXhzuq@i3@V@Y?a1+l~LP)S{XYJySS_Q4+z#7b|JEG5^k-V zk39+{ZCz9s6(!CeG8oN8zbL7pLtg$veVQ}4It7m6jy2nO`5G7S73&lL1>wjk41_f7 z8mC~^x?=EgIGzvul?`6y*!?o7B0cjER-VMb<&CO`W>@JlPoej}689&R853b_BV zuL1p^bYuUjT+HoGQ!{ASWt?5O7gyAz;L^-#yfSbMSa3NsKrS0M0)7S;CG^L^wh|{4 zkZ>Vk*ma{VR(F0YX||mc!Q$qV6@Uji7h_sY(}CUk%f*li|E0z87vUkmlZPA_ebmmz zR=}iVp&l*P8s4Dm%O#Z)ENZ#&X0IZAltvJW3BuV>CKW)ivWdl2fSa4`7jD<`Xld9$ z^TY*>@^zTt=E*9>DG9HqS!v_+IY%ttiYzo5(OOOP)ggV{jBd;Z1M|&Ic>d2R?4dfy zVw);Jvp5zxXon?$E!lCxs9ow>`{(P|^7y}J%Q2zIPA=}^?h!&8LG+zn^nISNoA5N@8N#!K=LnrFUxr2V4$`ol@V_=iTgCis;zf7vAiVpp zOc#CU5Z)(94q&{$P9?6z8;a3Azx zv^fO>IGu`Q3?@ABJNoX7hw->@e<@A@I)p8(x5+oMB4q#zg0LdXa6v{c$JVj^M? zF?>)9T7rdgT&Ia5%2)U^7K*UfGb&P^2Orq5ztbIY7eHuKBwS9_^uZhmE4cBZhig9; zLuetC;%UWachP1ISYHh#a-){QN^9T~)?Wh|u~$hA%);{>lQAL7v;>;pHBpf*9U3?1 ztO?b_=h{7F$dJ9vtcO}{o|Q4~r^`FgK1W<0PRWmFg>}#z(=(ixYuNk-*va};bscqV!EfnTU!g=wtoOF0W53) 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 b009e5bde5..fd7afa3bf6 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.ShortcutsManagement rootEntries.Add(unspecifiedAddInSection); // Go through all input bindings - var inputBindingInfos = CommandsRegistry.FindInputBindingInfos(null, null, null); + var inputBindingInfos = CommandsRegistry.FindInputBindingInfos(null, null, null, null, null); foreach(var inputBindingInfo in inputBindingInfos) { // Find appropriate or create new add-in section for input binding ShortcutManagement.AddIn addinSection; @@ -156,10 +156,17 @@ namespace ICSharpCode.ShortcutsManagement var shortcut = pair.Key; var inputBindingInfo = pair.Value; + if (inputBindingInfo.Gestures.Count == shortcut.Gestures.Count) { + foreach (var gesture in shortcut.Gestures) { + inputBindingInfo.Gestures.ContainsCopy(gesture); + } + } else { + inputBindingInfo.IsModifyed = true; + } inputBindingInfo.Gestures = new InputGestureCollection(shortcut.Gestures); } - CommandsRegistry.InvokeInputBindingUpdateHandlers(null, null); + CommandsRegistry.InvokeInputBindingUpdateHandlers(); return true; } diff --git a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs index 70af13b05e..e68a69c6c2 100644 --- a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs +++ b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs @@ -483,7 +483,7 @@ namespace ICSharpCode.SharpDevelop.Commands var commandBindingInfo = new CommandBindingInfo(); commandBindingInfo.ClassName = routedCommandName; - commandBindingInfo.ContextName = CommandsRegistry.DefaultContextName; + commandBindingInfo.OwnerType = typeof(WpfWorkbench); commandBindingInfo.RoutedCommandName = routedCommandName; commandBindingInfo.AddIn = addIn; @@ -491,10 +491,15 @@ namespace ICSharpCode.SharpDevelop.Commands // If pad have shortcut specified add input binding if (!string.IsNullOrEmpty(padContent.Shortcut)) { + CommandsRegistry.RegisterClassInputBindingsUpdateHandler(CommandsRegistry.DefaultContextName, delegate { + var updatedGestures = CommandsRegistry.FindInputGestures(CommandsRegistry.DefaultContextName, null, null, null, routedCommandName); + item.InputGestureText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); + }); + var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(padContent.Shortcut); var inputBindingInfo = new InputBindingInfo(); - inputBindingInfo.ContextName = CommandsRegistry.DefaultContextName; + inputBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; inputBindingInfo.RoutedCommandName = routedCommandName; inputBindingInfo.Gestures = gestures; inputBindingInfo.Categories.AddRange(CommandsRegistry.RegisterInputBindingCategories("Menu Items/Views")); @@ -505,15 +510,6 @@ namespace ICSharpCode.SharpDevelop.Commands bindingsAssigned.Add(routedCommandName); } - - CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { - var updatedGestures = CommandsRegistry.FindInputGestures(CommandsRegistry.DefaultContextName, null, routedCommandName); - item.InputGestureText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); - }); - - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); - CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); - item.Command = CommandsRegistry.GetRoutedUICommand(routedCommandName); diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs index 8845aaab52..bec829381a 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs @@ -88,24 +88,7 @@ namespace ICSharpCode.SharpDevelop.Gui placeholder = null; var contextName = padInstance.GetType().FullName; - - CommandsRegistry.LoadContext(contextName, (UIElement)Content); - - CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, null, delegate { - var newBindings = CommandsRegistry.FindCommandBindings(contextName, null, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(newBindings); - }); - - CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, null, delegate { - var newBindings = CommandsRegistry.FindInputBindings(contextName, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(newBindings); - }); - - - CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName, null); - CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName, null); + CommandsRegistry.RegisterNamedUIElementInstance(contextName, (UIElement)Content); } } } diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs index 4405504be5..36595af053 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs @@ -93,24 +93,8 @@ namespace ICSharpCode.SharpDevelop.Gui CommandManager.InvalidateRequerySuggested(); if (newActiveViewContent != null) { - string contextName = newActiveViewContent.GetType().FullName; - - CommandsRegistry.LoadContext(contextName, (UIElement)Content); - - CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, null, delegate { - var newBindings = CommandsRegistry.FindCommandBindings(contextName, null, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(newBindings); - }); - - CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, null, delegate { - var newBindings = CommandsRegistry.FindInputBindings(contextName, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(newBindings); - }); - - CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName, null); - CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName, null); + string ownerName = newActiveViewContent.GetType().FullName; + CommandsRegistry.RegisterNamedUIElementInstance(ownerName, (UIElement)Content); } } diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index cdcec48b5f..3ea5cc7bc4 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -80,7 +80,7 @@ namespace ICSharpCode.SharpDevelop.Gui } } - CommandsRegistry.DefaultContextName = this.GetType().Name; + CommandsRegistry.DefaultContextName = this.GetType().AssemblyQualifiedName; CommandsService.RegisterBuiltInRoutedUICommands(); @@ -92,20 +92,17 @@ namespace ICSharpCode.SharpDevelop.Gui // Register context and load all commands from addin CommandsRegistry.LoadAddinCommands(AddInTree.AddIns.FirstOrDefault(a => a.Name == "SharpDevelop")); - CommandsRegistry.RegisterCommandBindingsUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { - var newBindings = CommandsRegistry.FindCommandBindings(CommandsRegistry.DefaultContextName, null, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(newBindings); - }); + //CommandsRegistry.RegisterCommandBindingsUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { + // var newBindings = CommandsRegistry.FindCommandBindings(CommandsRegistry.DefaultContextName, null, null, null); + // CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); + // CommandBindings.AddRange(newBindings); + //}); - CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { - var newBindings = CommandsRegistry.FindInputBindings(null, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(newBindings); - }); - - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); - CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); + //CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { + // var newBindings = CommandsRegistry.FindInputBindings(null, null, null); + // CommandsRegistry.RemoveManagedInputBindings(InputBindings); + // InputBindings.AddRange(newBindings); + //}); mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath); diff --git a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/CommandBindingDescriptor.cs b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/CommandBindingDescriptor.cs index 856f33d900..28bc7ffb94 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/CommandBindingDescriptor.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/CommandBindingDescriptor.cs @@ -38,12 +38,11 @@ namespace ICSharpCode.Core get; private set; } - /// - /// Full name of context class. - /// - /// UI element in which this binding will be valid - /// - public string Context { + public string OwnerInstanceName { + get; private set; + } + + public string OwnerTypeName { get; private set; } @@ -86,7 +85,8 @@ namespace ICSharpCode.Core Class = Codon.Properties["class"]; Command = Codon.Properties["command"]; CommandText = Codon.Properties["commandtext"]; - Context = Codon.Properties["context"]; + OwnerInstanceName = Codon.Properties["owner-instance"]; + OwnerTypeName = Codon.Properties["owner-type"]; Gestures = Codon.Properties["gestures"]; Category = Codon.Properties["category"]; } diff --git a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingDescriptor.cs b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingDescriptor.cs index f3534ab70a..853278fc62 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingDescriptor.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingDescriptor.cs @@ -28,12 +28,11 @@ namespace ICSharpCode.Core get; private set; } - /// - /// Full name of context class. - /// - /// UI element in which this binding will be valid - /// - public string Context { + public string OwnerInstanceName { + get; private set; + } + + public string OwnerTypeName { get; private set; } @@ -60,7 +59,8 @@ namespace ICSharpCode.Core Codon = codon; Command = codon.Properties["command"]; CommandText = codon.Properties["commandtext"]; - Context = codon.Properties["context"]; + OwnerInstanceName = codon.Properties["owner-instance"]; + OwnerTypeName = codon.Properties["owner-type"]; Gestures = codon.Properties["gestures"]; Category = codon.Properties["category"]; } diff --git a/src/Main/Core/Project/Src/AddInTree/AddIn/Runtime.cs b/src/Main/Core/Project/Src/AddInTree/AddIn/Runtime.cs index 0f4c5ddff6..182f1ae6b5 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddIn/Runtime.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddIn/Runtime.cs @@ -84,6 +84,10 @@ namespace ICSharpCode.Core // preload assembly to provoke FileLoadException if dependencies are missing loadedAssembly.GetExportedTypes(); #endif + + if(Loaded != null) { + Loaded(this, null); + } } catch (FileNotFoundException ex) { MessageService.ShowError("The addin '" + assembly + "' could not be loaded:\n" + ex.ToString()); } catch (FileLoadException ex) { @@ -92,6 +96,8 @@ namespace ICSharpCode.Core } } + public event EventHandler Loaded; + public Assembly LoadedAssembly { get { Load(); // load the assembly, if not already done diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs index 96fa3be922..0d6bce8752 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs @@ -8,12 +8,12 @@ namespace ICSharpCode.Core.Presentation /// Stores details about command binding /// public class CommandBindingInfo - { - private UIElement contextInstance; - + { public CommandBindingInfo() { - ContextName = CommandsRegistry.DefaultContextName; + IsModifyed = true; + OldCommandBindings = new CommandBindingCollection(); + NewCommandBindings = new CommandBindingCollection(); } /// @@ -90,28 +90,105 @@ namespace ICSharpCode.Core.Presentation } /// - /// Name of the class which owns this binding + /// Store name of object owning this binding (can only be used with named objects) + /// + /// Named objects can be registered throgut + /// + public string OwnerInstanceName{ + get; set; + } + + private UIElement ownerInstance; + + /// + /// Stores instance of object which is owning this binding + /// + public UIElement OwnerInstance{ + get { + if(OwnerInstanceName != null && ownerInstance == null) { + ownerInstance = CommandsRegistry.GetNamedUIElementInstance(OwnerInstanceName); + } + + return ownerInstance; + } + set { + ownerInstance = value; + } + } + + /// + /// Assembly qualified name of the class owning this instance + /// + /// Named type can be registered throgut /// - public string ContextName{ + public string OwnerTypeName{ get; set; } + + private Type ownerType; /// - /// Instance of class which owns this binding + /// Stores type owning this binding /// - public UIElement Context { + public Type OwnerType { set { - contextInstance = value; + ownerType = value; } get { - if(contextInstance != null) { - return contextInstance; - } else { - UIElement context; - CommandsRegistry.contexts.TryGetValue(ContextName, out context); - - return context; + if(ownerType == null && OwnerTypeName != null) { + ownerType = Type.GetType(OwnerTypeName); + CommandsRegistry.RegisterNamedUIType(OwnerTypeName, ownerType); } + + return ownerType; + } + } + + /// + /// Default binding update handler update owner or type bindings (depending on input binding info type) + /// so they would always contain latest version + /// + private BindingsUpdatedHandler defaultCommandBindingHandler; + + /// + /// Default command binding handler. Updates command binding if binding info changes + /// + internal BindingsUpdatedHandler DefaultCommandBindingHandler + { + get { + if(defaultCommandBindingHandler == null && (OwnerTypeName != null || OwnerType != null)) { + defaultCommandBindingHandler = delegate { + if(OwnerType != null && IsModifyed) { + GenerateCommandBindings(); + + foreach(ManagedCommandBinding binding in OldCommandBindings) { + CommandsRegistry.RemoveClassCommandBinding(OwnerType, binding); + } + + foreach(ManagedCommandBinding binding in NewCommandBindings) { + CommandManager.RegisterClassCommandBinding(OwnerType, binding); + } + + IsModifyed = false; + } + }; + } else if(defaultCommandBindingHandler == null && (OwnerInstanceName != null || OwnerInstance != null)) { + defaultCommandBindingHandler = delegate { + if(OwnerInstance != null && IsModifyed) { + GenerateCommandBindings(); + + foreach(ManagedCommandBinding binding in OldCommandBindings) { + OwnerInstance.CommandBindings.Remove(binding); + } + + OwnerInstance.CommandBindings.AddRange(NewCommandBindings); + + IsModifyed = false; + } + }; + } + + return defaultCommandBindingHandler; } } @@ -136,6 +213,35 @@ namespace ICSharpCode.Core.Presentation { get; set; } + + /// + /// Indicates that generated command bindings are modified from last access + /// + public bool IsModifyed { + get; set; + } + + public void GenerateCommandBindings() + { + OldCommandBindings = NewCommandBindings; + + var managedCommandBinding = new ManagedCommandBinding(RoutedCommand); + managedCommandBinding.CanExecute += GeneratedCanExecuteEventHandler; + managedCommandBinding.Executed += GeneratedExecutedEventHandler; + + NewCommandBindings = new CommandBindingCollection(); + NewCommandBindings.Add(managedCommandBinding); + } + + internal CommandBindingCollection OldCommandBindings + { + get; set; + } + + internal CommandBindingCollection NewCommandBindings + { + get; set; + } internal void GeneratedExecutedEventHandler(object sender, ExecutedRoutedEventArgs e) { if(ExecutedEventHandler != null) { diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs index 6f067afa8b..6cb2bb6197 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs @@ -7,6 +7,8 @@ using System.Threading; using System.Text; using System.Text.RegularExpressions; using System.Linq; +using System.Reflection; +using System.Collections.Specialized; namespace ICSharpCode.Core.Presentation { @@ -31,18 +33,111 @@ namespace ICSharpCode.Core.Presentation get; set; } + // Binding infos private static List commandBindings = new List(); private static List inputBidnings = new List(); + // Commands private static Dictionary routedCommands = new Dictionary(); internal static Dictionary commands = new Dictionary(); - internal static Dictionary contexts = new Dictionary(); - private static Dictionary>> commandBindingsUpdateHandlers = new Dictionary>>(); - private static Dictionary>> inputBindingsUpdateHandlers = new Dictionary>>(); - + // Update hanlers + private static Dictionary> classCommandBindingUpdateHandlers = new Dictionary>(); + private static Dictionary> instanceCommandBindingUpdateHandlers = new Dictionary>(); + 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(); + + // Categories private static List categories = new List(); + /// + /// Register UI element instance accessible by unique name + /// + /// Instance name + /// Instance + public static void RegisterNamedUIElementInstance(string instanceName, UIElement element) + { + if(!namedUIInstances.ContainsKey(instanceName)){ + namedUIInstances.Add(instanceName, element); + + // If there are some bindings and update handlers already registered, + // but owner is not loaded then move these to arrays which holds bindings + // and update handlers of loaded instances + if(instanceCommandBindingUpdateHandlers.ContainsKey(instanceName)) { + foreach(var handler in instanceCommandBindingUpdateHandlers[instanceName]) { + RegisterInstanceCommandBindingsUpdateHandler(element, handler); + } + instanceCommandBindingUpdateHandlers.Remove(instanceName); + InvokeInstanceCommandBindingUpdateHandlers(element); + + foreach(var handler in instanceInputBindingUpdateHandlers[instanceName]) { + RegisterInstanceInputBindingsUpdateHandler(element, handler); + } + instanceInputBindingUpdateHandlers.Remove(instanceName); + InvokeInstanceInputBindingUpdateHandlers(element); + } + } + } + + /// + /// Get instance by unique instance name + /// + /// Instance name + /// + public static UIElement GetNamedUIElementInstance(string instanceName) + { + UIElement instance; + namedUIInstances.TryGetValue(instanceName, out instance); + + return instance; + } + + /// + /// Register UI type which can be accessible by name + /// + /// Type name + /// Type + public static void RegisterNamedUIType(string typeName, Type type) + { + if(!namedUITypes.ContainsKey(typeName)){ + namedUITypes.Add(typeName, type); + + // If any bindings or update handlers where assigned to the type + // before it was loaded using unique name move these to array + // holding type bindings and update handlers + if(classCommandBindingUpdateHandlers.ContainsKey(typeName)) { + foreach(var handler in classCommandBindingUpdateHandlers[typeName]) { + RegisterClassCommandBindingsUpdateHandler(type, handler); + } + classCommandBindingUpdateHandlers.Remove(typeName); + InvokeClassCommandBindingUpdateHandlers(type); + + foreach(var handler in classInputBindingUpdateHandlers[typeName]) { + RegisterClassInputBindingsUpdateHandler(type, handler); + } + classInputBindingUpdateHandlers.Remove(typeName); + InvokeClassInputBindingUpdateHandlers(type); + } + } + } + + /// + /// Get type by uniqe type name + /// + /// Type name + /// Type + public static Type GetNamedUIType(string typeName) + { + Type instance; + namedUITypes.TryGetValue(typeName, out instance); + + return instance; + } + /// /// Get reference to routed UI command by name /// @@ -121,7 +216,14 @@ namespace ICSharpCode.Core.Presentation public static void RegisterInputBinding(InputBindingInfo inputBindingInfo) { inputBidnings.Add(inputBindingInfo); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(inputBindingInfo.ContextName, null); + + if(inputBindingInfo.OwnerTypeName != null || inputBindingInfo.OwnerType != null) { + RegisterClassDefaultInputBindingHandler(inputBindingInfo); + } else if (inputBindingInfo.OwnerInstanceName != null || inputBindingInfo.OwnerInstance != null) { + RegisterInstaceDefaultInputBindingHandler(inputBindingInfo); + } else { + throw new ArgumentException("Binding owner must be specified"); + } } /// @@ -134,233 +236,371 @@ namespace ICSharpCode.Core.Presentation } /// - /// Find input input bindings which satisfy provided arguments + /// 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 contextName, UIElement contextInstance, string routedCommandName) { + public static ICollection FindInputBindingInfos(string ownerTypeName, Type ownerType, string ownerInstanceName, UIElement ownerInstance, string routedCommandName) { var foundBindings = new List(); - for(int i = inputBidnings.Count - 1; i >= 0; i--) { - if((contextName == null || inputBidnings[i].ContextName == contextName) - && (contextInstance == null || inputBidnings[i].Context == null || inputBidnings[i].Context == contextInstance) - && (routedCommandName == null || inputBidnings[i].RoutedCommandName == routedCommandName)) { - foundBindings.Add(inputBidnings[i]); + + foreach(var binding in inputBidnings) { + if( (ownerInstanceName == null || binding.OwnerInstanceName == ownerInstanceName) + && (ownerInstance == null || binding.OwnerInstance == ownerInstance) + && (ownerTypeName == null || binding.OwnerTypeName == ownerTypeName) + && (ownerType == null || binding.OwnerType == ownerType) + && (routedCommandName == null || binding.RoutedCommandName == routedCommandName)) { + + foundBindings.Add(binding); } } return foundBindings; } - + /// - /// Register delegate which will be invoked on change in input bindings in specified context + /// Remove input binding associated with type /// - /// Context class full name - /// Register update handler which will trigger only if input bindings registered for this object where triggered - /// Update handler delegate - public static void RegisterInputBindingUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { - if(contextInstance == null) { - contextInstance = NullUIElement; + /// Owner type + /// Input binding + public static void RemoveClassInputBinding(Type ownerType, InputBinding inputBinding) + { + var fieldInfo = typeof(CommandManager).GetField("_classInputBindings", BindingFlags.Static | BindingFlags.NonPublic); + var fieldData = (HybridDictionary)fieldInfo.GetValue(null); + var classInputBindings = (InputBindingCollection)fieldData[ownerType]; + + if(classInputBindings != null) { + classInputBindings.Remove(inputBinding); } - - if(!inputBindingsUpdateHandlers.ContainsKey(contextName)) { - inputBindingsUpdateHandlers.Add(contextName, new Dictionary>()); + } + + /// + /// Remove command binding associated with type + /// + /// + /// + public static void RemoveClassCommandBinding(Type ownerType, CommandBinding commandBinding) + { + var fieldInfo = typeof(CommandManager).GetField("_classCommandBindings", BindingFlags.Static | BindingFlags.NonPublic); + var fieldData = (HybridDictionary)fieldInfo.GetValue(null); + var classCommandBindings = (CommandBindingCollection)fieldData[ownerType]; + + if(classCommandBindings != null) { + classCommandBindings.Remove(commandBinding); } + } + + /// + /// Register command binding by specifying command binding parameters + /// + /// Command binding parameters + public static void RegisterCommandBinding(CommandBindingInfo commandBindingInfo) { + commandBindings.Add(commandBindingInfo); + commandBindingInfo.GenerateCommandBindings(); - if(!inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - inputBindingsUpdateHandlers[contextName].Add(contextInstance, new List()); + if(commandBindingInfo.OwnerTypeName != null || commandBindingInfo.OwnerType != null) { + RegisterClassDefaultCommandBindingHandler(commandBindingInfo); + } else if (commandBindingInfo.OwnerInstanceName != null || commandBindingInfo.OwnerInstance != null) { + RegisterInstaceDefaultCommandBindingHandler(commandBindingInfo); + } else { + throw new ArgumentException("Binding owner must be specified"); } - - inputBindingsUpdateHandlers[contextName][contextInstance].Add(handler); } - + /// - /// Remove input bindings update handler + /// Unregister command binding /// - /// Context class full name - /// Unregister update handler which was triggered only if input bindings registered for specific instance where updated - /// Update handler delegate - public static void UnregisterInputBindingUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { - if(contextInstance == null) { - contextInstance = NullUIElement; - } - if(!inputBindingsUpdateHandlers.ContainsKey(contextName)) { - if(!inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - for(int i = inputBindingsUpdateHandlers[contextName][contextInstance].Count - 1; i >= 0; i++) { - if(inputBindingsUpdateHandlers[contextName][contextInstance][i] == handler) { - inputBindingsUpdateHandlers[contextName][contextInstance].RemoveAt(i); - } - } + /// Command binding parameters + public static void UnregisterCommandBinding(CommandBindingInfo commandBindingInfo) { + commandBindings.Remove(commandBindingInfo); + + // Remove command bindings + if(commandBindingInfo.OwnerType != null) { + foreach(ManagedCommandBinding binding in commandBindingInfo.OldCommandBindings) { + RemoveClassCommandBinding(commandBindingInfo.OwnerType, binding); + } + + foreach(ManagedCommandBinding binding in commandBindingInfo.NewCommandBindings) { + RemoveClassCommandBinding(commandBindingInfo.OwnerType, binding); + } + } else if (commandBindingInfo.OwnerInstance != null) { + foreach(ManagedCommandBinding binding in commandBindingInfo.OldCommandBindings) { + commandBindingInfo.OwnerInstance.CommandBindings.Remove(binding); + } + + foreach(ManagedCommandBinding binding in commandBindingInfo.NewCommandBindings) { + commandBindingInfo.OwnerInstance.CommandBindings.Remove(binding); } } } + #region Register bindings update handler /// - /// Invoke registered input bindings update handlers registered in specified context + /// Register command binding update handler which is triggered when input bindings associated + /// with specified type change /// - /// Context class full name - public static void InvokeInputBindingUpdateHandlers(string contextName, UIElement contextInstance) { - if(contextInstance == null) { - contextInstance = NullUIElement; + /// Owner type + /// Update handler + public static void RegisterClassCommandBindingsUpdateHandler(Type ownerType, BindingsUpdatedHandler handler) + { + RegisterClassCommandBindingsUpdateHandler(ownerType.AssemblyQualifiedName, 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) + { + if(!classCommandBindingUpdateHandlers.ContainsKey(ownerTypeName)) { + classCommandBindingUpdateHandlers.Add(ownerTypeName, new List()); } - if(contextName != null) { - if(inputBindingsUpdateHandlers.ContainsKey(contextName)) { - if(contextInstance == NullUIElement) { - foreach(var instanceHandlers in inputBindingsUpdateHandlers[contextName]) { - foreach(var handler in instanceHandlers.Value) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } - } - } else if(inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - foreach(var handler in inputBindingsUpdateHandlers[contextName][contextInstance]) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } + if(!classCommandBindingUpdateHandlers[ownerTypeName].Contains(handler)) { + classCommandBindingUpdateHandlers[ownerTypeName].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) + { + var instance = GetNamedUIElementInstance(instanceName); + if(instance != null) { + RegisterInstanceCommandBindingsUpdateHandler(instance, handler); } else { - foreach(var contextHandlers in inputBindingsUpdateHandlers) { - foreach(var instanceHandlers in contextHandlers.Value) { - foreach(var handler in instanceHandlers.Value) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } + if(!instanceCommandBindingUpdateHandlers.ContainsKey(instanceName)) { + instanceCommandBindingUpdateHandlers.Add(instanceName, new List()); } + + instanceCommandBindingUpdateHandlers[instanceName].Add(handler); } } /// - /// Remove all managed input bindings from + /// Register command binding update handler which is triggered when input bindings associated + /// with specified instance change /// - /// Input binding cllection containing managed input bindings - public static void RemoveManagedInputBindings(InputBindingCollection inputBindingCollection) { - for(int i = inputBindingCollection.Count - 1; i >= 0; i--) { - if(inputBindingCollection[i] is ManagedInputBinding) { - inputBindingCollection.RemoveAt(i); - } + /// Owner instance + /// Update handler + public static void RegisterInstanceCommandBindingsUpdateHandler(UIElement instance, BindingsUpdatedHandler handler) + { + if(!instanceCommandBindingUpdateHandlers.ContainsKey(instance)) { + instanceCommandBindingUpdateHandlers.Add(instance, new List()); } + + instanceCommandBindingUpdateHandlers[instance].Add(handler); + } + + /// + /// Register input binding update handler which is triggered when input bindings associated + /// with specified type change + /// + /// Owner type + /// Update handler + public static void RegisterClassInputBindingsUpdateHandler(Type ownerType, BindingsUpdatedHandler handler) + { + RegisterClassInputBindingsUpdateHandler(ownerType.AssemblyQualifiedName, handler); } /// - /// Register command binding by specifying command binding parameters + /// Register input binding update handler which is triggered when input bindings associated + /// with specified type change /// - /// Command binding parameters - public static void RegisterCommandBinding(CommandBindingInfo commandBindingInfo) { - commandBindings.Add(commandBindingInfo); + /// Owner type name + /// Update handler + public static void RegisterClassInputBindingsUpdateHandler(string ownerTypeName, BindingsUpdatedHandler handler) + { + if(!classInputBindingUpdateHandlers.ContainsKey(ownerTypeName)) { + classInputBindingUpdateHandlers.Add(ownerTypeName, new List()); + } + + if(!classInputBindingUpdateHandlers[ownerTypeName].Contains(handler)) { + classInputBindingUpdateHandlers[ownerTypeName].Add(handler); + } } /// - /// Unregister command binding + /// Register input binding update handler which is triggered when input bindings associated + /// with specified instance change /// - /// Command binding parameters - public static void UnregisterCommandBinding(CommandBindingInfo commandBindingInfo) { - commandBindings.Remove(commandBindingInfo); + /// Owner instance name + /// Update handler + public static void RegisterInstanceInputBindingsUpdateHandler(string instanceName, BindingsUpdatedHandler handler) + { + var instance = GetNamedUIElementInstance(instanceName); + if(instance != null) { + RegisterInstanceInputBindingsUpdateHandler(instance, handler); + } else { + if(!instanceInputBindingUpdateHandlers.ContainsKey(instanceName)) { + instanceInputBindingUpdateHandlers.Add(instanceName, new List()); + } + + instanceInputBindingUpdateHandlers[instanceName].Add(handler); + } } /// - /// Register delegate which will be invoked on any chage in command bindings of specified context + /// Register input binding update handler which is triggered when input bindings associated + /// with specified instance change /// - /// Context class full name - /// Register update handler which is triggered only if input bindings registered for specific instance are updated - /// Update handler delegate - public static void RegisterCommandBindingsUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { - if(contextInstance == null) { - contextInstance = NullUIElement; + /// Owner instance + /// Update handler + public static void RegisterInstanceInputBindingsUpdateHandler(UIElement instance, BindingsUpdatedHandler handler) + { + if(!instanceInputBindingUpdateHandlers.ContainsKey(instance)) { + instanceInputBindingUpdateHandlers.Add(instance, new List()); } - if(!commandBindingsUpdateHandlers.ContainsKey(contextName)) { - commandBindingsUpdateHandlers.Add(contextName, new Dictionary>()); + + instanceInputBindingUpdateHandlers[instance].Add(handler); + } + #endregion + + #region Invoke binding update handlers + + + /// + /// Invoke all inbut binding update handlers + /// + public static void InvokeInputBindingUpdateHandlers() + { + foreach(var instanceHandlers in instanceInputBindingUpdateHandlers) { + foreach(var handler in instanceHandlers.Value) { + handler.Invoke(); + } } - if(!commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - commandBindingsUpdateHandlers[contextName].Add(contextInstance, new List()); + foreach(var classHandlers in classInputBindingUpdateHandlers) { + foreach(var handler in classHandlers.Value) { + handler.Invoke(); + } + } + } + + /// + /// Invoke all command binding update handlers + /// + public static void InvokeCommandBindingUpdateHandlers() + { + foreach(var instanceHandlers in instanceCommandBindingUpdateHandlers) { + foreach(var handler in instanceHandlers.Value) { + handler.Invoke(); + } } - commandBindingsUpdateHandlers[contextName][contextInstance].Add(handler); + foreach(var classHandlers in classCommandBindingUpdateHandlers) { + foreach(var handler in classHandlers.Value) { + handler.Invoke(); + } + } } - + /// - /// Remove handler command bindings update handler + /// Invoke command binding update handlers associated with UI element instance /// - /// Context class full name - /// Unregister update handler which was triggered only if input bindings registered for specific instance were updated - /// Update handler delegate - public static void UnregisterCommandBindingsUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { - if(contextInstance == null) { - contextInstance = NullUIElement; - } - if(commandBindingsUpdateHandlers.ContainsKey(contextName)) { - if(commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - for(int i = commandBindingsUpdateHandlers[contextName][contextInstance].Count - 1; i >= 0; i--) { - if(commandBindingsUpdateHandlers[contextName][contextInstance][i] == handler) { - commandBindingsUpdateHandlers[contextName][contextInstance].RemoveAt(i); - } - } + /// Owner instance + public static void InvokeInstanceCommandBindingUpdateHandlers(UIElement owner) + { + if(instanceCommandBindingUpdateHandlers.ContainsKey(owner)) { + foreach(var handler in instanceCommandBindingUpdateHandlers[owner]) { + handler.Invoke(); } } } /// - /// Invoke registered command bindings update handlers registered in specified context + /// Invoke command binding update handlers associated with UI element instance /// - /// Context class full name - /// Invoke update handlers which handle update only in specifyc context - public static void InvokeCommandBindingUpdateHandlers(string contextName, UIElement contextInstance) { - if(contextInstance == null) { - contextInstance = NullUIElement; + /// Owner instance name + public static void InvokeInstanceCommandBindingUpdateHandlers(string ownerName) + { + if(instanceCommandBindingUpdateHandlers.ContainsKey(ownerName)) { + foreach(var handler in instanceCommandBindingUpdateHandlers[ownerName]) { + handler.Invoke(); + } } - - if(contextName != null) { - if(commandBindingsUpdateHandlers.ContainsKey(contextName)) { - if(contextInstance == NullUIElement) { - foreach(var instanceHandlers in commandBindingsUpdateHandlers[contextName]) { - foreach(var handler in instanceHandlers.Value) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } - } else if(commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { - foreach(var handler in commandBindingsUpdateHandlers[contextName][contextInstance]) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } + } + + /// + /// Invoke command binding update handlers associated with UI element type + /// + /// Owner type + public static void InvokeClassCommandBindingUpdateHandlers(Type ownerType) + { + InvokeClassCommandBindingUpdateHandlers(ownerType.AssemblyQualifiedName); + } + + /// + /// Invoke command binding update handlers associated with UI element type + /// + /// Owner type name + public static void InvokeClassCommandBindingUpdateHandlers(string ownerTypeName) + { + if(instanceCommandBindingUpdateHandlers.ContainsKey(ownerTypeName)) { + foreach(var handler in classCommandBindingUpdateHandlers[ownerTypeName]) { + handler.Invoke(); } - } else { - foreach(var contextHandlers in commandBindingsUpdateHandlers) { - foreach(var instanceHandlers in contextHandlers.Value) { - foreach(var handler in instanceHandlers.Value) { - if(handler != null) { - ((BindingsUpdatedHandler)handler).Invoke(); - } - } - } + } + } + + /// + /// Invoke input binding update handlers associated with UI element instance + /// + /// Owner instance + public static void InvokeInstanceInputBindingUpdateHandlers(UIElement owner) + { + if(instanceInputBindingUpdateHandlers.ContainsKey(owner)) { + foreach(var handler in instanceInputBindingUpdateHandlers[owner]) { + handler.Invoke(); } } } /// - /// Remove all managed command bindings from + /// Invoke input binding update handlers associated with UI element instance /// - /// Command binding cllection containing managed input bindings - public static void RemoveManagedCommandBindings(CommandBindingCollection commandBindingsCollection) { - for(int i = commandBindingsCollection.Count - 1; i >= 0; i--) { - if(commandBindingsCollection[i] is ManagedCommandBinding) { - commandBindingsCollection.RemoveAt(i); + /// Owner instance name + public static void InvokeInstanceInputBindingUpdateHandlers(string ownerName) + { + if(instanceInputBindingUpdateHandlers.ContainsKey(ownerName)) { + foreach(var handler in instanceInputBindingUpdateHandlers[ownerName]) { + handler.Invoke(); } } } + /// + /// Invoke input binding update handlers associated with UI element type + /// + /// Owner type + public static void InvokeClassInputBindingUpdateHandlers(Type ownerType) + { + InvokeClassInputBindingUpdateHandlers(ownerType.AssemblyQualifiedName); + } + + /// + /// Invoke input binding update handlers associated with UI element type + /// + /// Owner type name + public static void InvokeClassInputBindingUpdateHandlers(string ownerTypeName) + { + if(instanceInputBindingUpdateHandlers.ContainsKey(ownerTypeName)) { + foreach(var handler in instanceInputBindingUpdateHandlers[ownerTypeName]) { + handler.Invoke(); + } + } + } + #endregion + /// /// Load all registered commands in add-in /// @@ -398,15 +638,6 @@ namespace ICSharpCode.Core.Presentation } } - /// - /// Register binding owner instance which can be identified by unique name - /// - /// Context class full name - /// Context class instance - public static void LoadContext(string contextName, UIElement context) { - contexts[contextName] = context; - } - /// /// Get list of all command bindings which satisfy provided parameters /// @@ -417,12 +648,14 @@ namespace ICSharpCode.Core.Presentation /// Context class full name /// Context class full name /// Collection of managed command bindings - public static ICollection FindCommandBindingInfos(string contextName, UIElement contextInstance, string routedCommandName, string className) { + public static ICollection FindCommandBindingInfos(string ownerTypeName, Type ownerType, string ownerInstanceName, UIElement ownerInstance, string routedCommandName, string className) { var foundBindings = new List(); foreach(var binding in commandBindings) { - if((contextName == null || binding.ContextName == contextName) - && (contextInstance == null || binding.Context == null || binding.Context == contextInstance) + if( (ownerInstanceName == null || binding.OwnerInstanceName == ownerInstanceName) + && (ownerInstance == null || binding.OwnerInstance == ownerInstance) + && (ownerTypeName == null || binding.OwnerTypeName == ownerTypeName) + && (ownerType == null || binding.OwnerType == ownerType) && (routedCommandName == null || binding.RoutedCommandName == routedCommandName) && (className == null || binding.ClassName == className)) { @@ -434,51 +667,6 @@ namespace ICSharpCode.Core.Presentation } - /// - /// Get list of all command bindings which satisfy provided parameters - /// - /// Null arguments are ignored - /// - /// Context class full name - /// Get command bindings assigned only to specific context - /// Context class full name - /// Context class full name - /// Collection of managed command bindings - public static CommandBindingCollection FindCommandBindings(string contextName, UIElement contextInstance, string routedCommandName, string className) { - var commandBindingInfos = FindCommandBindingInfos(contextName, contextInstance, routedCommandName, className); - - var bindings = new CommandBindingCollection(); - foreach(var binding in commandBindingInfos) { - var managedCommandBinding = new ManagedCommandBinding(binding.RoutedCommand); - managedCommandBinding.CanExecute += binding.GeneratedCanExecuteEventHandler; - managedCommandBinding.Executed += binding.GeneratedExecutedEventHandler; - - bindings.Add(managedCommandBinding); - } - - return bindings; - } - - /// - /// Get list of all input bindings which satisfy provided parameters - /// - /// Null arguments are ignored - /// - /// Context class full name - /// Get input bindings assigned only to specific context - /// Routed UI command name - public static InputBindingCollection FindInputBindings(string contextName, UIElement contextInstance, string routedCommandName) { - var inputBindingInfos = FindInputBindingInfos(contextName, contextInstance, routedCommandName); - - var bindings = new InputBindingCollection(); - foreach(var binding in inputBindingInfos) { - foreach(InputGesture bindingGesture in binding.Gestures) { - bindings.Add(new ManagedInputBinding(binding.RoutedCommand, bindingGesture)); - } - } - - return bindings; - } /// /// Get list of input gestures from all input bindings which satisfy provided parameters @@ -489,12 +677,12 @@ namespace ICSharpCode.Core.Presentation /// Get gestures assigned only to specific context /// Routed UI command name /// Gesture - public static InputGestureCollection FindInputGestures(string contextName, UIElement contextInstance, string routedCommandName) { - var bindings = FindInputBindings(contextName, contextInstance, routedCommandName); + public static InputGestureCollection FindInputGestures(string ownerTypeName, Type ownerType, string ownerInstanceName, UIElement ownerInstance, string routedCommandName) { + var bindings = FindInputBindingInfos(ownerTypeName, ownerType, ownerInstanceName, ownerInstance, routedCommandName); var gestures = new InputGestureCollection(); - foreach(InputBinding binding in bindings) { - gestures.Add(binding.Gesture); + foreach(InputBindingInfo bindingInfo in bindings) { + gestures.AddRange(bindingInfo.Gestures); } return gestures; @@ -540,5 +728,77 @@ namespace ICSharpCode.Core.Presentation return registeredCategories; } + + /// + /// Register default command binding update hander which will keep instance command + /// bindings upated + /// + /// Command binding info + private static void RegisterInstaceDefaultCommandBindingHandler(CommandBindingInfo commandBindingInfo) + { + if(commandBindingInfo.DefaultCommandBindingHandler != null) { + commandBindingInfo.DefaultCommandBindingHandler.Invoke(); + } + + if(commandBindingInfo.OwnerInstanceName != null && commandBindingInfo.OwnerInstance == null) { + RegisterInstanceCommandBindingsUpdateHandler(commandBindingInfo.OwnerInstanceName, commandBindingInfo.DefaultCommandBindingHandler); + } else if(commandBindingInfo.OwnerInstance != null) { + RegisterInstanceCommandBindingsUpdateHandler(commandBindingInfo.OwnerInstance, commandBindingInfo.DefaultCommandBindingHandler); + } + } + + /// + /// Register default command binding update hander which will keep type command + /// bindings upated + /// + /// Command binding info + private static void RegisterClassDefaultCommandBindingHandler(CommandBindingInfo commandBindingInfo) + { + if(commandBindingInfo.DefaultCommandBindingHandler != null) { + commandBindingInfo.DefaultCommandBindingHandler.Invoke(); + } + + if(commandBindingInfo.OwnerTypeName != null && commandBindingInfo.OwnerType == null) { + RegisterClassCommandBindingsUpdateHandler(commandBindingInfo.OwnerTypeName, commandBindingInfo.DefaultCommandBindingHandler); + } else if(commandBindingInfo.OwnerType != null) { + RegisterClassCommandBindingsUpdateHandler(commandBindingInfo.OwnerType, commandBindingInfo.DefaultCommandBindingHandler); + } + } + + /// + /// Register default input binding update hander which will keep instance command + /// bindings upated + /// + /// Input binding info + private static void RegisterInstaceDefaultInputBindingHandler(InputBindingInfo inputBindingInfo) + { + if(inputBindingInfo.DefaultInputBindingHandler != null) { + inputBindingInfo.DefaultInputBindingHandler.Invoke(); + } + + if(inputBindingInfo.OwnerInstanceName != null && inputBindingInfo.OwnerInstance == null) { + RegisterInstanceInputBindingsUpdateHandler(inputBindingInfo.OwnerInstanceName, inputBindingInfo.DefaultInputBindingHandler); + } else if(inputBindingInfo.OwnerInstance != null) { + RegisterInstanceInputBindingsUpdateHandler(inputBindingInfo.OwnerInstance, inputBindingInfo.DefaultInputBindingHandler); + } + } + + /// + /// Register default input binding update hander which will keep type command + /// bindings upated + /// + /// Input binding info + private static void RegisterClassDefaultInputBindingHandler(InputBindingInfo inputBindingInfo) + { + if(inputBindingInfo.DefaultInputBindingHandler != null) { + inputBindingInfo.DefaultInputBindingHandler.Invoke(); + } + + if(inputBindingInfo.OwnerTypeName != null && inputBindingInfo.OwnerType == null) { + RegisterClassInputBindingsUpdateHandler(inputBindingInfo.OwnerTypeName, inputBindingInfo.DefaultInputBindingHandler); + } else if(inputBindingInfo.OwnerType != null) { + RegisterClassInputBindingsUpdateHandler(inputBindingInfo.OwnerType, inputBindingInfo.DefaultInputBindingHandler); + } + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs index 698c9e5745..624aa3b0af 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs @@ -39,8 +39,6 @@ namespace ICSharpCode.Core.Presentation { var descriptors = AddInTree.BuildItems(path, caller, false); foreach(var desc in descriptors) { - var contextName = !string.IsNullOrEmpty(desc.Context) ? desc.Context : CommandsRegistry.DefaultContextName; - // If routed with such name is not registered register routed command with text same as name if(CommandsRegistry.GetRoutedUICommand(desc.Command) == null) { var commandText = string.IsNullOrEmpty(desc.CommandText) ? desc.Command : desc.CommandText; @@ -48,7 +46,15 @@ namespace ICSharpCode.Core.Presentation } var commandBindingInfo = new CommandBindingInfo(); - commandBindingInfo.ContextName = contextName; + + if(!string.IsNullOrEmpty(desc.OwnerInstanceName)) { + commandBindingInfo.OwnerInstanceName = desc.OwnerInstanceName; + } else if(!string.IsNullOrEmpty(desc.OwnerTypeName)) { + commandBindingInfo.OwnerTypeName = desc.OwnerTypeName; + } else { + commandBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; + } + commandBindingInfo.RoutedCommandName = desc.Command; commandBindingInfo.ClassName = desc.Class; commandBindingInfo.AddIn = desc.Codon.AddIn; @@ -60,7 +66,15 @@ namespace ICSharpCode.Core.Presentation var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(desc.Gestures); var inputBindingInfo = new InputBindingInfo(); - inputBindingInfo.ContextName = contextName; + + if(!string.IsNullOrEmpty(desc.OwnerInstanceName)) { + inputBindingInfo.OwnerInstanceName = desc.OwnerInstanceName; + } else if(!string.IsNullOrEmpty(desc.OwnerTypeName)) { + inputBindingInfo.OwnerTypeName = desc.OwnerTypeName; + } else { + inputBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; + } + inputBindingInfo.AddIn = desc.Codon.AddIn; inputBindingInfo.RoutedCommandName = desc.Command; inputBindingInfo.Gestures = gestures; @@ -83,10 +97,17 @@ namespace ICSharpCode.Core.Presentation var descriptors = AddInTree.BuildItems(path, caller, false); foreach(var desc in descriptors) { var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(desc.Gestures); - var contextName = !string.IsNullOrEmpty(desc.Context) ? desc.Context : CommandsRegistry.DefaultContextName; var inputBindingInfo = new InputBindingInfo(); - inputBindingInfo.ContextName = contextName; + + if(!string.IsNullOrEmpty(desc.OwnerInstanceName)) { + inputBindingInfo.OwnerInstanceName = desc.OwnerInstanceName; + } else if(!string.IsNullOrEmpty(desc.OwnerTypeName)) { + inputBindingInfo.OwnerTypeName = desc.OwnerTypeName; + } else { + inputBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; + } + inputBindingInfo.AddIn = desc.Codon.AddIn; inputBindingInfo.RoutedCommandName = desc.Command; inputBindingInfo.Gestures = gestures; diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs index 1e0cb6468e..5303b35d7c 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs @@ -5,95 +5,183 @@ using System.Collections.Generic; namespace ICSharpCode.Core.Presentation { - /// - /// Stores details about input binding - /// - public class InputBindingInfo - { - private UIElement contextInstance; - - public InputBindingInfo() { - ContextName = CommandsRegistry.DefaultContextName; - Categories = new List(); - } - - /// - /// Context class full name - /// - /// Described binding will be valid in this context - /// - public string ContextName { - get; set; - } - - /// - /// Context class instance - /// - /// Described binding will be valid in this context - /// - public UIElement Context { - get { - if(contextInstance != null) { - return contextInstance; - } else { - UIElement context; - CommandsRegistry.contexts.TryGetValue(ContextName, out context); - - return context; - } + /// + /// Stores details about input binding + /// + public class InputBindingInfo + { + public InputBindingInfo() { + IsModifyed = true; + OldInputBindings = new InputBindingCollection(); + NewInputBindings = new InputBindingCollection(); + + Categories = new List(); + } + + public string OwnerInstanceName{ + get; set; + } + + private UIElement ownerInstance; + + public UIElement OwnerInstance{ + get { + if(OwnerInstanceName != null && ownerInstance == null) { + ownerInstance = CommandsRegistry.GetNamedUIElementInstance(OwnerInstanceName); } + + return ownerInstance; } - - - /// - /// Routed command text - /// - /// Override routed command text when displaying to user - /// - /// - public string RoutedCommandText { - get; set; + set { + ownerInstance = value; } - - - /// - /// Add-in to which registered this input binding - /// - public AddIn AddIn { - get; set; + } + + public string OwnerTypeName{ + get; set; + } + + private Type ownerType; + + public Type OwnerType { + set { + ownerType = value; } - - /// - /// Routed command name - /// - /// Described binding triggers this routed command - /// - /// - public string RoutedCommandName { - get; set; + get { + if(ownerType == null && OwnerTypeName != null) { + ownerType = Type.GetType(OwnerTypeName); + CommandsRegistry.RegisterNamedUIType(OwnerTypeName, ownerType); + } + + return ownerType; } + } + + /// + /// Routed command text + /// + /// Override routed command text when displaying to user + /// + /// + public string RoutedCommandText { + get; set; + } - /// - /// Routed command instance - /// - /// Described binding triggers this routed command - /// - /// - public RoutedUICommand RoutedCommand { - get { - return CommandsRegistry.GetRoutedUICommand(RoutedCommandName); + + /// + /// Add-in to which registered this input binding + /// + public AddIn AddIn { + get; set; + } + + /// + /// Gestures which triggers this binding + /// + public InputGestureCollection Gestures { + get; set; + } + + /// + /// Routed command name + /// + /// Described binding triggers this routed command + /// + /// + public string RoutedCommandName { + get; set; + } + + /// + /// Routed command instance + /// + /// Described binding triggers this routed command + /// + /// + public RoutedUICommand RoutedCommand { + get { + return CommandsRegistry.GetRoutedUICommand(RoutedCommandName); + } + } + + private BindingsUpdatedHandler defaultInputBindingHandler; + + /// + /// Default binding update handler update owner or type bindings (depending on input binding info type) + /// so they would always contain latest version + /// + public BindingsUpdatedHandler DefaultInputBindingHandler + { + get { + if(defaultInputBindingHandler == null && (OwnerTypeName != null || OwnerType != null)) { + defaultInputBindingHandler = delegate { + if(OwnerType != null && IsModifyed) { + GenerateInputBindings(); + + foreach(ManagedInputBinding binding in OldInputBindings) { + CommandsRegistry.RemoveClassInputBinding(OwnerType, binding); + } + + foreach(ManagedInputBinding binding in NewInputBindings) { + CommandManager.RegisterClassInputBinding(OwnerType, binding); + } + + IsModifyed = false; + } + }; + } else if(defaultInputBindingHandler == null && (OwnerInstanceName != null || OwnerInstance != null)) { + defaultInputBindingHandler = delegate { + if(OwnerInstance != null && IsModifyed) { + GenerateInputBindings(); + + foreach(ManagedInputBinding binding in NewInputBindings) { + OwnerInstance.InputBindings.Remove(binding); + } + + OwnerInstance.InputBindings.AddRange(NewInputBindings); + + IsModifyed = false; + } + }; } + + return defaultInputBindingHandler; } + } + + /// + /// List of categories associated with input binding + /// + public List Categories { + get; private set; + } - /// - /// Gestures which triggers this binding - /// - public InputGestureCollection Gestures { - get; set; - } + /// + /// Indicates whether generated input bindings where modified from last access + /// + public bool IsModifyed { + get; set; + } + + public void GenerateInputBindings() + { + OldInputBindings = NewInputBindings; - public List Categories { - get; private set; + NewInputBindings = new InputBindingCollection(); + foreach(InputGesture gesture in Gestures) { + var managedInputBinding = new ManagedInputBinding(RoutedCommand, gesture); + NewInputBindings.Add(managedInputBinding); } } + + internal InputBindingCollection OldInputBindings + { + get; set; + } + + internal InputBindingCollection NewInputBindings + { + get; set; + } + } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs index cd875ce082..3bb34d1c1a 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs @@ -140,13 +140,12 @@ namespace ICSharpCode.Core.Presentation if(!codon.Properties.Contains("command") && (codon.Properties.Contains("link") || codon.Properties.Contains("class"))) { var commandBindingInfo = new CommandBindingInfo(); commandBindingInfo.AddIn = codon.AddIn; - commandBindingInfo.ContextName = CommandsRegistry.DefaultContextName; + commandBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; commandBindingInfo.Class = CommandWrapper.GetCommand(codon, caller, createCommand); commandBindingInfo.RoutedCommandName = routedCommandName; commandBindingInfo.IsLazy = true; CommandsRegistry.RegisterCommandBinding(commandBindingInfo); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); } if(codon.Properties.Contains("shortcut")) { @@ -154,16 +153,19 @@ namespace ICSharpCode.Core.Presentation var inputBindingInfo = new InputBindingInfo(); inputBindingInfo.AddIn = codon.AddIn; inputBindingInfo.Categories.AddRange(CommandsRegistry.RegisterInputBindingCategories("Menu Items")); - inputBindingInfo.ContextName = CommandsRegistry.DefaultContextName; + inputBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; inputBindingInfo.RoutedCommandName = routedCommandName; inputBindingInfo.Gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromInvariantString(codon.Properties["gestures"]); CommandsRegistry.RegisterInputBinding(inputBindingInfo); - CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContextName, null, delegate { - var updatedGestures = CommandsRegistry.FindInputGestures(null, null, routedCommandName); - this.InputGestureText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); - }); - CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); + + BindingsUpdatedHandler gesturesUpdateHandler = delegate { + var updatedGestures = CommandsRegistry.FindInputGestures(null, null, null, null, routedCommandName); + this.InputGestureText = (string)new InputGestureCollectionConverter().ConvertToInvariantString(updatedGestures); + }; + + gesturesUpdateHandler.Invoke(); + CommandsRegistry.RegisterClassInputBindingsUpdateHandler(CommandsRegistry.DefaultContextName, gesturesUpdateHandler); } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs index 1c372c6e35..0e6a5b5c37 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs +++ b/src/Main/ICSharpCode.Core.Presentation/ToolBar/ToolBarButton.cs @@ -50,13 +50,12 @@ namespace ICSharpCode.Core.Presentation if(!codon.Properties.Contains("command") && (codon.Properties.Contains("link") || codon.Properties.Contains("class"))) { var commandBindingInfo = new CommandBindingInfo(); commandBindingInfo.AddIn = codon.AddIn; - commandBindingInfo.ContextName = CommandsRegistry.DefaultContextName; + commandBindingInfo.OwnerTypeName = CommandsRegistry.DefaultContextName; commandBindingInfo.Class = CommandWrapper.GetCommand(codon, caller, createCommand); commandBindingInfo.RoutedCommandName = routedCommandName; commandBindingInfo.IsLazy = true; CommandsRegistry.RegisterCommandBinding(commandBindingInfo); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContextName, null); } if (codon.Properties.Contains("icon")) {