From 4003bdda88c7c76546355178ce8a415669611c1b Mon Sep 17 00:00:00 2001 From: Sergej Andrejev Date: Sun, 5 Jul 2009 17:14:31 +0000 Subject: [PATCH] InputBindingCategory codon git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/shortcuts@4397 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../ShortcutsManagement.suo | Bin 107520 -> 120320 bytes .../ShortcutsManagement.csproj | 1 + .../ShortcutsManagement/Src/Data/AddIn.cs | 4 +- .../ShortcutsManagement/Src/Data/MapTable.cs | 44 ++++++ .../ShortcutsManagement/Src/Data/Shortcut.cs | 4 +- .../Src/Data/ShortcutCategory.cs | 4 +- .../ShortcutsManagementOptionsPanel.xaml.cs | 132 +++++++----------- .../Project/Src/Commands/MenuItemBuilders.cs | 22 ++- .../Project/Src/Gui/Workbench/WpfWorkbench.cs | 2 + src/Main/Core/Project/ICSharpCode.Core.csproj | 1 + .../Command/InputBindingCategoryDoozer.cs | 48 +++++++ .../DefaultDoozers/MenuItem/MenuRootDoozer.cs | 9 -- .../Core/Project/Src/AddInTree/AddInTree.cs | 1 + .../CommandsService/CommandManager.cs | 103 ++++++++------ .../CommandsService/CommandsService.cs | 45 ++++-- .../CommandsService/InputBindingCategory.cs | 27 +++- .../InputBindingCategoryCollection.cs | 85 +++++++++++ .../CommandsService/InputBindingInfo.cs | 5 +- .../ICSharpCode.Core.Presentation.csproj | 1 + 19 files changed, 374 insertions(+), 164 deletions(-) create mode 100644 src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/MapTable.cs create mode 100644 src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingCategoryDoozer.cs create mode 100644 src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategoryCollection.cs diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement.suo index 763864d7dcf0487ce140121a95156dcc0f96c773..de3e8c933130ebff153b9a1af81e0cd4fafbd4d5 100644 GIT binary patch delta 7110 zcmbVR34B!5)qiI)Gfoz=6EO+d2q8$wMiv%@$wGk;NCGizK}bm02?2%x5lz5QB~l7G zz@=YNmhvH0ij=2$ELH|V1PT~!U8=N1L_~^+8e8iE{ogmqkVF#rzM0>D?z{J%d+vSr zo_n^bK54GrbKkxggU>UHqI3bm0570BKWymLB@j6^pL)vhJMwJU_gO;S zPp8NQ9o9;<(wIej+&!MFeT?dNrfj3d4;^x}m|8|*9B;I+%`Ml`6D_^kv^KfrxY9&4 zxwdXrZSLMQNH%2y8OnTR9==6NnNp&R(#s-chEl35RAQA8Xf0P3D>fxvnWahbsR0LogUxM+QN9ZNiIl5MQ z`v9`=`4C@GT}Ibvlu9Y#M6Y6&jlD-I6%5F+JxYAa~5m{W2dp@yb@LDb0MJrZ{L zl9{*l+Z-gNuw2Q;+cKXNyR<@vhcDEX_=f2zyQq;A4zJH?r!LHvXV zS7v9?G}#i*-)5iVW5xt`U-X;^!w(j+b_w0D9?w}$+%PgwbeTp0YW&hCh^={c-VqVP z|5)qGwO30hL=BI0CA!WF-u*(&>T9FA0-MNER@f$CchFsV;A{vqea5*JNN1ZwZi7+GS~vT)+%WO>RW)`?boVQ2T8y)N3zspD_5ne-n(T{^! z4Ir7e-qY2nuLGpe$oBnOhWTl+rw`VU2sNh=13$maG1uHww`<|BEam8^gE&6#IDIalPRQ3%z@L3t|Os4@(hp{rjTblnWt zHohmKVKJP2Z+lhJL6r=e0<^*K6?*rja_n3?`_H;?~MCSgKmA^8_%T z3K)Ub$0l{B+~SsFYoXtVHVtThb$rl<9Z}?gw&pV#^-`dn^;fH!R+u;?Z1^J^=k=mswD1049pWww72rAGbOWY|ENeB2nn(MAoH0`Pkja0-p-MeMz= zSVoj3ML78tR1=$z<0mN7G!SnEqVT(!rvWLSwSb%GZJ=KCTahP=3bD*UL9|P3 zG|(K^f1v+$;4Hfq1$8}*r%!=1z!l&v;By{O6qNTKp56yO0R9Gi2z&&b2mTI7yMF;? zBk(bB5%>hS1js(=Dt*@cEbBMd7fq@+5*b9%bSjgg7hxI(oj8kEEcfI0CU`%Pg9Elf zcIM-d7b%%|k_LXhGDDoPQmHPY{w{BJB%(eQ^kQ$b?!75jW&WY{l=SD+BYP(I31n4AMGzevv-j1)j>zQ9Ujo(4&zQP#ct2Temg8nJBGJ4FIMa? z>cT13)D2r4s_RR7ls7Kv#l@)={9v-1C|*TY%^pEkc+7ggt2^X3Ov*6lHTm(idVliZ z2bxkvWDR-q)TS_DPbDiJjOg&A%&ehgul`DZB}GY7`od(TC`qF1msBkp za%kk;&VjCJ@fEb3>Z7I9y&VM)!)ppn)CH;IgVrEO<)l(Pe4npJ6pEJ~qi*uTw|tg2 za$et4sqO5D(|9k~{B188szBoPkD`Yr^K{K+Q#{~TRn;8`)`H{d67h~f1>AThMXcFE z{=9daFPEo!YS!%p&Al)@hQ?@c^+PHAj*g{bp$urXLZv_%s~y=w{m5&k?pT!L>Xa%K zN*nJv`TycQd%WCuLWVF#o>0<@t*PB^`!P}Mv#h&#b_sm5@(l93+YxBP`cnz9_h^gQ z>OpQjX5nJb)D4CWF0u^MY%m_B`nODfUM4)J(B!b>lzXvAbEQRkza>Hly~{g_*9vKh ze)@N_bUI(%JSK(T)j-JwPr4_z3*~Zu2))Z)m;8zXJ6|GPt<@pof;*k|nukM|db2t9 zxV@TAbfvDP9vevhhQO(vt4Ix0b4i5up-3@qFkFDDYI61YnS-E#zfb)$iS z+dE{dEy$-@;;^N^5c7u8#Lg%`9!jAGVSSSB)3>){p1OacWn`0y>c_~-K4ukk5~L2( zcye`uV!`fvUJZo5Zsol4L5q?emHHmW*bkr z#F^Rg9?}f|2AKo-;g45`imfy0NAbRu#tUr*b?IOU+P^JiG<32Tj@gHGp+jQcgLG1y ziXyI`Dql5c3PN13%8psXW;ssqKqve)>~*bv&H-Y54%K$B2^vkJZ6w~!qdwwHA&u*V zqrf@;bJJ{Wl{dDc)mF`>GtjKLqxDc@Kq&=lU)Rt>#1{tzuziyU|7&)lmS0AD%)_J> zld-+@{9+OJ-)sEe-gqGjKFCLNtMnQF5Jkblr+{iZTf4j<;x7fXdec(8!1&fLAZ$x1 z*OHGW>25mTOEfJdgu9QRt*}kIZ5icCZ_i_TixEUOr#*AOcxg0U6pu`#x=uDb;;urW zO`0t4@m(&5czy~^(7ab5g5r`ae~~(k=5->A5SSsQ)P020TY=s#gbkJ&`(8rW1CJlB zFylR)R*=IVN_Avf`rk$UIW4JcOh~#kye&Mqu__G4$d}HwL=WxUn~ohw{%Ve&PqxdO zVS%mqDV&fRN_vjunDqYqk)_OdmHntoFXYyS6uXmXSVKlVStHXgQplhCA(|s+ z9nzy-`>)AYcFLsC7!COtBRy|tB5}Nqe$@7@Cx1u2DTo7aA&9s+p6wSrwdtGbWkdZI z$~0KyiYEb1VWfRx@pCkqkGUt9c1f}0Wm|hv0{d9P**er{k%7#V)&tBtK-Hvh<<>|_ zc96LnEkz*d+M3LC2xRB9|7@kF3{~a2w;>}knaXG#FB|7gCB^ozhCQI%xOI35s8H=oN5yaC5!70GgTufQ2XFX(|x?CSz zp+^;q^{Ap$x0W-}Cxt;eAq$-oNXJRqQrRor+l6?6`KS-oU*dL@E7QVpa%HnX(t28% zfL?@mnGanxOPQ`L1H%#!LtXIps?-NE+DwMQeSN=${7i5?$ix8%czmpA6?@=0KKyA|aNl#LM9n z#j)oD?;ndDkQ%yeSP?CbhSIZQXB-ta^Z2@%hb)J;<R zGsY$DScgFf9e;7?Q^`GDEE*$m(7CaQo}{SU8$!k8QmX94K4@Q+(qE_}WAF`}7DGp! zBP;3CJB-xQmeUV+Xm_}2bDp5?ci`ys3%y0$Z|UteZ#VT|0PkGClN&zl=Gv0^bQ4E6 z(pj-(9mVQ7$gn4O^Yt^)5R6~QjQ=rFy^%8ipSA*-PcR=x=CK(=GsfmZA;z^?&%N!u zeRh NMvv2IyoRyz^Iv=Xr&a&} delta 4226 zcma)<3s_ZE7RUGhaJcdkc}0cD%PT$x2oM#`?1ErQ23J(X0ULZ)<`Yp7F|Lnhswoqe z-CZ+&iRPf@3pnPnGPois7%3Jyqm^OfRG&G@_|eyl<}mBr$Z#BVF5i!R_S*Zbz4uys zuf2|KcMn^GsWM9O^%Fw$WWtzUj1N7c^zS*CpL#RFOdndTOo6x7sJsPl>$UBN8*Vhh zg&S;zT9KLtcuU_cc!+Gis`gLU@v2(@w*@gWZvnz6R&}ES535@T{{nB5wtHl_3q$PR zRjd_w`kNay-|t_v}e2Pmz?{hGt;Ae16OMc(7w#eLjz zKXYqr(>e(8g12_vyFq!lkGT5pD;;3TQtq>s8N__NE5Yw)xfj<%8K3`>FVt@OJ_hF^ z47>cI{#UF_0TubDxsB%rW8S|s{*i077VWzKUQ?fc^FpJzb2JmfJj58XI4*1H!=RZs zq7Cf*5LC$m$_;*?gUiEAU1z!KWe-SwVCT^_kIry&`u8S1-f|M zK^q1qYnJzUyR;5bv6~LtR#L#Qp>%P`esb8J)R5c(>KL6$^=hoEv5SLgMM{Qq#9Moc z+Ec7jq@kV<6bx;^Je2TThRC&m$CiPs0F4M zv-u`CkS~41(1%9a{K$LO7=(8EW2pshT4-WVXt5)FfLMwf@f6vLf+;vF+hiQ|nq;jg zD;+Xm3!=5}r$l?GfmJTUw8$CfTqrs81OM9^*7^dM<@pimy@q+L07{awAoiSjl@!9lQ4M+DB+1+I!E@*igS%eHX%u&JnKd9qfPu@@9;%`7V_RKk+9 zqN3k|>Pk0CYZ^wuLLb!KB*$7+vwRZ3KEJM_&DbvTWGzN;pcq9Lu7{J^97Jt%6SQ<& zHE7+u8gkr-r0RT!eJFCP*Nw(cZXM3!-}1Ir@O-)At|kfbSn|Zt%P9Pn_vMB%M9N-0 z;bjV&RG3tIL-TpD&BJ{Ozm~$Z@h(3r9WNu8$|fC`$JZlKezgHjT9dulO*MB_P6eAg zw^F~`#O<4RsAnVQuhz=Tw|Q!V_MB0vJUq&IEb+n5go&N@~kjW$QvHq&d=UD8D`8 zb`8x=4O)Bi%L=WrS`fwVew5BjGx_X_*G8T`9zdqct)#>hQb^`9?aC!TXkT9r0*$=r zK^{MTE<@6h!!f{L3{{T7L-1WxtOz4m7{AJu^GyxKdfa5Z01a&=%A*A$nQx&&5hEt@ z4K$CL>Aag}iE(0qn8o!%eotkL`>E@1qIgDF)E~s1bDOVx;DEvt6;jj;}W&#cdL6n9STV>}v&R zc3xA{x=LM7@Up_>3LwoLx!m&WuB}5p<<|Jlh2P{LlEkgX?YNG4o+)E~#~1$u`WNX>6J0LUs5v&J$Gxv!QJrFnBbXol57@ks%CO9aQcid`I|e8=vR8NWf5eH23PHH|4V z@I+aCh#oQke}#_ONPwJ{%K6zhGqG`C_g0*5GJGEqZC%a<=M{cXD)un3JpQ#gPg6`) zm|S!KG1Q#xpxtQ2GTFM*@lP?01?GtpwW z7%YZ}cz#OY`Vel97KvPs6RG_4bMI6>zA4T(lDQ>Ltm2u)#Scyx!lC8=nxS5lgn>$s zs&=;)eQ^?Af()I*9%j3j1$Dn{W83KLuX&Iqo;Y|HrOuxH$KWjNJ@9alsas3x;f?qM z(!{=%!6N&{MI` zW$PFpd0nhC7fsO03KxKUteI4n5J<5LN9mImV7JL$f!AG)6w_ONxgEX9=B`TH+x%hT zsDS0parDwbSj4H{xB$)#P4a4g_{yk6OtKeZtdYz`$$~=s^!+!r>l|czAu<$XJ3S-| zR&bvzZqMo3$7>EpkuW2Y7}D}-2)=WCrwu->!{55I!8i5z;(xRmrn2D zBbA>H(=Mf~o9w{pS{`}@ddt6?k>NU#r#V?pH{*V3>4!Ku!4rMSkshqGKQmF5mM+)# zLq6q=&6T+^=fBaF5$hDEn*f~rux xYb^dEm%fQ~BaJhC!9MbXEIouYl`r)Uvej7(-6MalB_1e;P0?929hB!5`X4uR3OWD) diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj index aee48ab3ec..3584421c92 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/ShortcutsManagement.csproj @@ -156,6 +156,7 @@ True + diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs index 9a7f7010d0..103fc1662a 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/AddIn.cs @@ -126,8 +126,8 @@ namespace ICSharpCode.ShortcutsManagement.Data /// Compared object /// Comparison result public int CompareTo(object obj) { - if (obj is ShortcutCategory) return 1; - if (obj is Shortcut) return 1; + if (obj is ShortcutCategory) return -1; + if (obj is Shortcut) return -1; var addInObj = (AddIn)obj; return Name.CompareTo(addInObj.Name); diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/MapTable.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/MapTable.cs new file mode 100644 index 0000000000..0417812046 --- /dev/null +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/MapTable.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; + +namespace ICSharpCode.ShortcutsManagement.Data +{ + public class MapTable : IEnumerable> + { + private readonly Dictionary forwardMaping = new Dictionary(); + + private readonly Dictionary backwardMaping = new Dictionary(); + + public void Add(T1 mappingObject, T2 mappedObject) + { + forwardMaping.Add(mappingObject, mappedObject); + backwardMaping.Add(mappedObject, mappingObject); + } + + public T2 MapForward(T1 mappingObject) + { + return forwardMaping[mappingObject]; + } + + public T1 MapBackward(T2 mappingObject) + { + return backwardMaping[mappingObject]; + } + + public void Clear() + { + forwardMaping.Clear(); + backwardMaping.Clear(); + } + + public IEnumerator> GetEnumerator() + { + return forwardMaping.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return forwardMaping.GetEnumerator(); + } + } +} diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs index 59234a91ee..e83e535e56 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/Shortcut.cs @@ -159,8 +159,8 @@ namespace ICSharpCode.ShortcutsManagement.Data /// Comparison result public int CompareTo(object obj) { - if (obj is AddIn) return -1; - if (obj is ShortcutCategory) return -1; + if (obj is AddIn) return 1; + if (obj is ShortcutCategory) return 1; var shortcutObj = (Shortcut)obj; return Name.CompareTo(shortcutObj.Name); diff --git a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs index 371536cd6b..3334394618 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Data/ShortcutCategory.cs @@ -153,8 +153,8 @@ namespace ICSharpCode.ShortcutsManagement.Data /// Comparison result public int CompareTo(object obj) { - if (obj is AddIn) return -1; - if (obj is Shortcut) return 1; + if (obj is AddIn) return 1; + if (obj is Shortcut) return -1; var categoryObj = (ShortcutCategory)obj; return Name.CompareTo(categoryObj.Name); 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 e1a3de6340..0c95c6a70b 100644 --- a/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs +++ b/src/AddIns/Misc/ShortcutsManagement/ShortcutsManagement/Src/Dialogs/ShortcutsManagementOptionsPanel.xaml.cs @@ -52,7 +52,7 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs /// /// Stores shortcut entry to input binding convertion map /// - private readonly Dictionary shortcutsMap = new Dictionary(); + private readonly MapTable shortcutsMap = new MapTable(); private List rootEntries; @@ -91,7 +91,6 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs } BindProfiles(); - BindShortcuts(); } private void BindProfiles() @@ -130,90 +129,58 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs private void BindShortcuts() { + shortcutsMap.Clear(); + // Root shortcut tree entries rootEntries = new List(); // Stores SD input binding category to category section convertion map - var categoriesMap = new Dictionary(); + var categoriesMap = new MapTable(); var unspecifiedCategory = new ShortcutCategory(StringParser.Parse("${res:ShortcutsManagement.UnspecifiedCategoryName}")); rootEntries.Add(unspecifiedCategory); - // Go through all input bindings - var inputBindingInfos = CommandManager.FindInputBindingInfos(null, null, null); - foreach (var inputBindingInfo in inputBindingInfos) + CommandManager.InputBindingCategories.Sort((c1, c2) => c1.Path.CompareTo(c2.Path)); + var parentCategories = new LinkedList(); + var previousDepth = 0; + foreach(var bindingCategory in CommandManager.InputBindingCategories) { - // Find appropriate or create new category sections within add-in section for input binding - var shortcutCategorySections = new List(); - if (inputBindingInfo.Categories.Count == 0) - { - // If no category specified assign to "Uncotegorized" category - shortcutCategorySections.Add(unspecifiedCategory); - } - else - { - // Go throu all categories and find or create appropriate category sections - foreach (var bindingCategory in inputBindingInfo.Categories) + var categoryName = Regex.Replace(StringParser.Parse(bindingCategory.Text), @"&([^\s])", @"$1"); + var shortcutCategory = new ShortcutCategory(categoryName); + categoriesMap.Add(bindingCategory, shortcutCategory); + + AddCategory: + var currentDepth = bindingCategory.Path.Split('/').Length - 1; + if (currentDepth > previousDepth) { - ShortcutCategory categorySection; - if (categoriesMap.ContainsKey(bindingCategory)) + previousDepth++; + + if (previousDepth > 1) { - // If found appropriate category assign shortcut to it - categorySection = categoriesMap[bindingCategory]; + parentCategories.Last.Value.SubCategories.Add(shortcutCategory); } else { - // Create appropriate category section and root category sections - - // Create direct category to which shortcut will be assigned - var categoryName = StringParser.Parse(bindingCategory.Name); - categoryName = Regex.Replace(categoryName, @"&([^\s])", @"$1"); - categorySection = new ShortcutCategory(categoryName); - categoriesMap.Add(bindingCategory, categorySection); - - // Go down to root level and create all parent categories - var currentBindingCategory = bindingCategory; - var currentShortcutCategory = categorySection; - while (currentBindingCategory.ParentCategory != null) - { - ShortcutCategory parentCategorySection; - - if (!categoriesMap.ContainsKey(currentBindingCategory.ParentCategory)) - { - // Create parent category section if it's not created yet - var parentCategoryName = StringParser.Parse(currentBindingCategory.ParentCategory.Name); - parentCategoryName = Regex.Replace(parentCategoryName, @"&([^\s])", @"$1"); - parentCategorySection = new ShortcutCategory(parentCategoryName); - - categoriesMap.Add(currentBindingCategory.ParentCategory, parentCategorySection); - } - else - { - // Use existing category section as parent category section - parentCategorySection = categoriesMap[currentBindingCategory.ParentCategory]; - } - - // Add current category section to root category section children - if (!parentCategorySection.SubCategories.Contains(currentShortcutCategory)) - { - parentCategorySection.SubCategories.Add(currentShortcutCategory); - } - - currentShortcutCategory = parentCategorySection; - currentBindingCategory = currentBindingCategory.ParentCategory; - } - - // Add root category section to add-in categories list - if (!rootEntries.Contains(currentShortcutCategory)) - { - rootEntries.Add(currentShortcutCategory); - } + rootEntries.Add(shortcutCategory); } - shortcutCategorySections.Add(categorySection); + parentCategories.AddLast(shortcutCategory); } - } + else + { + while (previousDepth >= currentDepth) + { + parentCategories.RemoveLast(); + previousDepth--; + } + goto AddCategory; + } + } + + var inputBindingInfos = CommandManager.FindInputBindingInfos(null, null, null); + foreach (var inputBindingInfo in inputBindingInfos) + { // Get shortcut entry text. Normaly shortcut entry text is equalt to routed command text // but this value can be overriden through InputBindingInfo.RoutedCommandText value var shortcutText = inputBindingInfo.RoutedCommand.Text; @@ -228,27 +195,26 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs // Strip this sign from shortcut entry text shortcutText = Regex.Replace(shortcutText, @"&([^\s])", @"$1"); - var gestures = inputBindingInfo.DefaultGestures; - if(SelectedProfile != null) + var shortcut = new Shortcut(shortcutText, new InputGestureCollection(inputBindingInfo.ActiveGestures)); + shortcutsMap.Add(shortcut, inputBindingInfo); + + // Assign shortcut to all categories it is registered in + if (inputBindingInfo.Categories != null && inputBindingInfo.Categories.Count > 0) { - var userDefinedGestures = SelectedProfile[inputBindingInfo.Identifier]; - if(userDefinedGestures != null) + foreach (var bindingCategory in inputBindingInfo.Categories) { - gestures = userDefinedGestures; + var shortcutCategory = categoriesMap.MapForward(bindingCategory); + shortcutCategory.Shortcuts.Add(shortcut); } } - var shortcut = new Shortcut(shortcutText, gestures); - - // Assign shortcut to all categories it is registered in - foreach (var categorySection in shortcutCategorySections) + else { - categorySection.Shortcuts.Add(shortcut); + rootEntries.Add(shortcut); } - - shortcutsMap.Add(shortcut, inputBindingInfo); } rootEntries.Sort(); + foreach (var entry in rootEntries) { entry.SortSubEntries(); @@ -268,13 +234,13 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs } } - UserDefinedGesturesManager.CurrentProfile = SelectedProfile; - + shortcutsMap.ForEach(p => p.Value.IsModifyed = true); foreach (var pair in shortcutsMap) { pair.Value.IsModifyed = true; } + UserDefinedGesturesManager.CurrentProfile = SelectedProfile; CommandManager.InvokeInputBindingUpdateHandlers(); foreach (var profile in profiles) @@ -472,7 +438,7 @@ namespace ICSharpCode.ShortcutsManagement.Dialogs originalRelatedShortcut.Gestures.Clear(); originalRelatedShortcut.Gestures.AddRange(relatedShortcutCopy.Gestures); - var id = shortcutsMap[originalRelatedShortcut].Identifier; + var id = shortcutsMap.MapForward(originalRelatedShortcut).Identifier; SelectedProfile[id] = new InputGestureCollection(relatedShortcutCopy.Gestures); } } diff --git a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs index 8f7d7ddc84..6c9e0f7d93 100644 --- a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs +++ b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs @@ -202,6 +202,15 @@ namespace ICSharpCode.SharpDevelop.Commands public class ToolMenuBuilder : IMenuItemBuilder { + private static InputBindingCategory externalToolsCategory; + + static ToolMenuBuilder() + { + var categoryName = StringParser.Parse("External tools"); + externalToolsCategory = new InputBindingCategory("/MainMenu/Tools/ExternalTools", categoryName); + ICSharpCode.Core.Presentation.CommandManager.RegisterInputBindingCategory(externalToolsCategory); + } + private bool bindingsAssigned = false; public ICollection BuildItems(Codon codon, object owner) @@ -230,7 +239,7 @@ namespace ICSharpCode.SharpDevelop.Commands var inputBindingInfo = new InputBindingInfo(); inputBindingInfo.OwnerTypeName = CommandManager.DefaultContextName; inputBindingInfo.RoutedCommandName = routedCommandName; - inputBindingInfo.Categories.AddRange(CommandManager.RegisterInputBindingCategories("Main Menu/${res:XML.MainMenu.ToolMenu}/External tools")); + inputBindingInfo.Categories.Add(externalToolsCategory); CommandManager.RegisterInputBinding(inputBindingInfo); } @@ -528,8 +537,15 @@ namespace ICSharpCode.SharpDevelop.Commands inputBindingInfo.RoutedCommandName = routedCommandName; inputBindingInfo.DefaultGestures = gestures; - var menuPath = "Main Menu/${res:XML.MainMenu.ViewMenu}" + (Category == padContent.Category && padContent.Category == "Main" ? "" : "/" + padContent.Category); - inputBindingInfo.Categories.AddRange(CommandManager.RegisterInputBindingCategories(menuPath)); + + var categoryPath = "/MainMenu/View" + (Category == padContent.Category && padContent.Category != "Main" ? "/" + padContent.Class : ""); + var category = ICSharpCode.Core.Presentation.CommandManager.GetInputBindingCategory(categoryPath, false); + if(category == null) { + category = new InputBindingCategory(categoryPath, padContent.Category); + ICSharpCode.Core.Presentation.CommandManager.RegisterInputBindingCategory(category); + } + + inputBindingInfo.Categories.Add(category); inputBindingInfo.AddIn = addIn; CommandManager.RegisterInputBinding(inputBindingInfo); diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index 0c4b141da2..4db95f1f7e 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -75,6 +75,8 @@ namespace ICSharpCode.SharpDevelop.Gui public void Initialize() { + CommandsService.RegisterInputBindingCategories(this, "/SharpDevelop/Workbench/InputBindingCategories"); + // Use shortened assembly qualified name to not lose user defined gestures // when sharp develop is updated CommandManager.DefaultContextName = diff --git a/src/Main/Core/Project/ICSharpCode.Core.csproj b/src/Main/Core/Project/ICSharpCode.Core.csproj index 351cf0e5f8..c6d7bc6158 100644 --- a/src/Main/Core/Project/ICSharpCode.Core.csproj +++ b/src/Main/Core/Project/ICSharpCode.Core.csproj @@ -66,6 +66,7 @@ + diff --git a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingCategoryDoozer.cs b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingCategoryDoozer.cs new file mode 100644 index 0000000000..9527fdda66 --- /dev/null +++ b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/Command/InputBindingCategoryDoozer.cs @@ -0,0 +1,48 @@ +/* + * Created by SharpDevelop. + * User: Administrator + * Date: 7/3/2009 + * Time: 4:50 PM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace ICSharpCode.Core +{ + /// + /// Description of InputBindingInfoCategory. + /// + public class InputBindingCategoryDoozer : IDoozer + { + /// + public bool HandleConditions { + get { + return true; + } + } + + /// + /// Builds InputBindingDescriptor + /// + public object BuildItem(object caller, Codon codon, System.Collections.ArrayList subItems) + { + return new InputBindingCategoryDescriptor(codon, subItems); + } + } + + public class InputBindingCategoryDescriptor + { + public string Id; + public string Text; + public List Children; + + public InputBindingCategoryDescriptor(Codon codon, System.Collections.ArrayList subItems) { + Id = codon.Properties["id"]; + Text = codon.Properties["text"]; + Children = subItems != null ? subItems.Cast().ToList() : new List(); + } + } +} diff --git a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/MenuItem/MenuRootDoozer.cs b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/MenuItem/MenuRootDoozer.cs index ffbfa34f6f..3c10689423 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/MenuItem/MenuRootDoozer.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddIn/DefaultDoozers/MenuItem/MenuRootDoozer.cs @@ -37,11 +37,6 @@ namespace ICSharpCode.Core { get; private set; } - - public string Name - { - get; private set; - } public string Path { @@ -57,10 +52,6 @@ namespace ICSharpCode.Core if(codon.Properties.Contains("category")){ Category = codon.Properties["category"]; } - - if(codon.Properties.Contains("name")){ - Name = codon.Properties["name"]; - } } } } diff --git a/src/Main/Core/Project/Src/AddInTree/AddInTree.cs b/src/Main/Core/Project/Src/AddInTree/AddInTree.cs index 87bc8e279c..8ef65e6643 100644 --- a/src/Main/Core/Project/Src/AddInTree/AddInTree.cs +++ b/src/Main/Core/Project/Src/AddInTree/AddInTree.cs @@ -35,6 +35,7 @@ namespace ICSharpCode.Core doozers.Add("ToolbarItem", new ToolbarItemDoozer()); doozers.Add("Include", new IncludeDoozer()); doozers.Add("InputBinding", new InputBindingDoozer()); + doozers.Add("InputBindingCategory", new InputBindingCategoryDoozer()); doozers.Add("CommandBinding", new CommandBindingDoozer()); doozers.Add("RoutedUICommand", new RoutedUICommandDoozer()); doozers.Add("GesturesPlaceHolder", new GesturesPlaceHolderDoozer()); diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs index 63c0b25f1e..f3123c8e47 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandManager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.IO; @@ -49,7 +50,7 @@ namespace ICSharpCode.Core.Presentation private static Dictionary namedUITypes = new Dictionary(); // Categories - private static List categories = new List(); + public static List InputBindingCategories = new List(); /// /// Register UI element instance accessible by unique name @@ -492,7 +493,11 @@ namespace ICSharpCode.Core.Presentation /// Update handler public static void RegisterClassInputBindingsUpdateHandler(Type ownerType, BindingsUpdatedHandler handler) { - RegisterClassInputBindingsUpdateHandler(ownerType.AssemblyQualifiedName, handler); + // Use shortened assembly qualified name to not lose user defined gestures + // when sharp develop is updated + var ownerTypeName = string.Format("{0}, {1}", ownerType.FullName, ownerType.Assembly.GetName().Name); + + RegisterClassInputBindingsUpdateHandler(ownerTypeName, handler); } /// @@ -593,14 +598,9 @@ namespace ICSharpCode.Core.Presentation private static void InvokeAllBindingUpdateHandlers(System.Collections.IDictionary updateHandlers) { - foreach(var updateHandlerPair in updateHandlers) { + foreach(DictionaryEntry updateHandlerPair in updateHandlers) { // TODO: This can be fixed with .NET 4.0 - List handlers = null; - if(updateHandlerPair is KeyValuePair>) { - handlers = ((KeyValuePair>)updateHandlerPair).Value; - } else if(updateHandlerPair is KeyValuePair>) { - handlers = ((KeyValuePair>)updateHandlerPair).Value; - } + var handlers = (List)updateHandlerPair.Value; if(handlers != null) { foreach(var handler in handlers) { @@ -739,49 +739,62 @@ namespace ICSharpCode.Core.Presentation return gestures; } - /// - /// Register input binding category - /// - /// Format: - /// , - Separates categories - /// / - Describes hierarchy meaning category to the left is child of the category to the right - /// - /// parent/child - /// - /// String representing list of categories. - /// Returns list of categories which can be assigned to input binding - public static List RegisterInputBindingCategories(string categoriesString) { - var registeredCategories = new List(); - - if(string.IsNullOrEmpty(categoriesString)) { - return registeredCategories; + public static InputBindingCategory GetInputBindingCategory(string categoryPath, bool throwWhenNotFound) + { + foreach(var category in InputBindingCategories) { + if(category.Path == categoryPath) { + return category; + } } - // Split categories - var categoryPaths = Regex.Split(categoriesString, @"\s*\,\s*"); - foreach(var categoryPath in categoryPaths) { - // Split category path - var pathEntries = Regex.Split(categoryPath, @"\s*\/\s*").ToList(); - - var accumulatedPath = ""; - InputBindingCategory parentCategory = null; + if(throwWhenNotFound) { + throw new ApplicationException(string.Format("InputBindingCategory with path {0} was not found", categoryPath)); + } + + return null; + } + + public static ICollection GetInputBindingCategoryCollection(string categoryPathCollectionString, bool throwWhenNotFound) + { + var categoryPathCollection = categoryPathCollectionString.Split(','); + var categories = new List(); + foreach(var categoryPath in categoryPathCollection) { + var category = CommandManager.GetInputBindingCategory(categoryPath, throwWhenNotFound); - // In a loop create category hierarchy specified in a path - foreach(var categoryPathEntry in pathEntries) { - accumulatedPath += "/" + categoryPathEntry; - var matchingCategory = categories.FirstOrDefault(c => c.Path == accumulatedPath); - if(matchingCategory == null) { - matchingCategory = new InputBindingCategory(categoryPathEntry, parentCategory); - matchingCategory.Path = accumulatedPath; - categories.Add(matchingCategory); + if(category != null) { + categories.Add(category); + } + } + + return categories; + } + + public static IEnumerable GetInputBindingCategoryChildren(string categoryPath) + { + var categoryDepth = categoryPath.Count(c => c == '/'); + foreach(var currentCategory in InputBindingCategories) { + if(currentCategory.Path.StartsWith(categoryPath)) { + var currentCategoryDepth = currentCategory.Path.Count(c => c == '/'); + + if(currentCategoryDepth == categoryDepth + 1) + { + yield return currentCategory; } - parentCategory = matchingCategory; } - - registeredCategories.Add(parentCategory); + } + } + + public static void RegisterInputBindingCategory(InputBindingCategory category) + { + if(string.IsNullOrEmpty(category.Path)) { + throw new ArgumentException("InputBindingCategory path can not be empty"); + } + + if(string.IsNullOrEmpty(category.Text)) { + throw new ArgumentException("InputBindingCategory text can not be empty"); } - return registeredCategories; + InputBindingCategories.Add(category); } /// diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs index d2445aa543..20e9d751e3 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs @@ -3,6 +3,7 @@ using System.Reflection; using System.Windows.Input; using System.Windows.Documents; using System.Text; +using System.Collections.Generic; using System.Collections; using ICSharpCode.Core; @@ -17,7 +18,7 @@ namespace ICSharpCode.Core.Presentation { var menuRoots = AddInTree.BuildItems(menuRootsLocationPath, caller); foreach(var menuRoot in menuRoots) { - CommandsService.RegisterSingleMenuBindings(menuRoot.Path, caller, menuRoot.Name); + CommandsService.RegisterSingleMenuBindings(menuRoot.Path, caller, menuRoot.Category); } } @@ -69,19 +70,24 @@ namespace ICSharpCode.Core.Presentation var defaultGesture = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromInvariantString(codon.Properties["shortcut"]); inputBindingInfo.DefaultGestures.AddRange(defaultGesture); - var menuCategories = CommandManager.RegisterInputBindingCategories(categoryPath); - inputBindingInfo.Categories.AddRange(menuCategories); + // Menu category + var menuCategory = CommandManager.GetInputBindingCategory(categoryPath, true); + inputBindingInfo.Categories.Add(menuCategory); + // User defined categories if(codon.Properties.Contains("category")) { - var userDefinedCategories = CommandManager.RegisterInputBindingCategories(codon.Properties["category"]); - inputBindingInfo.Categories.AddRange(userDefinedCategories); + var additionalCategories = CommandManager.GetInputBindingCategoryCollection(codon.Properties["category"], true); + inputBindingInfo.Categories.AddRange(additionalCategories); } CommandManager.RegisterInputBinding(inputBindingInfo); } if(item.SubItems != null) { - RegisterSingleMenuBindings(item.SubItems, caller, categoryPath + "/" + item.Codon.Properties["label"]); + var subMenuCategory = new InputBindingCategory(categoryPath + "/" + item.Codon.Id, codon.Properties["label"]); + CommandManager.RegisterInputBindingCategory(subMenuCategory); + + RegisterSingleMenuBindings(item.SubItems, caller, categoryPath + "/" + item.Codon.Id); } } } @@ -102,6 +108,27 @@ namespace ICSharpCode.Core.Presentation RegisterRoutedCommands(typeof(EditingCommands)); } + public static void RegisterInputBindingCategories(object caller, string path) { + var descriptors = AddInTree.BuildItems(path, caller, false); + + foreach(var desc in descriptors) + { + RegisterInputBindingCategories(desc, ""); + } + } + + private static void RegisterInputBindingCategories(InputBindingCategoryDescriptor descriptor, string categoryPath) + { + categoryPath = categoryPath + "/" + descriptor.Id; + var category = new InputBindingCategory(categoryPath, descriptor.Text); + CommandManager.RegisterInputBindingCategory(category); + + foreach(var desc in descriptor.Children) + { + RegisterInputBindingCategories(desc, categoryPath); + } + } + public static void RegisterRoutedUICommands(object caller, string path) { var descriptors = AddInTree.BuildItems(path, caller, false); @@ -161,7 +188,8 @@ namespace ICSharpCode.Core.Presentation } if(!string.IsNullOrEmpty(desc.Category)) { - inputBindingInfo.Categories.AddRange(CommandManager.RegisterInputBindingCategories(desc.Category)); + var categories = CommandManager.GetInputBindingCategoryCollection(desc.Category, true); + inputBindingInfo.Categories.AddRange(categories); } CommandManager.RegisterInputBinding(inputBindingInfo); @@ -194,7 +222,8 @@ namespace ICSharpCode.Core.Presentation } if(!string.IsNullOrEmpty(desc.Category)) { - inputBindingInfo.Categories.AddRange(CommandManager.RegisterInputBindingCategories(desc.Category)); + var categories = CommandManager.GetInputBindingCategoryCollection(desc.Category, true); + inputBindingInfo.Categories.AddRange(categories); } CommandManager.RegisterInputBinding(inputBindingInfo); diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategory.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategory.cs index 0fed535ec6..d388666109 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategory.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategory.cs @@ -1,4 +1,6 @@ using System; +using System.Linq; +using System.Collections.Generic; namespace ICSharpCode.Core.Presentation { @@ -12,16 +14,20 @@ namespace ICSharpCode.Core.Presentation /// /// Category name /// Parent category (null - root level category) - public InputBindingCategory(string name, InputBindingCategory parentCategory) + public InputBindingCategory(string path, string text) { - Name = name; - ParentCategory = parentCategory; + if(path == "/ContextMenus/Tabs") + { + + } + Path = path; + Text = text; } /// /// Category name /// - public string Name + public string Text { get; set; } @@ -29,9 +35,12 @@ namespace ICSharpCode.Core.Presentation /// /// Reference to parent category /// - public InputBindingCategory ParentCategory + public List Children { - get; set; + get + { + return CommandManager.GetInputBindingCategoryChildren(Path).ToList(); + } } /// @@ -40,8 +49,12 @@ namespace ICSharpCode.Core.Presentation /// Format: /// /category/subcategory /// - internal string Path { + public string Path { get; set; } + + public override string ToString() { + return Path; + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategoryCollection.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategoryCollection.cs new file mode 100644 index 0000000000..1fd6a09780 --- /dev/null +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingCategoryCollection.cs @@ -0,0 +1,85 @@ +/* + * Created by SharpDevelop. + * User: Administrator + * Date: 7/4/2009 + * Time: 9:02 PM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ +using System; +using System.Collections.Generic; + +namespace ICSharpCode.Core.Presentation +{ + /// + /// Description of InputBindingCategoryCollection. + /// + public class InputBindingCategoryCollection : ICollection + { + private List categories = new List(); + + public InputBindingCategoryCollection() + { + } + + public int Count { + get { + return categories.Count; + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + public void Add(InputBindingCategory category) + { + if(category == null) { + throw new ArgumentException("InputBindingCategory can not be null"); + } + + if(!categories.Contains(category)) { + categories.Add(category); + } + } + + public void Clear() + { + categories.Clear(); + } + + public bool Contains(InputBindingCategory category) + { + return categories.Contains(category); + } + + public void AddRange(IEnumerable categories) + { + foreach(var category in categories) { + Add(category); + } + } + + public void CopyTo(InputBindingCategory[] array, int arrayIndex) + { + categories.CopyTo(array, arrayIndex); + } + + public bool Remove(InputBindingCategory category) + { + return categories.Remove(category); + } + + public IEnumerator GetEnumerator() + { + return categories.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return categories.GetEnumerator(); + } + } +} diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs index 67f9463965..c86d32ccbb 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs @@ -19,8 +19,7 @@ namespace ICSharpCode.Core.Presentation OldInputBindings = new InputBindingCollection(); NewInputBindings = new InputBindingCollection(); DefaultGestures = new InputGestureCollection(); - - Categories = new List(); + Categories = new InputBindingCategoryCollection(); } public string ownerInstanceName; @@ -179,7 +178,7 @@ namespace ICSharpCode.Core.Presentation /// /// List of categories associated with input binding /// - public List Categories { + public InputBindingCategoryCollection Categories { get; private set; } diff --git a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj index da7c657ddd..9db7d439f2 100644 --- a/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj +++ b/src/Main/ICSharpCode.Core.Presentation/ICSharpCode.Core.Presentation.csproj @@ -72,6 +72,7 @@ +