From a1b74dfb38af72eff4565f2d7d712697e74e899c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 3 Oct 2006 14:23:40 +0000 Subject: [PATCH] Add ResourceToolkit AddIn (from hornung.dynalias.com/svn/resourcetoolkit/trunk, rev 70). git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1866 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- data/resources/StringResources.de.resources | Bin 224805 -> 229903 bytes .../resources/StringResources.es-mx.resources | Bin 285249 -> 285532 bytes data/resources/StringResources.es.resources | Bin 285394 -> 285676 bytes data/resources/StringResources.nl.resources | Bin 279849 -> 280111 bytes data/resources/StringResources.pl.resources | Bin 235694 -> 244136 bytes data/resources/StringResources.tr.resources | Bin 224327 -> 224551 bytes .../Project/Configuration/AssemblyInfo.cs | 33 + .../Project/Hornung.ResourceToolkit.addin | 135 ++ .../Project/ResourceToolkit.csproj | 132 ++ .../Resources/EditStringResourceDialog.xfrm | 73 ++ ...NRefactoryResourceCodeCompletionBinding.cs | 59 + .../CSharpResourceCodeCompletionBinding.cs | 40 + ...rpCodeCoreResourceCodeCompletionBinding.cs | 69 + .../NewResourceCodeCompletionData.cs | 63 + .../ResourceCodeCompletionData.cs | 70 + .../ResourceCodeCompletionDataProvider.cs | 75 ++ .../VBNetResourceCodeCompletionBinding.cs | 40 + .../Src/Commands/RefactoringCommands.cs | 57 + .../Commands/TextEditorContextMenuBuilder.cs | 150 +++ .../Src/Gui/EditStringResourceDialog.cs | 83 ++ .../Src/Gui/UnusedResourceKeysViewContent.cs | 316 +++++ .../Src/ProjectFileDictionaryService.cs | 90 ++ .../Refactoring/AnyResourceReferenceFinder.cs | 83 ++ .../Refactoring/IResourceReferenceFinder.cs | 35 + .../Refactoring/ResourceRefactoringService.cs | 364 ++++++ .../SpecificResourceReferenceFinder.cs | 93 ++ .../Src/Resolver/AbstractResourceResolver.cs | 112 ++ .../Resolver/BclNRefactoryResourceResolver.cs | 458 +++++++ ...SharpCodeCoreNRefactoryResourceResolver.cs | 154 +++ .../ICSharpCodeCoreResourceResolver.cs | 299 +++++ .../Resolver/INRefactoryResourceResolver.cs | 44 + .../Project/Src/Resolver/IResourceResolver.cs | 56 + .../Src/Resolver/NRefactoryAstCacheService.cs | 94 ++ .../Resolver/NRefactoryResourceResolver.cs | 390 ++++++ .../Src/Resolver/NodeTrackingAstVisitor.cs | 1144 +++++++++++++++++ .../Resolver/PositionTrackingAstVisitor.cs | 142 ++ .../PropertyFieldAssociationVisitor.cs | 242 ++++ .../Src/Resolver/ResourceResolveResult.cs | 80 ++ .../DefaultBclResourceFileContentFactory.cs | 63 + .../DefaultFileLocalizedResourcesFinder.cs | 109 ++ .../ILocalizedResourcesFinder.cs | 26 + .../IMultiResourceFileContent.cs | 26 + .../IResourceFileContent.cs | 82 ++ .../IResourceFileContentFactory.cs | 33 + .../MergedResourceFileContent.cs | 213 +++ .../ResXResourceFileContent.cs | 89 ++ .../ResourceFileContentRegistry.cs | 120 ++ .../ResourcesResourceFileContent.cs | 270 ++++ .../Project/Src/ResourceResolverService.cs | 136 ++ .../Src/ToolTips/ResourceToolTipProvider.cs | 48 + .../Project/ICSharpCode.SharpDevelop.csproj | 2 +- .../Resources/StringResources.resources | Bin 272973 -> 277128 bytes src/SharpDevelop.sln | 9 +- 53 files changed, 6499 insertions(+), 2 deletions(-) create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Configuration/AssemblyInfo.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Resources/EditStringResourceDialog.xfrm create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/CSharpResourceCodeCompletionBinding.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/NewResourceCodeCompletionData.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionData.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionDataProvider.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/VBNetResourceCodeCompletionBinding.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/EditStringResourceDialog.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/UnusedResourceKeysViewContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/AnyResourceReferenceFinder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/IResourceReferenceFinder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/SpecificResourceReferenceFinder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NodeTrackingAstVisitor.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultBclResourceFileContentFactory.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultFileLocalizedResourcesFinder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ILocalizedResourcesFinder.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IMultiResourceFileContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContentFactory.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/MergedResourceFileContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResXResourceFileContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourceFileContentRegistry.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourcesResourceFileContent.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs create mode 100644 src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs diff --git a/data/resources/StringResources.de.resources b/data/resources/StringResources.de.resources index bbb60886152d0518223deca4caba6e9d3bcbc7b7..f45b1abf8036ef4e9a6c14c352708d319e0061b4 100644 GIT binary patch delta 27972 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 tGh}&e6#B4Efs-5x5;i}i{C~$R6CD5m delta 23593 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 Q(#U@N_gIAj*}fV2e_);F6aWAK diff --git a/data/resources/StringResources.es-mx.resources b/data/resources/StringResources.es-mx.resources index 4e86aac426d445d6cf66371d1f7ba28cf3616cb7..ab73446e751d9901daaddbbe37d35fc45d9fce57 100644 GIT binary patch delta 26862 zcmZu(2V54%)1IC4P!SLj5fKrI1sh^R#fFNC9c%1j>_!257g1yHC}S6UV#RLkU8Ba{ zW7pVX*VxPV>>UE;|0TZ{-kqJ@ot^T`?B3ztjhU`)&NOAAO1o~+6<6c;DnD-+l&Ma} zm>GGQ3KnOovs}@(8cfgKh#FNQ%CkjLl@5vmYA8BHOa*Q-wfdXr$Wo?veEEelPG(4WDw2MLc zmnaHbPt=_XncYShRd;MPvM!Hv17RbWv2J6jRemicT+P@{D3?d!A{`ycnX1 zixo{U!PuJU?HZ!cDMY`y6aDUGP?1uKmYrm}Sd^(gv=Ew!Xm2c0%dbow<}!6YL$vuU z(=j62>cMoqzM>;_i0-5(Dt<}P_Gv^v_hdTqoGDXFqUn)LPF09rz9DKA&-7Q!Bc?W3 zXaYXP@F^Ov==JYRqnj{AgeZzXuPE>qBy}>V=W?be6PSD*6=hz>)cO_EZkVn)7Ad_6 z=1`DghN5}X6}^B7j%QVLVh|C#Fb#1g$}kM`!KAy6D$4g3-?4VgppJ@i3sb+&*i8?j z9v7MRtztR|waz-obfAl(J6E8Uy-d@F;`bXS@9m15FTfNvnF{DxVo9A#QF2%0Dvqv)r!OxfTtjXE&By#&eEDEf2= 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 delta 26827 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 DeN2W5 diff --git a/data/resources/StringResources.es.resources b/data/resources/StringResources.es.resources index 2f71791f0d6fb2fc3f9887e063f6883df6d6ded5..62b4870f85dc09b19ed57df019ec7ae7ffa79482 100644 GIT binary patch delta 26927 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

6%1F0!0)LM z4j~|nO3gO#N2udRd07eSz&L-I8;baD_*%Pbb?)%mR;#t4!WH3l{a>fjW!H)rJYI%X zG$PeZxmnR@!OLIkG?lc)o|OPzo3UhjnGuHMkueN~(!R=uzH7ybea(yLi~7C~Xa{1e zWTHPme61ZKY0Bs@SUcUD?| z`Nzfui_*DI}tTVv5KC<|+$4C@bK zpe6?Lq_?)jm?prC13f_6)JA0Qdux?Radohf>$NfQF>509Rh9nru(5}4t$kYz6~f`a z+1^?ENG72Awr@A{yt5=t?vP{Q7+?CGWj9dsbCY*EdUN2jkIT24({S8K_rpk?!l&0k z?w){#&Ez4U>lmJRQ!u(NVoQIvMcSN-V|@fTPT3s#v(0e}3!$peqGYr$zPrO0^ea>U zXx8?e=DjX-EK!@)GrY~*@3lIy>p(%f1ebnq`{VTbaR0XN@q)flUGln3aPvW}y^_SFBLf!7C}vMO-M2kl+u zxQ_L=h*W3@2kY>`c5rLh@P;r&pAVKz>*L;IXG0@|r+l!5a%~KuHenTAIHBPtEp(N) z{e$gb7G+)|g!6$Ep4@y1UyaaJCb~oT&kwf7(a7tbl5KRXM4^a&@xd;h(d{04dZB|{ z$140WWjZ&>*#wnnwvXD8EFX_(f(7$`wD+JJBAQYxHRYzJRQ+g&mgd3tJL)3>yITpn zF(!+UJxvYV@H90Fn(eH~b=%Rt!|y=DKFZFfMhEk!|Ej;ljHNvr0VXxb-z_1dO6ZgZmXs4`wu3k1_DP(wAm z(MsxkGP2YTuNc+WH{X!JVfg|a9V2@7_U+iFKYq9C8P%~%r+&RV_;zpO+plexc5T{q xIj||pw|$51zHNH9>)fS(Pu~t*JGAT9w@usb9YFTg6G_NP!*8qeS>w=z{{zHmxwrrT delta 26749 zcmZu(2Yip$*FX0>o**KLh=_=Y)D{sdB8b>Q5PK6_)d)gs#%OEQ2*I&q*WT1#wRh}2 zilSDGQnlXieV#0R|Ly0OU+%f*-h1vD-*fJLo_P9OwsTvu#Vu408x~!2-83RwgiCDZ zf=mgenD#GI6i}Nf$&IK<6{1;N75&y((-ege)BM{^Z66R-T*}n*7p5`?h=v=AnzUE+ z!x=?gk1>s(%~UBD(GF*#c}|Kl4^VV^CeyVD@I*0no5mDam?_6yMThe;weHKYbhICun&NEG5hsJ*^&+bCiYQAhrk^uml97sDbs-uxgJ^YDgXS$( z6uyz@;(n$fnDoKFMEPbxkYGh0^D%ApBUk?VL(GhP zp(%6`6{g7XqM{{tm_BAP=+9+L9VRgOIw~5op6T2xrqZRET49mkEieEikC~<@8$K_g z^piQE@F7G4voa0KN)#K5`MM}7bzIS$xA+~4zd(ED45laDu$jI@4=ynUt!65}1k70v zF$I6C=-xG=ZTpy}4#)T3OmRCDjl2lu*J1MaS2QV?0Pa~DEWE)XDws74#65yhBp zv}P)Nkm!76rd^RteO@qC?#Z;^!=NqPX0O&N?xj!7gL4aOeXjhx<%sDMjUm!aa`@ zWiJa2S7Ms>BfhV|mEoR#Llo^PtLTyg(?q!C(aucou0Zg$ilPrIijCQ&C~S|S4)ckY z)?iwDim6}+*mN*a-r__v>A#b}}z*9(x@jXb3U@hWc(DAEG#y7BG2zIoK$UUP$zf>hEd`^*f0iwEviMlq1-wb04 zL#*sy%arph)0PEHnd&NfautggA}aeUg!_Vci(%Tgq5&ej15q44-%n=Bvx#X89HVb% zqUJ4__Wp~-M!@mHn0_y>XjTu{8jkf6KC<^OBBz>I5JEf%SM(WC-Xp$vft<1XS|ZMY z3$Hwhy!R>c{75t*hoW(<6+IkB6qSK!w>OgyysJrVqSupwJ@CSFl@zV3r6{2z(HD5l z?~rQYc%odZVIN45ZL^}tu8`D0Q5#4$@FCOF*G!{IAwF*@dQgez@1LO4R@aG~5xC`l zV>&R9=;J>`1HNZ+>_pV>jiU446LlX+)NK_2>;wdx&*TPUy$84r0ncHRsKEk7f36}5 zISrtD4Lr(V(A`-?Co&s!7*25Mm7*&}iJk$Q`XUD3jv{6mH=+mdMj%GLeah&Fg)h*G!?DDTsc1jorYl(u~UfJ0s+4OQEnh8r|p6712!BH znB@?}2pgJOo#_sMu-8(e4+zG7(9r!JMAiOMQVF!p{^`WFChQ6%}>KjTmW3)TS)cW?<&< z>_k@~`Bu33AJKrOt?;(7M0;S{_5F!HLCB?1pkasmVf&d=fg+2THYF%320t3~p6ECb zYv?vbdE69z!ly1mqTSEPHDy&ST}8ay+)VTxVj=TsrW)B0E5nh5E-88(4mGuBYJUoW ziWqWOp``|N)_<$xOdC!{;#^b1=aD348+Zc(k~p2?(3(jo>RAn5x4M z8Y6x)!{i?j-RCu?*2{vR&O@}g98G={!B+cD=K)C zY4`<2|HJ}l-#Q=y5Q5L)xwq+n~GF-(8P0R=KMoy!YHn*C0I{uqd*sdwxaN zf)q{6r>G1BukMfNIjg8zH-P&zKx0#w3#R)-289BPb9Vty6aYNB0unPR3jV~D6())` z>nMs^Nz}Uo)4U6Ctdnr4VnF-bLWP>h ziZWo;9-`@`F?oohN*|!nsfva@0O0Q?3ap1D0n~Za525@IoN)$GhfzrC#W{esd(E&Kp8#6K>QJN9&6MdRPVQ!*m)4b#Yr{1d6@ zZU|8XJZBF)X=H6!e>{`(BS6+3re%{9U7yR89a;E(bEXRLxV3FijUYjG|3%RUloKBt z0sNrmNtWh!PGrU`Hb zk2`?!;Lqo%c1ytaH4#L!dtpaVWynILltoA_-vDC1CGzMC`{maG2Df{Sq=;a<*p6w6 zTYQMWS8Ogg)TnUaIkeu#OVPh5yk4wlazW{G8R(S}@*8Mxic-X@m_GMpsy7WwEGOF8 z9vN*6(>B2ET|`Yq@O?zStpm4e{v7lD%@ps5dEh=%@!542`x~Ih*V~|D%bC76DVAcO z)!8lv1zuK^I~S^5_~P3!id=IteLE6qb|#YtDu}Ir09xVOSK&sreSWJRc(2e5a@_c6dBk zQ7&M4?fWpx0wflwI_6KJIVX^QGa|niVJeXWS&)#oCn`GmJr>2pNf4+Q5bpPF03%lv zc}QZ>g1M334*^ZTz!d9Zi3YXBoJX1NzE|}393Wn^(@cxuYgOkn^;)iIzzArhF;Pxb zCJ{9O3rPSW7r0hW_~|%B>H^Va6z~V$qS&8~x~mpU#RfI#k6h3X)ntr9SzyrAXe63} zOkE<8KgKJ%cpvb)6QJhHl;t`CaWPY(kIG2j04n1a#a{~Wi`|hM=m|?PlyR&W_<*3- zN+4+gZj4amlz2to4n(H)B5DMg7hF`dSV7}Jo)f*1Tc#`OhIDWZX`tvKMMvNgYf-&M zK-LQ1LKy}MNFa-s2{d;Fx;#L3MoRcT9xHC!u?0;)^ z)IH!knHBE#l<4P!D4@0wJ%$^G-aoDR7f2~Bp*e{(FIZc3w zKciX!a6wztrVZ426{<#9cXB|Ag+0DGiqh*I!0#v7#GOYxE!kf%!p&))pUSg5!iF^71V!o0j!sBrrHEY zL&33U19SrW--d0n0BT|?p@3Yf=vFn<)_1TW=%I}-6!!q09NYjYbUV}fRZQXW*-B=Q z-3zz79FH?H;I2e-qJ$>c8{DlTraceTT7prNd=-Uy;833j^~pRyRBjYsVMq{Lkj){^ zvTJ~v{1D{~4(%s^YB`W#heP}yapGEngo1Iy5y1VrDrx{p9s*_dmj}HMU}wPJivB1H z44MMtR3d60i3qKxs63)ScK}XA@Wt74m>z{7Z5}~cfdD+}34ew^)rWueg8!_6kyh*i z{0xC#2Oz0b$HBKH5Cfke_-i(tv`PbZdpslBI2R?xIXE}`xv&=^asNw2Es&*F&Bg%) ziY{~xMyZOUmkFhpQB-pRqO}oGhBzEUegeL)LE#N8ZA3{iZl$8(@TfLe{K-FxsvzIb z=*#2_gN%e`zIR703=NQjqJ!0Nj33Wb3l(0Sii*kx6P=1h$~*rC-d`AJk?%ohjKsei z=za;uGE{j{P}7ALOg|y&pTm;Jp!&ZcOvzbr(CLVcrr486N2j-qG6s$yTglN_q}m>gB14bCY*PWy`rX|fU1m% z0Gyk50%#2!h zJ1Vpv5EoGI@tJTccPt!>3{XhXvs_3k5kv*Dpge`&AKr#jLp_{#P*lvkgv*OpxIg%r z>B=zVeUz9PvMGA!0+XWhsRa;ddmi>z85Q-$X9EPNa|qszg!tuGoTk^K;=s3hgUg4T zsCf~zj}V+*&*8a$!u~H1Q}})AAfj?U0H83O3hE*S;pE^It>_$V|LhS!6Gw}Pjfk*D z06&;ySA7Trm)MSo35y-ag!$=p6-b&zs|86m3FnYPn5;Nz-!O#XP@o$8V{ZYh*>=?1p%Hvrzh5E>i_C(eX=uLKJ5KQQ-BXsV;46Af@J z2EHFdhA8t}gxhz(szFT4gPHQSM`COSpZF14D2cKm7wR^cV5z_)9dYjY1G}1q zU1SFoJwlz_4gyUBZajv!pF~x91TWbO|isAq~8W{jKocf%o3X*5VytqT^fn&x*R0Ho66$1J#evb;Y0(=6oJO-bC zV6p-8fs)YF+j>j`0bZZ6>!mpL7talC0Mw=_?7S5!1~_PBTSYgEtWcDHD{O(Rn9xDd zmj^i0KE=@y=ad(SfP<*eBI*$Rdm#RBkYDWe9jJ6yFkKphq}&o0WY-{jV>o&s_ zFb~HCSh)*yQlS_MWYlyOzekqKuj0Fv%N85;55W2=3d+kc++q}@Jy9FpMXX!_|5T>K zFxrLT0Ahgdq=~q6h{Dy&9j0ag`De!wW2JEBxq%#%h~OTNtIpjxlwhsinIS?(+hN{Rb)}S`E6zxJ_6)lQmdOTduAGakh#~3_5qgHr@w*#TCQ}uMZMxI4-u4_j1CN_i#I01N5Kz5mklM@Bcz^GYBU? zNPn%DqP4gah<}K5wjOyEF75)iJpnfudlQ!qaFJ!xp&@4+$ycEGiEmpzXY6M<#;%O0 zOt77|Jr%8KL-Y;w=R5;}0`QE4NP9nGb!UV#jModNt;36OV}+y_2E3XFhl_!O3~zz^ zI;5HY%@J7G;+Q4?7v+jPocYt~&|Fe&+-DhMt$^gaLw) zhr$8vzX5s2qqO`PcW4)ZFOyITRsbp^V}J7!TMI^R8Gu|>mdGV5%IWSng_yvsg7Csm zifSJry14+0fv0g_Me`q_p81(*UJcI3Q2PScK~S zXQ<(@xrVq6V$1}Bw{CX1Qh|gT1 zP;A5BQK|I6c?6M^Z5X1x93r@V#c{#@0?9J~Pk}b$*#A8$wRk*GLd`M^u)K8*oa;R@eI`Y}WJ87q(s#pW>@ie( z&49@ZS29H*oa)8rtCTbLCj{KA0|=C=igt`eQE*#PJka{g6`(u9c^uF_0pi@9hg7)( zX|1@T0&NsMNB-W9RM)!<(k0yRNAxv%hld5<;2vf^P`(PzqIXgLR>X6i8PLfDTza-f z<(rr23G#RbxbL$l=p$<*K>bqeA3|I^&*a-3x1`9y&F7$|CfqD#LmgEF00<<`g9wku zS?qj%1erH*1wQ^dx1ztA0J;&dbpibW9f2#aff%`f&WM@5s7Ss;hTGa(k$(&h+kFsg zYf&b(gHGBZ_-^gQF0t?rEuevNxXOdYFI0d5E~6wGiQG39mBuh2g9{F-2-NT|NT)k7 z5j3)3}6hU*O@9r$Ic<*PZD)HifVQn4qZU_ zpJMX>LZHIa8*!-zO!G&yw?@s>!V4zoi$n!!=bi!r-zVy`1eYOz_$4?XJPAayPk`qv zhdS3Ge4Zn5Vc{akIjvyev+$&QSx}Qr#wAcO)bVGrTT%4J2{%b+@VvqUPsG9zNn=7# z*kOmKQCSw>2m5bA7(GL2)DD0t5Kh~=Iqnw_N)uNh5eDK|Jcnt=IYm9{p}axG;qV9I zwF`33IpmW8c(~z<5bTIV1|O+e0|~A>?mF_og>&KA&nTpf;zZFQaL2X)U!xnO2|{Wf zgDi@`ynY`~WWPf#hT3@+Fze-0qD4)CcZYDa`2{6#D13T2jzFmAdduQ}CLA>s zruqiA@SovWFCg$Gvi|c1k3XR8!bTL6nPCfT%3&r^A(R47R>A%^U2wrr8np`4cpt%+ zBNNgH()%kI?%4)K8!w{vhPp#A_|JDJ^!g(*YQp39qn_)csQ`zE;0>VOQ4@?a%=qY=_m^@=$5gnvK;X96ljAx)nG5XS*l zUZH+yibLQ>Tx|QnIrkzr*2H}jZd)=oMv>DN=n#Lms`u#3ResA{MYV1ruTQC5617md zOP<-Pk;*I4v(*?5>n|@)sobd@0n%)a%Fn&}%id|qJ01Dj997he?T>S&yqu-{rNlht zBvP;+#0?=ICZT|da|14@HFD# zC8|Cr46rp7w^Vsa-KCgq?*Pf$5CVWw)4T@uWVK~n219)sAnO8B6x(K*@>AI)cA09! zz5}&pyk*3%s*%+F6&ooHwP;g=($y?K5cP^|SgF2~X3Lc~HykK|?yz6naus8?LFah8 zGiHVI3Kl$5Z6`8 zL84bH2R=Gb@{X}Z3YY7v;YardYPJ5TSe~y|Z6$GyDr}BH3hOCT_Nr16xK@Sm_#dQ0 z9qie61Ke!)S{Q7`5B5B%6sG_Rr*Ek@#n7Q2q{`1&!|HQfuRQqk589*BD86QvL4ZKL zLXd=RP@XbuJzOIUL~Ge}M3=OATci7DNj#*==`oS~%OKluSSLh$HmOX!V^HeKHbo*f zDo69cSMz#nUN7@65C^78U=j24he7GK<+K^*EX_KmB)*bw{fJs}Ft2l2_ z&So@v(q{9NlpaqWJviNzAm`_eX;XS@#sEG#ICUpMa(1h7;(rIH?!=;aFb}bv($ebO z-;^sC9g@x}pm=d3@M!D0?pFb#wkdxeGeo;!ExEHx6_)wiVDH&OY&W%dK5kPLc`+z@ zi@pZ{RiG4<727fWrXdac;|AGNZtqZzeER?OwcZIAeUV;> z=R1{~QlfUL>1Jl+u-V$8HMD@u*mtN*X$3!nY#}^tsE+9&W&)Tj)i#k^djNrb_9zc? z8;FCo^(988lZ)5Gn&Ta!H#~oD}R8FNhUQi+CpwT*GTi6+S8JeGdLAjcc_Y#X-{*rRdP?G-qUmb4d%pa41w3N*~_Y$I`1J1P; zx+W8i%OGz0iWtb3fu&PyP_|a`cKjAW&=X%nDbjJ%zhp#`EIBglH~@< zh^ba%rMV0zoSD+$imE63-lJ|fbsaWucoWHU&sbgG1nKGP$djAMBB#dM_OK|UZy_N6 z7^{7!g&tK@ir+>qc9+Q8Y8E#fmu~QPcQCm1xOA-MU7%9bI6L-IHqn{m#@W_i_lIgH zE&qUtmW;zeDV=y{?qjb{{!rEV$~Y-`Pp#(SlEiD$?A7yS6*&HZb{-sw(nW)lo+z@SbWZ7Gc<5z+}`rf2sYP z{}*kh7BcxcVDsS<<)JFe=O=2X8ID^2bo!|@LxX217-N1(HH@Dg7b>xTA%V>O#f}!( z%OZE?4Zmp7rpbxt$QTP>phP^6N!O>J^rZ@ocbVcK&6D5*?=Aj=W|j$Gn_==xpisbs z^wVRU{PYTFRvEniol&a2hA|`2v-v-3$@|xU<+kYA@jrUpb4ZwWt}kWNo~-=X%*Fj0F^3qhl3 z{NytZBL4sqLnfx1U3UqLonsr}g+Bw|&V9m0bHpX*_Rp#fz;oDV zH4iCnibCx%;|oTVh|?3*mph96rw6hJmyb&ZZ)f(jsRy_yH;j`74m?=8D=w@$=<%~S zCOxOG!6CAl*&7>3WM0Eh<8&0wFbho41;NPA>U)`*f%8L^2@Y8NMLndYV3YmK%4rOi zPOh2k3w!`qtPFO*h|c==#T-3F8Wse4#H9!p?>i)e9LUHhn5W3_&j6{YOlZV`@3zi9 zDSYxd6Z`P2DdLlv=kl*pwB^%x2RU*8uT4Mu0w?y9OO7099!n9fu2{q$vVb?=)O1sT z940|d?8QG#)s|158RT|+ekyX;TK*!V45A{wf93Qb)|k*4wocn>>0;97oNxK zZaRMc+|Ay^2LMO#Rqoxi1$i# zgIoQj*f^~kDh1vOg>FvR;{Lt#0#?Pk7q`jy)_vK_aX`7S%nWyVA!J-hl=Rj93WkDabcc1-Bt!DO=ftphdF<` zcBd)c+)FoQz88C{ZL;5;%gKvk>^37eH{yHK^*+P(@A5o1<~3&6k-UCAKuWVoq&HVY zi8|363Xhs$<9%v}tj_~&O`BmA9$!)FQl2quq_y1VGS0SwbVCH|<*JLSB7&Csc`qtyp zC8;p)<{`7RVK=H(5?Yws&d6psOKdSNEPofpJXdCEh_d$B(=0z*hYQ@KhO{llt)#U- zEIMYk-qKW_H(R@dx8yC(-AxBvuv&-sT)N#z-W3Oic}a%=E+gRq@UCF}dxWYlssvY+ zqyTnRgY@r>%()mEEq#OFtUsfVH_x%p|IsCI3BZBy^J8;#RaH_Z269b)Fh_h>Vp(*1 z%H%+}LY|Ubo&TAm?P`%dqP8tZY97D}J?uS|FUu9p zM6`RRwhPPIvd9rv=h_Oi1WO2l1?~sKshb4BWOwG;_ckegb@P<7InLTa06nzJ$am%0(L4rXN4Z-b zc)7Yf^nPnzI$gMga3sH+r|s}PXP%!u99W!ox!nm0fsLa0RX|$v5_JYdDD^C-2?VfB}3@an~!a)A=A9ARy4g(x}El9UT zaMv+QEJ&SiS``eevcPsqbQYG(RoTa^2acZhileFmWLuzZ?W~!+uFCn%4rnJ!*smJA zYVd+&_}0eRTb+x_i)xs7?1FT92RY1^XyyW$RGo+M=Jb-GJ4j+`usa`LkPP~IGE1g= zHQ-0r(o1=!CKMS}likhxX`2Dji(jS}#Tvb{7OLsUT2RIN|JCQsnHK(cL2F28I6Ij+ z7i#ynY_T*P=J%BjwE!RPwE+r6rDSc6F@wMosaeX%Es)KcXh+%YOo8yIDs|XLHIb+~ z$PHZ<+QIgv4*Q!wrZM(#Hk{*qUuTlRb)oKr|Iu+99lR!aIQHcr0TEmfB|hd2mWdHS zh!+?ZCixn(zm%&7)nvxAjfm8?FXvvAd>X6|s2N)i!5y5&ajzci7`{ld#ly3F>%+)h z(HUY5k5Ag2!KF8~pvDwIO{hOQI@dJ(L z?7CRrBbBu03uuIb#anko$WM*nLq!(bo`*RD<&(AuZu`7hAvx6_(f*Pa%79uO|3IB-;_@+kw>k#lX(pf$%aZ|Ypgx6H8%rto@&h< zRaXgYgX(MkQu)%CbIH6mNFSS*>R_o7h0sRZUwqr5D!9H>sw8vR6z2vs0GA5U*3VZ< zWlCGF$F-M9$u?X;hHhdfr!LgYy3FfHO_xbnv^~9_^lryxxWh7g!QJh!VEi&|yp#p~ zB&a<~;T6lIa<7yz^V-7)PAp3m!B0G+I6uE!CZSPW+ziIE;4nRbmyC}>#MP7yQ5>qG zB`J#Q@XTMeaJi&u2Q0k$R~b3hZn(>~4(w_Ej=>$J!ystpLkCE69PQqzZBH585$Wmr zuj0~)Ys=pq0dw!IMhBH$`gTH%;J;iFf8-((^)1%_*a@efV9D2+n>mCn$6LM1p33Un z-I*g*ggAHMSq@#$IXivlvo74qVI-(C(^DsQt_E6( zmcSld)ohM-_0(A%<<}knvi2YjwuyiC;3nK{g=~mMlIi*#cXk+n&YzRz$6G>C<~R@{ zG*HTzA@0vb{ z&_h_H5BK7yE43H*Q7*DRnkOT*g!Ki;4PIrd)0*j*en5)Hec7FtuhI_Q)ZDx(*)F97 zon`p+D%szU+w-+mwo^t8M3vRNKdkV_D(TywYnypjYpB+`iEq@~BYxF=C$kku6>at0 zj$uchxmt%Ao@x#RfF-OJmoCsW1PGGM131`WBiKh+>MkYVFDiuxLaZ$V*v(f;9LW8+%^JP+vU-eo@Y4hFg{9>iWMqwE=kIx_oO+c;4} zpqoyEq0NA`$v&$odj=!TR$H5HaPA?fDk9QThJs=?TdT7?)~YHuhX8>)r01wQ6bnX6 z+o2p`4hCbgJKh1Awka5p;cLaA;&1KCWc!bt;G(5!IfcJ^C(h5r8j|jco8*Ds4!(Tp(MsCdy4oj^TM~GSNtG2s1 z{{$mxPSst`{)pq+`2R56NM%^B8A1hwqI_wCR!9+9H3p^6+@FCd)u=j=;LifvaE6U~ zPw6@(>ll=NS@H5hGIpm9(>ZeJ%a?uy*Ib`G*#$&CGwizP7g|RGlkFi+AA9F<7 z8@7nwj)ith%ZRaDQ&rPn73IlzY$ihgUQ~j|0TP>GOsG8uZxMTP+hp-{L#}~?yQHU- zACED;F~-8Uf-+(}VCDN{aiYf~(YEpAO!2Hqvj9iBzR_ZJ-05+-2sKQ`J{vnZ|;*-gFFN+@cvIM#$(^b>&$ zn{17^{=#J(YQrhBY_cNn&cFpW*#T*hBPX*1=KR)DcGdI) z(BsAR((`VgjAEkoCLK1(lX}GAP}@EI!gv?KQRc+K_s49qQ4#_c&ek85tu|>Fth0O* z-T|=zl369-7J&DxIcbu9(fXt6H-kpN6Z4SyFN; zN`p4jIn22xwqPr&GcDY#b(>3f)aR{fjjGuO;E_!yY_vcAKaWLfitkK7cAXi(!pEB> zY6kZ;3vJQSY|&97dzqEc4!7HQBg2D7ZIQmh)y!W(?`YGX=o^mhTO`j+u4SG8eYl*R zg?fAoCO2=O-P3Ld&w}OiZPn`lpl0EOUrJ8S;-O~Gtwg0}%;AF0wUAw_VlSQOJDR;! zM$YCcylAU@n$0CMHGsD`{HVlKBZ z3xX1^naaq`x!7d6-^67#7mz#iI2ah$a2|J8ctZvke_11-zus7ND2DWudW;cX=#4?0w@HJ=TuB1w;Y>7X0m7u0 zEL;G*8M#fqEZ|x^%lfV)UU>~iwOIFs%7R5GHm)rMHm=zw&lhrk^U5~u2QL@mPJZ(u z95ixn*GV6u;cT{;{c#&!e=%zA!4kI+<0mX;*X)sa%H4;0K#oojdkO}0wg-eQ!Et5< z+EeugDu`~&g(aBvIEXXS5qmD>Qn>3#SjzKML#eb33ZAt?rYz$w=JFk>^UeR2yhb+H>>o~Y@_|#&W%dwq{J7hxww9#xiJDU&DS>Ni6e{;^={D5W~oA>Q< zJOOaQ>w{ITcIF0{SgX@tqE@spCXOI^wz*+^YsK{4vXy)GVm|kFRD{WVD zBlWFj?Q9MM0}jOr>?ajgAh*ol@dA&LLrI*aHvx z-0|Fa?P}aimE0wFH*ro0TZ`wPClTFaTtnP3aI*({>pR(SJv z%)S}Ion6Zwj=hu5O!s!l@O4~`pQbJCF3;CN^0(G1(s;-xJ;xoo3aJ1DsJ*B6V*n*6VbD@)qei5VwLPG~fKPoGCHsRnGy+^97hx#nGNt?mj zd^560!hgsvkg*1VPZ=w2;Y4r#v?DSXav0O9Kx z5g{*kpiI8<8)Ej2wW!rDvJEFwSBc!l)y?pI8UQWwZ`-&Ox7sJqcOck@ZO5Hi;CAb} zy2^Hh#*bj^sTqTHpU;dPNKFD7UfoNkdCG(~MkeXM1M+S_4_;GD?LiDW@d<10rsidI zTA~HZh@B`ho}k@bGY80#owx;kxle8%;L;Mb3$v+h}Jy<96fz)-5?ZG-l<<1`5+lPW2VlD4f8+AYxICC$GIbcf}w--gy$n+eY;6J^= zGyj07eZcV@2W+v1?Zcvp2W0X-u3+BBh^qFMzU)Jkv2@sv1XOcBP6nm)@Acs%>-TfG zYGd~lKY((k|L=OLvNHStd{BPZJ8HmdEMhf>)4wD0D4B8{7c6yt$4U1F2)$F=0rKT{ z97JCKE_n}fCkJ(qXsnXHCy?8B97Kl5B-suj`?NnONyo6nmqXCg`a|%%p$GL&EsCd_ zuDOCG@-R*yOAgB2Jy2leQ5eeN|Lrg|zXvl%*b{#~48J^^)^2bF?K^09w)+F-!a?{wnaPAW)j-lQec}VZEr8yO>T{UYN!Cxr($&%v`f5lhCQhe@^c9XjN;gIw`fm3zm z!@4@NB>VRSp5nwFme7;jm@gl;)wJ(4FzVzdTt50KS$-weTgxI}umWQQ&E%dA#N9c?=ws2z(j-|B3z?g6Z{9?W1{Q-8uGgtOnJ0 zM3(4zEFDqTA3Z?ab4;7T;;d+XIi?{YZ3*x5xDRW4Lf3C;MEp%aLEdvhOV*m7o)G5? zT*)kaQlA>LU4Q}mT|lJwIVt(BqO`qn0ZLhS0q4q*;HYVHxaKz;<<$km(&3Zhd=bOx zlve%1i%2g+FXFL!u*|#2p=K1wp*Gp+5)$KxQ{sDxEAxU=(%}-9=HIM#0oi#8K9~sR zAjx(GB7D3ADm$_he zyOQl^<<9OD4yFLjR8V?ef!{Q-m}JfsEYKEx$*Z5e0(9+`*3NPj$#bCiUd03d;UE{( zTJXpbiFoLY`}LI9y?#blnAIiouX0hOTa571zq`78Eyq^Liw(>AYw!a9YuL>J46QFO zuc7Sv2}JV*+Kue?m1|JN|g#KX?eY*s?T(Fg>j*x}==F z&H;E=^~-g@dlRr!my)*uE(tfVX7ml1q2n3pdmHbEf>PA%0gkX#4o~@f0|-0pjJV$9 zN<8z7G`NYA!O}C*@RmKoQ(XRF=j_d}@BaAMC-j~FndJFOb`bAdxNJCup8R_H{QQSC zNdxmqicCf2%q>8*qtw5NpxAv2Vdi-oy3U)9&{`7$CHgi_^R@I>NY-$eQ>$LTXxdpm z-^K}JsP6F=uRHM8_IH5LTh2=C9d2%VBwEjw?xM0Uau;=DQMCKX{^Yi+EWeBC%ggS& z+|#U$zHr?aBwHT9<6EL#(`x6aWfe37tO~q0b)(Mcs$;W$`~x%e6Z~6Y;bttzVHVjb z%`YY;%7S}bgl8wtxB(UZc@N?(Pn0j(0+A2c)wvqf*bm1DebuoyQ7Yf(3VbY48^C6e zU+=?cf7rwI2>J6qQrD|A7C*cRob&*XNsc{$>w2Bj2S&^0;0~6X*o^u{Gc+-S(N`+9 z&()>21?##Bt%RPyw4TiNF|7;LkPUyLx~O+9oj{%sF=I2`;V;b}LY7YFw4dPBx5ucF zdg-O`M*d?iEYBXon?{|JFAur3IUP&Xv6rwq6CS}qmV($Ul^ALsLc2$5JIuYNRY~^3 zbFuD_QeO;TIVXvK;r1c!A-wwOBm6l17?-Lq{}ygeZE}{Ukb2p9omwp&TRmY< z@%-zUo)6c`PXRDTp28B(!Id0+7MH^_)XX`gz%vfP+xJn=@Su471&y3{UvS8b7x1~6 zXm(F+O2l(yt0foY)(ftLelOGQqR#ut>_yG|Xh!O0c;@QR)AvZwEo8(CZln6h%@-(( ze*uFveR$@k@ZRMq%@BRQbINEx9o(mRtrMS9cAHWgYVHEpI1B!&GhX3H7WWc*_I?ep zdH`CP6q>L37R{Py23o!R<)VCgiP|jhB>*MJ9yxR&7lVM+=j5iqj56p6x5f{Bg$q}t z%~yEV(^QgP;Y`zAO6rB2-(bo1uK^B&(-D?|VE&BZf!1&^;oe+wbyqT^@bQU9@ zpi$7VKJ=;2;Z?3kQm$mK5$|yjsdq(OO>m*%oyrw|MO-q1xZqzLU+Y=G-H8@nk^Oo; zO>}B(1(wFQwO7*CMOQ`Mbw&0$fbYw{xaPZ^gbn6RtdHtFt(DV^Tpg6f0 z9{l8*Wu588jDpkG8=2Vax^1lnY zO>vl~41c*U3k)b)H{=@Q9kYBlzGCr^Vus1e2Pw8>Pz5ZTIEgv!(1@ZEdb4L4j*Hi<>-O>e>HE6w~kwI=`f)*0+!(4_Q zRB3v;lpY^-Qcss(BC{Boq)=wVkDuMLy%;QxGBC5@#*VkOwBOh~Tfk%Hx~-igWhO_- z;AjMxWxpc&Ngh{tP7|5rXhd+#ZS50gQ#_-1!JIQWho1lBgAoUxG}p(u}v zt;h9JD`}9`h*bS$K~|$G&%a}Nksj(PcumGt^0>jy`|j9wPMN^Z{OeAt@)o#&cQaW{QXvTgz3+JXbjGYw;EmJ@0`gX>)ebGh1bqpjlwDI{Bqjc$fR!B#5`v`B`(PD zG~ZxuTblUXXT9S0o^@oWdlLKBo=jZajS%*|r%h5wH}YHS;mLhJ;hy#cYgsws zZur{5Oui?PIk3@%_fn@0yW}84a=>>jX&>Cvb}A%3IpL>+Jz%GcUa-@bd)iJpWnT`% zO?-1AdeG;|)$Uv3q>}yQwguecKRh1tJg4C#k`s)3(ilB88JGGG?DdOz z8UftmLAq6odm0|8!MEvwPM4OU0&*cT2V}!+Cz8ho<}w2Cw<+y&8TAplYjYW4Dn?%9 zGMe!8KefNwO6lnZ82kNCamkQO_~MOidF6&>=jDc@T>VqWx3$D4SV#BZPfGuku-ry} zc72#?RI$eO$_<#-Ry3PEOcf2|TxF{_Tu;x)LmukAH8r<^BgJRD;WMWmYM&`0?egdq z9_m=lDRc4|MU|Tz&SSK|Q9rMb5s0EU(#NR7-#?PGRgFB-+XpUo*~f5IqB~0I2N0gT zDyGB1$u_9N*~5`*XGHT=ZI7d>AdNj_inxIeagLVeM*4m~Iz z_xT!)xc+1D^}&#&Z-7zV9!p#ayWyUtD$W%8ob(;_m67?3Cg$MB`iMNGI6@TM?o!te z3(UiK|KuT>QW!6GgS(Wh`38Ql(GQxrnY=az`ASBtW7hdg7r!Yp`AUm#0EbgSY?O|; z{ToEd9T1zO5<@uPN$PR|@_l~8nR`F6cV>x{xd6<*`HA$6ND&DX*x-p&DPWX0KRx++ z2T2961OKO~Q=;G~fP@qARKIPJBA!Lel*NAA={t0#$zylPw1NPvAJLOuJD4ex1Qr5D z%>B;-7TH(rmN3ZX&<8cs&8M>8H$`F$%peB}8Q%OdJ^6i6=rd1YL{Y(K;u{X`$igsV zE$L9$2uYt6=Lr^_I^hTN!YL6@lLjeWo46Y6S96&$N|G$mxYBS(iV<+u25A z-tbJSw6ru(&sYG8fHRnAL+oci%SUs02byMbA zhp{TB4^2j*V~xZjKXz{I>^BKVqz&O{sI_Y;2tiV{n(OA1CUEBd1b3<#+%V zxcgjg1prT9rO}6$F!aNi$t8@6?Dj%?m8DcS`B(yFOr96E9ielZBJR4#D)2(SluKrW zj9qZ`(1)tMur2m`py6xQdy(us{^DK|EB8w`LgGroiGH%!8<=rvoOs^gC;NAnEEHIkC$41Y~4$ZwN{#}K#poc#Hk1Sy#+C(uE=!VqHBvT* zUPrlA7AbyH(u^PjPqZ;H4%K>-=(7_o-^0Y(OnM7W`qtC_>-bN4NC|N-XL#b){cah! zdE0V8tD-M804J*t6x_d;L!4EX{pE~`IAwk=hj8onGM$bCf)VL`f_0d^oKYuvC8=ND zaLlYV6aO+*^O`2AJZkC1db&W(hu|MzsZ!BsBp*UB-S7&~eb!g0 z)9tQc6g553ZekBW+s}xmVtPn4mwpBPaSS?J9i{Im{Z&!g)_~FG=*fd*c@6l_ir3mhTdJe7x3W=I8q_o*`Q~d`SkoBB zkF4)rGO-r6{^qqL)G}iE^J^Wv#o6hN?WcEYL+0V(2tIdEbVyi~?cvzPH*z){`K;_4 zTM@d$Sp$l`&D5_ngkpq7UTZ{5Z6u3YZ*1%V#XZxvz|#KIBW<(~kA4G}t;ExkX>IBt zfzEnk*C1$k$hta6!z z7cjT7nJ3o+FrmJ2lnFjK#OP|6o&VNpD34fu^CQ5p;}fnsib-^Y(cPT#cXER9N@XbO zl6FCwgzjWPFx~^V+*VPyk2<+-;AiDbgd2JrS5n6r^RXGo;shs5C0(7<09 zL_%d=@2r>PB8_lyYz&ME(0vhREsJc45!Vo9UrX8F(5PzmNh1e0G6H${JG-i}7JuFd z#lZY`w&$i$%J9Z_HtI(=hBw`KX9o%z{`@4F7Y#Q#)z}C&)jv8|7dAHPNRuYOp8)CG z#OTgL{;_ss@i{hy)YHIMQSDR&flYVieCqDgX>pvE_XmuNJQ3YU35XV`)7y zur6w{+y7Xqo6!u#)HBT3PS5Bk4VppW8Q&-8s^&-}#owp;)tBaw^+o}xx%B(wOr$9R z&7tQ?U$N!qhL}SaofuP4jyH$N+sobNMl@sl=NtU4aIyl)J{=t6fBHw?fA1Cb?S~MR8%;A2HbvaFV;V;jezsUqv&NqC6kOyR}gyV`=L2L0@RM zX#=Oc)EeOPH`*O_yNncR11HTaE!r3r&DA ztblfi-PYBJSp)5wb{luK8RS%3)GqbpPFtgeLu>SfwU>suIJ-1#2jQZB8{W?Nra$Mc QCcfv59KVI0GuDp#KN+V}uK)l5 diff --git a/data/resources/StringResources.nl.resources b/data/resources/StringResources.nl.resources index 4f396745ebbdcb54c8b549765cabee4e43563938..f0e775ea4c55a0f79d97acdebd0e7ec9b9656f40 100644 GIT binary patch delta 26802 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 D1<6!o delta 26675 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 bEHN?>k~!7(aK~(fNdNbnyQH)8ha> diff --git a/data/resources/StringResources.pl.resources b/data/resources/StringResources.pl.resources index 0486ae93f4a53fd3b1ad6cdd371071bbbf926365..159c0b85ef26f0d89bad5d9a1a4a878688cd8188 100644 GIT binary patch delta 41572 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 KM&H-8?Ee9{#U-Qw delta 33717 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ීLfZhgKw3fG2 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Ð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 delta 32504 zcmZr(2V7Oh(w|*Dh=_PWL_|bDL`0g1Gy!QMB2p}f*sy?#h}gS8j2b(->e_pZCAJt7 zHTD!^?1|CD3Q0`t-6Y1S-+#}cXx{hoL+;GZ&dyHXJ?HX1x?J=4Pc@6zvRS*PXAr#^ z%V@C+E1>OOM3;{f#SP&!-2mW`iiRjvVMlY)|`n5XIqmhi-cOZ%{Ve~}`r%$dzxLwc$ zfnfrtL@*wQpN9DPBZ$!(S5EvJMz>xNbsEmdE0)uQTu#%hIkCT>)vt*9IB-fW=)~zx zBGI=)iJ&EVACs3so!_4)>JaRgRrQ5A+Hl%%7n{7z=->B=+*(rs^&7?LcymrAO&Rrk zNaPKh?*0LG6GTUn7+GgAs?(iOX%9w^VbhQIFp8-QbF?H1e$7aZV>GlsOx1#s^F5-7 zL{7(@;9RXab&cUP9=tVZGB1+oRyffoBOv4yqR*jiGgg3|-Ge#+#bFoMzk_Ed6MY14 zU-323bl7dx8b+J4Idu%@v}FaOna_xl#t?}CoQ4gBXMc&GJB-dXBwB9I>23hbP=nKQ z&S=6yq90-N&HIRc`-M@aEuyJDk+UOF-G3PURp7{}5A4SV_N_1u=QRH$) zFJ2LSU59AXVWO4~VgHZz5*-MFqzJ>@0wfy`PS!^ltwfmo#)+1G%BZ9ogy~H*3m(t0 z>yeGI`{|6D*JQK-+G;ry(SfMh8_#K*2|Oo&{u4&?5hZygP&K@LI!twJ5u;C$Pny&w zdJh{&D==~L7)JC5cAVq_2@#6@b|4kQNs1w9SO>)VD@M-|t3FU)bJ(@|r=Uli$6&{e zP7zf(O>|{6QYuVz_5o2k9COG}2m_}yAI53vU8LXVNx zFrpjc61E=wE2HhmTJA_P8Mhdng5&+(l+%De;O&QzY|I&TsSj_4ZI5+@v$kR6F^f^* zR-|KJBq0b|fV%PVJfg$HIo$wl8^*|{5SbEYwD9LN7LK?ELVfi4VmcmO$!9{fWArW8{t9c;_JeZo(Iq5_N7w^zv^og@DV77`4lWjcYL4)_~DnWWkrn z^R31a1>7gP{S>~{ozpk(A;}?U1RVq)Z{(L0qQ?l~`~sxh-bk;aC8vcLJcwkpa0~4G z8Ik1ygd#k65$s(B(J&I}bnsxJdv1)XcY%ot8D-pM^uazxtJV?CgyXsgBI#7)bf6~D z-Q&pjc|?0oF`5ehx#bT5H=+C@@%(_F;EgcXWjMg(9q>kYa6IC4Hy96H0_WOD)b(S8 z-Fl+FyHU3hb|;r3DgDbRAsT}1zd*`YsA}P8KLLLRMfpZEBqGqS47P;YcFeLFg?8BHss~bHaw4;piJZIbH8VwBbIZ@OsGqOP@3P10ggF z$dDqUrYN-&u0kvD?4RZ!c_2|7xQ51bEW&C7#%~axJBasBpxbye8l?7u65Zz@W9XH$?NG zxf_V}3nl1&pt+aV(G~y3DEA1Xtkv*?#_+R(Wr%&WOTDe&?Qn|SV~PCG#k&8AYKI^1 zEvWC<_3~y!A42ldqi7tELMIZkpbMPx9x~l+G#LorS$`3|fOCaI$lJpieZCc$5t{oQ z8FAbdn5G}2Gce^abU-JuDfgdX|4Z;<2RH|zsko5IsTv$@^Aw_82q(`;D5ZZBc}zg% z%OvX2162(0&ppw2q@t-rcnz4xs6JBZC^+Fw^HFG_pqe{ipZbXK_t<5B#yQWjFI2l1#)WE z9QhrN_fssV>N8+}l@;~F9zPG^ zKi?vR$9p6GhaHFQOq~A0gci}961F3J1|Ug5`f*4|6XH2}p$Z;LL+p2A)QrQ)P}#y@ z=PhV5{)L%tp%N}cvl)sVR>4ja%uwZAInAttZm2mb>Cf<`spyav5?KsKh@ud!L~hww z@D(FFFze@rY}SU8_ho1S+6a^A*WhT&8*&QlG)3?HO4`5j};czd=Sk@&@fZHZ$oA(l;Ew_z3KO62;{aa)4D=crB`2 z&s;2sO!ll4cJxR1e2L=}1e`k`6%CEUm2a`@CPW(4ceE2C0?EheJ5 z9m^nJXru)rm%S)3$YSkL%h%OJlM&45>v2S1v_p#C4B_{n=v+mpeT7O2AG-Jfa>Yn= zy%2olVnj_}oGXwg{Hha;g-J3XIJ1RQ7u;iXx&*}sYHjv45Kwzx4X2$E2um~*y`CVP zVDH`E!EsKasXT!y_cs{lzjI$v&({upNe?P$%fzxn)I|Y@XUe7tk$P#MX1}`sthT6c86;Wgk*1&-R z$;kN*qYl5o0p~ONeh_LqgzAKyRmbOg(P&INaH@+uaT`2FnZtZ5Ks%by2Otbl4eOyG z{rWSQ{(+|UA_=s?y(AapfRI; zbck^fpb|EAmO!p5e1ieb82)6c7kJ0JdJ)3TB?fOjITpf2g#`vrpm(Ze@6a4)P&LC z>u}EBPz_%b^@jRypcKD>sq$MP)79kE6OD|sK+E`uJC&>hwBMpx?&4IufXL9o9Xq1Gc~ zHd==}AMo4$9O)ZoJUC@q|{k z6Z*CgoE33GYVa*mCrYy)+UYd(0`*ah9v9;v0$*{0jXS{M#vg|Uuz^25$2}1QkAc># ztWlyrLI1cFCcOnsTOt3~hNM@Z?o~^0_J{K%Auflz;6A_~&8RP!z_tr8-tS{1CD?80 zZ1{*Px}PKH>(+p#2)$i*TweT&Gv0clK`^EDF7y-}Avyvki^sJNvg5@o2vINiLJOqq zkKi}Z!Zl0Se>Fla2U<9S1vY$+9gau4bridXTAw3~uA;C+B7IsxKv7E6wl$}g-(wLp z6+e4(N=GCtK@@xfdmmVe>{$i(Iu?vf$PYC*5*eKNOl|Nyh}Jz8K8A30X-xFxEI45S zh#W95zb`}<`w3^p133GYqQ{4DHJd|N z2>fz8l1wL+Pp~)~Z5_(usbqe@H*`D2jmTu*Zx(|oX)^$c?8alLvT0L7pLSp z`283cm5-47KZIbLaqQm6Xm)4#QFCNVTimeJEkHBb4OgVca9+12l8Ly{#*h8`Xeup{ z!5~bNx@aD;fR!7Z6V>eAaMZB4V0aqkn)v!_whD zjc~>LJ1U?Jqsb0L?b1-x9^hgd{#L&LdHFnc7`YO6e%0Y*C`j5i*d-NR5Hu5X64mSt zn#+FZc+WDjMR~4^RDHA=&WgdD!kv)MyD)MNXS8-dRDKe-+t5s-e1zaCj=f9cI z?gBXDQ>gnO;yoCR!L&{2T5NHeMdJ7qwyL2-L^L$W#z|O1U!M<8t_nu~VnJtwQ4pu^ z(H}0n48hMMY+>6DdvLXaEO_n`KG(x^A2=Q&Cl2M??LAz_AxF$Z>lR#!p7SHL`~@}O zwdmV!pvu+3K+S46f+1$l-bN%`L!Z8na5}*c{&&EP(tF+D!yey5*9=YkRz;O))RDG$r~y+9?1;KhjIc!xh{W8ibd-GLk3Ko*T5KocUZ*~z zCy3q20eE}@hbh5N(S0ZedLfnL#B22>y5QZ`Eo(B?LNp8v=1I6l3~DG^2U^r@LwVGP`cf`sQ4cXMFj#}s z6fEYqbQezoZTRpCQsEn9sZGFOECwA#O0c=;ALPuYfupkyZ3{B7YT{5(pjHPK3oN5@ zV10#OaICfoxXPI;gPqw;aVR*DM{~&1L^KGo;xo8t9^6E94sm2>#jubRtv*$yj_O4Wgk??FecPygplO2sc%arg0PjOtj8@L%0V^ z7pKD$w2{EMDO`=tm^o56N3n>Ch~yudiNkFhi%k)Z{A)8&9N*X?8XN0JgXxx;NKR}l z99o;S2bdlwTq0dXYHK&`mA<5cR6Axn>i+z!{td}?w8K4ctaI7eeb`vL~Y)mm&wsK>mtBHBh-r|EOOK~mARx1K& zl1}On?WrxUm^dWb89p&LI*GLu*P`S2W^-MHgcy@{1YzN&7O&L~is}zbjir;oh3W!* z5@XN5*NJTsp~-%_F%6yGG#6(h8;hQ?R@xoV$LsVxW8L{9gZY+Nlcr+VM-9~MfZ3zL zT)BjUcn}+^d1B1ib#faUEvN$e08kr1nL5LxZ6a9L1#z9VLZG5WX`H{96=&kb)kRc7 zW0BO>WSIz=`hs&Vt*n@tbo5bjNdp^qo7WL+zSct>%E!ck0x{H!_RYik#_S!K}>s!zd4dK&1oP7rZfAPAV z6~9Ro8llABs*&>0r@CM#=0_FZ3jRP1=d#6`eBL+sVq7Ue6&8Pd5VYj51$RO?~Gds>T>u|YzC**)y|aBE#)1)k_($>&=O zzdU`^6bo<2Mj(#D#zxXIYh6G^H>syB|J+)aL4ntMn)unu(d#|UtvX=ZaOBY}{Cm$@ zr1t8^O*R$Fvfg%DV;fX#QPd+|^zZG=Lu|@Kbe5}ja5L6Lr1VM@ewp^Hr)b_YQ7pn! z<*_#9f?B0fM_nq#ex6O4AZB7!9~-L}-3~)BFoITMMxQLc-A3#h9wgr2A#`SKQQ9|I zWcRh>Lu%{tl=QO~r~BIQVl|S*Kd-ItQekC36aTjy^xzJ*74+Tu+wdl~*j11y>1QVz zW|@g2{Y@-GobNx7&#=|yQ3D@jS@9Bs?p%qbh|IRPNP7c?0cu-^$U`18rCvQ8F-v zbrQ`7rSmCu^RVA@NRBPPP*>lI0$1eN@xSZpetI{@iF?Z&Z6*$kw&kJ`bky23f_%UI=GXiP2|9_KL$ zV(C~r)?6fy?aSKZ-vrTnoVlnv&ZOnyXrHaiTrj}~SZ6-Fu_zkXlYOjDYdYSJ?`tfg z#&_kX8|#ZJvYF$ps*Rwlm}+dUV1k2oACR&6f(eeCyDKl1OO7!sS^R>T)oO!~ACCPG zr+V(HG9R7fBr+#@@Hlr-G^eiEG0|UqFwsi;6@wY&gQ9ezt;U)tzGdVha*~Bs512q5 zGh~vz<`2kUhc->JWl`ebq%f@maIwI-iNTX?YQNjQWxO@!tc|bWwSBU^_5+|`(Wk&o zJe+LHOPfHnCc>-0kKb=1dKI+OygXDvQ{(3f9JCgI5)~vb)IjVvEwo`FVoo8dS)l_< z#HSRNE3Ox2YZE}2B-T!k6jzJP&7+X7b7_Nz&iqJ`AK&F6R!xslVy4G5cyO3Xm>!8r;{9-W+mL-cV?PcHMOHKpK2xDvzSS9 zYWg;T`BZ1k2blbdDHEo;veuZAk0e=ZT8=guqXWxEJ+wK1&{Ry16~5E$v=x9l0!pZ^ z^r~8tPsHP*STS?Dg}6K2hF@qZ-c0YOJt&(LDTd6jvWiAM7>WN>d}*HIMq!LX3)>mC znvEx}d-S!2%&^m(02#Y&Fw;^~?Xj=eH7iZ{&UDqnF=lMD!AvLd=}eQB0?c@QuEI2# z<)~!>V@Td$rj1xO%Z}w>{#b1$@CiC)-fRmd#Y*hv;A}^23-D@n4`DXPhkxn`GdB@E z=eY74p0H0>?LNj0i?g{7nq4#HAFS9(6u+)2xJm;y($<-FLLEA zyu|rmT=k{DTI8dJ;+AB%hyv}F#SWswVn?kLFgaxyAKuqXn06_#oTQZ{L-#LjMUb@8 z27{`v*d@~~eMlup)gh1c5<^$NLu;dpIk}uxOkQHar$U~M?@*bEpO?7u+5fYWnMhpf zs0qyOkChSunb%RLqPN|0BSs6$R8S$JnP{{ufbT8e_*?i*%lx#9n4)a&v|xpUsI%OG zKlKvLmv`bg3q;*@S+K%YoLFwlstdp6VZvdBz1F~6ZMBSk=n7Bn=dCNacy*}wbA>aH z_ZEG=a}fq;RVNPJwz`}suYKJxUHK5a4-+1&bl{`BbqyGxl|}ghW7@mu^7DoSdZ%Ka zAiCoT-ACR~@(BK!x9&m3tD{BRHMZKZcNXzoYc7tgvEgSFZFk|j)}EJC$Sjwy=2jwL zy$yd-A-Il{e%qOO^>VS9h+H>|*Y>H{o6`nMeOB{#Q9IV#XsvzJd8B-cP8)2sBw!LN zbOuDm+lV6@Y+07@`!Gycf9S;W@hOAP^+9An`}US2Dvnwke8l+=`)HqIZn|i`14oA~ zju!FIuR45xjZ2D+!?aTv%qbrfT|aW**VRBL@y$n0+QWASLpC{RHGP#a%Xo=Rn`|@} zU~(%kg`2HJgUwbv&=-Cmq!tu~o9(qY5S5GI#=H3HA$4T09SA%`+7@Tt%NO?OE`HeJ z$S13hW3FO6AZBm3(;76#4IA9QrOxZ0?f$$;bF3buga7U@7qfOa zFkex;vxne2U3o@xU4jWaZE@Z%-Z`0XZ;ova)_wt-EjpXb&jQ8WU6GoNKVG$|z%2hH zR0{#7lBUh>NZ!d`Se*+NYRdE7o@}Ua{&cst6l7~ECeHiRB>l{}ndr91S=)x8O%+48 z_eAjT{dHk8Ka1r5_zUM!gPG}bKV~kXKF{E8E#Uh>;v6nYuJ82_RrlI)?-t0?6)0)j znK|%akZml-`LhUNy)O^P;=+9s`K%V=^}a0a>lP}Bu>Bpy{{1%m=N973{+`-nAp45* z`#YP4B7^1PZbY50Mi39srCPDyN!2$@#ww-cui`0+6T$QlNi zc+f&y8BlJJ;)5yLCO|Xw9Ty*T7NLg%`H28nAV?^%_@Mb)S2DN3_JPZSBY_Gp!VWw0 z#}$}8hdr3P7pqxa@37?ZK+o+<-jFJ?d831nFaKfc`TES5J!&*Z7Qf&>2muX4-m(`4CLEdiig*N zg#wj)d0)A6IGs|2LP0Ez2jaO%#T?(`R$|`Q4qAO+_m*J;Me?^6qR}_8JTMSNNO21k zm%ee*x`7A{I~e*N@6Y?1d2QUvLPtYS$FYXOkR$Q*^5V~oy2cv9C0(n&Q8UFhn*cH9-Vb$eMQZ4OZmKD5w*@$_??Ru zmgn91o?rw(2a$5tRxCR2%t}DrPt^O~mAi!KZd-UEP;B|$f=7nvYV$bjUmGN(m4LH`ZYj2y=0?(fpHZQy~UuPy!h7; z68brE)=st^%p4c|Y|C#OLQcMH5+i^1;eUtdyU)KGCOU6-6i$~-%uV=Sp3Y-K4Xd8D z6N778csB|g3y#y5xR%EH2Bw781B zX2TDKmaitioXi}>wQDB+jheMg`x&fqE12K9Zlk>fW+9k&7a2D~IdAn2$EPshbQTd8%z1FwJ2NwWchaK6)GkW@ z$Pkx)x8Z$JfiHE?g^T~gQF{-A!}Y;0|FCCEb=IwJ`DojKR}s-(r#x}XlYd*u`N(Y> z(fPI`|23@4O})gC+hM$3c!fHS+%^-bciglt;d&!=Cq;aB$A%9IM{y4lJ0H4=;=AU& zC>(jTtES#xHM%9A`$^_)aIKR?Yr}>0y-9peICkSAfERD>S@KimV21WHCK*kj&wYP! z{k|W65Dw=bAjUkfXXv}|eyXRiemIfG;!uEAZRf*umJRekG3=2&FO1Op{+$ow#FIx3 zd@7#3px;v9sK<8vWcidh@$9h;zflPeePY8Gwbs|U^TeL-$4B(FYTn?d7W|vmWlP10 z>rZX8)2&t0Y5mw)$j0gEj?ZW8WgP67&DI;|nUO7QAraYb!x9OF|rH-d+&aIcOJR-{2 zeer8c(e_^l-Z@HIo8w%*;@>cBASnCmlyzQtX;T5g2ADVbm6^5_P?&V6%q*J&> zmduK~MOR1&oSj)91yIa8I0v2{E!WzqcI&kzXe{f-p`9=;z{a4#P*=C3!MCrHLS{1N zsZ9l_3}%2eeaN_F*bKBXyn)8+8_Yu63EapETwUYdNSR|0u9MZHhW#K&(FvTZFkFfN z%+$eARhS3A87)^=VQu(xLqwThl{rY?s?5a9Wn@*B&YQ=`)^HLvU@!5?fxVUy18vH+ z)mW_dK0fwWALHa4jX7y^0B0NUpBi)4HUiGkVVo4J$}BVH%)gC+-b3UOGv>s9kI@w) zBh9gD(`wAb@5jhD7FbTlykCvk^Ma07rY-4P!R!wFhU)O*Db1j%9 zYbN{DV4dYd3ueW_^v|{4eGb}DA^WmH>Q{zzvSjAkv^MYx#XU|Av&4PCiZ6m~5kP7V1y!aLbynyVyud{11s-Kc3lW-M~vZUIj0c z{IwReo)f3GP|nXm8v(jdMOQlo8&Z$i2caV#NXyG*kzbjZqxK;{6-{0`D7~$*lfC-F zz4@^?WyoRt1Rmr)_myX@nTO1=f!Dmiq$FJiG*ERo!a%IgHwdzAv9JEXW$S|IlYsMNljM9`HeB0^Aw3%!AT>0U)hVSV!%F*WXcpX^h3?`|x|JGty0BU-tOy(H>#e8@t#7O(G0Eq35iMum#(Zv%{b%DJjkPnPxJ(=jxM_aC zsX#BoIo4ygELk?M$I`X!?+$&3A%3i#N?cv|PwhmnmvB}GM0}nDbZ<(;C7N8_kcG-G z9hf6)DoY$#M=cKMC9vnVVc(pM|n6@_c<(sEx+hSYrytBG^cRqfd=(>1I^_d7r5Mz4vNot7v`hi z3Top4M;P!dSJ-S8;CKT*;|jN3P)T3E5e)L9&MZc|34FFe_faDj%pY}-rHxn@%_>Rd zFrEK7TW*0;RCx>QAq(9gV{_@(i22JKF0kbrHyqwVq(x(vsKsGwoV04pLTei5L-pu- z0QHgU8pB$nWNBm8nQu;##qKOzj&#S-`K}Ih<c!JW7Vrgr#4Dn>m`Hp0ntA2l;ELVH7R{TV=yz0q9 z_znGcBN^I^+3|<^U?VxI8DjB8vYgk9)nl66+>H6yTc-REe|5iUCm%LLYH^YdUd+d_ zF^KHm6+$`wNF>T;vcDGy{p36^C?`-J^MY0)U4OLuQT-DOvAK>g%QZ|0%pftRg3 z=M5!~mZ!X#E1M`Edb2o-Ss2J}3*!%xMFW_N%=BTA7C!>%Q;D=uHA}r@;GYU7tiU%~ z?27;o0xm$N2Eb~$z6kJ6GR2pT)dm5bR)O|I;2PH->P4P>T7XeMHR`8*gO5q-qraTz zhk*G3@OTBMEN;#``R!E6f>gb_ihk@Tx-rEP{{kBvTKAs5l6IRoGHxzn09RdKUNxP!^$mhxIbwT5nG%_VQb2*(ZWETpY;k7Pn#v{7Gk-GNgPj zMXlh5HD#?Zv_217F=s4^&potGU6gC+lCKLxsTm76&VXNqA%!jkoTv=oC{KkWbKg0K zFipWH{&5$jvW5nFQ8>KsIB3HvXq|aU7p1C(vM>UAX&nLc-Rh!5Ea1<&$W&j$j8%={ z7Oj~(ua+iv?qH6KBay&Ywq|jfLmJ+|l)Iu(aoi(WFp^&HNc4vtfKD{f_EE4=zcjhF zZ`r(@C>G6gu%#eYUuX0%3Oj#KmPV8j^o@ptE(eEPgTs|*=EHZV>CUK6NQ{9f#|=?r zaSY4lm(rwPFQv&C7A?D@VDKktvM82K<5peY8p&>h5&y3G9t_$$ZP4;3bydND9PTAs zw}tj@$3c(%@DDHSDx`B=J)%!Jx2(Q96!<$B!#IrI(|9AB}ZxndTlS#+yF zUQA**aRM$=TbE?0EgEnyW74O|%wOvSxJ-?8Q{em~0V6voOXa2@LT7Z7#VI&YEbFGM z4LhZ>jC6ZLso4aXPEh$4O)JZnz3h@S20ui#bE0lLFLwW!C0SL>;bQY=|!0ahj89*xxp8KgMG3v#Orx@$T25{FNYUiQGtoj*fXLfG!p)VfYgL(1au~aYYy>?IR@9!Rl zLBP0-=6(-2@NzX)w`awom1FMGsTVV$i}LNo-qXT+;^JBs6|)x7IUB(^v?qF+eZ8UT z*1geyr1X@JBsTrdn2(l&Ssj&@Vx?auvQBAF<(?C?hro}n#LGpQu#QI`P+0b=P=+pw zqny(RmiPD{bk)8%3kKqK^|$#<=nKun$TfZ0RNk>yS>TjyID+r%r5tK5Kh;Z_U?y+e zTbVpwj_r>(Ic&1fY9+|1EcOx0m%ja32RSzjbtxqq$>Q_g^2Ynd_5$TE**HWT>y2m4 z75ea#>joewAM{oVZ!7Bz#A$%bl!5F+Ei<#sQDSApAh6n!Y0v<$kp~CCwGMz{yrB%A z9K`U=%y$L1lG}2S;{M89yaOWC8O+Awj6QcTTdDc=!S_!MA%OOmi*i|-HVDXGik-i_ zHv}698v+X-=%Wf-mbRpys$J!SZu~{R3d=jl%sC+MlZUmO`WxodF+1Fmfgk3fMvUn% zQ&vERO7y&;ERi3oM7zox`Do-u<)d4vo>f7uqf=NN={JmRh0oxZlp}_t0()f1d4mm> zI+2&GIReQdI?G7&@K#+eS6MIu3AtUCO3}IiI<=>a8VUbT{~u~d;VG|-L~`yU@#lp; z6%w3De$eI6+94vy`Ck>D;v($0qJ=Dtk zlW~081lqmt()Q;E2Pokd%8)5Yh_&8F;kyR1oo|y(1%t!y8vz|_ah-n!4AAY;0gI~5hH=XU%#(Znfp57a zb`vIV%z##x4OEGs%&j`iMC#l)P(B`s9iN>IKPoq=g{(0P)L#x%+StgyM|-Z^L(zz{ zlgwo5Y{d5yU?&*Z46ZK5%Cfoc#tFRPAU%rp2>N#pHrsL#{AxXwB zLZ1`@^kieMj`ru<1{-1Fx0sFR*9I&19WUJ_a`6Mjbpq}w%;YHv$^O*`S8=mknR=j{ zhwk21OQAfw|3QBOwC0qH2UKtEqvJB1vVG;Q<&YGo|EluuWe_(gSM7SdT(BJe5T-^~ zLLtd3*k&!UlEIyo2yfk@c`KP0&X*4*E{1?j;rnuR+dwDwa^@WS?J$NPNQ; z-nNd7 z{X;lOe4fgCfztFLbO9Syl@mAOl$s2(VqSY=&c<&#Q0+SJ`k2PPdyjqsO_HXOwk#h>i~C&-2Q9 z>#azx>$c$beeBS(4rMFL;d6%SNpSIYv`S%H(H&ggin6d8B-jnGVKVz;%-J_o*GdIK zdTs;Rg`s*p1DnJfKCe%FK z-r35{yAe1!!{A@pl?d7MQwUo$%%~6g^jUl0$n%FO57@~!4O0OgDD{!>&p=ycxZye# z7kL|sL@7^2Fq>xSr~skyj=Zd*uh^gf9^Lz$se!i5@gN& zSO>@I18lwa(TMW&UCt+$KN?|dvUUVGKgA4=@}`cavil)6kPjJY925X_lr0WJi?c?m ztBUq~tNy!%bUFe%aQ7OB1Ur_Rdy=3m)DPCcSnxk zpL$1e)8dPfva23_B<(1!rrOJ*qb!nlA0-b5pdH76D@@0Zv21NT=sT-3dl@IZ2<)LP z08+p9F_4SDM%*^|5*cs9DCG-_`LM%S1tqsGx_K^QuxZR5mGfrtJu>;Qw%GI+-1Z!%z@RFM~}hScBsu>pUNDctDHvA?x}M7=bCeUlMZ-Q0 zbKcT*`KW{bb`9V7--&BZp!{|{0o#5y+DIT}>cdln6EM$rqvbCr7~aSQ+lg}5J{01n z^K9h@-{Hc?Zj9=KUB1Az&71GgC`ABHk=8#UmlU5y7W(2OLSo<;S#*`vtH8J+6_lK0 z9r=kd(o``p^b{^$f5iNbZ_O_`g{){fR+*@rshbQrji_imwt{J#76l4VgTna?0xDkJ zeoq84vI6O;%>*23z*%Qd@V)^YR{=McC(f`M+P^?17|4fbAW)rgge!J^ZNRp&<5_IT zYn;q~h^G`o&%r&nodvG|kfEgfq;B{X()Ju~Efaz4Re=oF2EGG3%O{}JW|c3X&oo(& zcgkC$tnK!JW2aq{^5B2>BI$I;M@Sn5GYS@BtI$+AG*GNQ1QkP(&IOPNldZm^bk))$}VxkF#!~ zJo-Dxcb4J~X7j`{`zg(_Uy!GE>kNkdf_!mmqRjh+jnYbi8ZCiJl7YX%=mC=|g!Qsg zFC=8)zw!8){MLZ{`&U$pX_J%=F*RBi-b9_5H_4DS|0Z(Er@uj*rEg;z-2`UqBqJzc zB_ETz5E_7IAX#{1Jd(bcB-t&)&_43TO=iiDS7Ji73s@~htrj5HLy`RIB(>FKepmnP zEnEM=T(xH)3ReE?F6Z4suB<-Ua8v-cGU66u{_rh4{<4v4Z^Bi|vF_-*$`PSj&g8Oq z)_M3zze{-1JfniZR$jafJ1RcfH}8<@Bc9stK017E3Opaz@x7R=Z0DkgCfePzM{99e_EbTU?=S!Ez=yTj2p*?(EpaQPx;zxKuy7UpM zf2~5@6gtAhaZ{I;C z@jFGb)<3MB#@jLE13d%UG7_h%Q`Wk^ggt;`^b-9BNu%=MIL&M$G}(g-_5J3?=|Cl!P55) zOM^A0yBqRb!B$@x z%*X3q%l@A+<7*j%Y5n`siSwa+$NO>~=k1Z<=W-q^8&=`wn)g)YAz&XVbE|M0+#nZJ z;XSlyprIblL*=Q_+(PSG0oRDZgG}}MLLT)~v=MT$hSyT|R^>KYE~pT3Y8H^TvVq23 z`NF9(O5+9EFBr@=2H$AhOKUoZ3U&v;R4WCsGPL4ty(C#;#s_MB zFk^u%GUo&2r`5n=3gE>Gmi+28IoX`A(4GO6WGvFHI=5Act2)o-5z`ILO|;;S($|7p zu@o6$!SS{E>ADjsiGQ`=Hau&(Qc-wq^?lqi6;3l8R0dbkAK#2C0@%Y?1Yf{&)#d<> zHsG+1+?=nUE?Zmj_Ixv#)x?fYSaNrMV7h#4$=hicD|pFqHSxDC?&w7QH2OgISI%8! zJuB{{xd7g-HrGhvFJ#WvyaDTe;3{ou@n9_1^VD+9#m!Gp0{6LFVIS(?2m``i~flGX@`fG1}bUc>8f6ox+H&K4YYI<%nuWe!!@{KVwubuM2&a z%AIw%o!nuMe@g0dM^;6?s>_o!i&@Gt$nQRKvORa;uCtT{>nK7WB--otTs_-sUXQ0} z13(%pOC7P%RrL^6697k6z)qHxe;s8vm^koG+A&acG$^*$=bjQ@3^Hjy0hw8W3|2|X zr2PV9?z>1cIiWtjzW5hL@+(HtwHmWkOzBd9XR!3C$t^W!AS)MgmKz+o1DdVFjywf7 zqoxKtmnY7~YZ|w@V=Z2W!GDl?#odaOJP}C4aK|sbE$O8>w5_CVfot4#{;dUdXvor6g zeE8ywSGnF;!XqW zZN{UuOMoM!i#LzpZu8ZeE#)IGxJQ~7a%s?fy~1EnZbbv8bp?!@4{sj5*cPRE!Fy|CvCIuW9;+=CN~5|ME1UB$eoe^2=6tYrWue-Uj(_EcT<7G^ z-MGUdwF_T4!k>F#^)>!bS>YmC;?G-YpDj}Fdi4oJCL7uU+KX<1di>2ISro$SDU2W9 zZ(Gv>QisSJEsy|4NxuM0U$|K22k|07zestDhf!vw3kwdY9K`}?*m)15e8SEAoLp(Wq1$|)uw@@Y~fWwC_@6UzG+waa}c~`C17{O z!cLk6BV0cQ9BII#0n4ahNPo0^lAQ$7N&6nKzI8kKND&MI@HYeODbI(hLKq5@L@bf`bIo|q zEsWb&i_t55dwDvP$7@|diPuUoNhY>JjAzQ8t#~ZYTOtd~C&;|_@&9V^-V%8Z7a?j^uC=FcN7v zDpKEYc)&w_m6muVUA-Ns4hO@D$I7TN7;`PZG?ol%a`W=q6rh4~&@_aNRHFue^OEVc71FKHc z=QWe#V!&iU*~pGqjI3EEYqf(YnQh=&z}U(j_($6h-hFl66-amf<$q{Bv>PDv*U2nZ zb~RqD{$rUmwc#!JgR({Q+hEZ@^+m%`L=Ls#q1?3G@R5RcNO)hwq4~03t^{eS0K5hn z2M22+=g09LII}#6<4Jh75Z;z&Xz9z9C8FB$H2I`01kDDVsl&B=@N&2Mt3|mq>c2?! z4S_-+gB7K_oYM|FpQ|s}Nn2M=tm8wq9hG#x2{<$Tp~Uc%`0TI!gRy9X2Vmrt1ca2u z3O!XT#y=#$XWZqJ1djI}rFVOtpsmDcqHNwCXAu1;RhY=lv@Jjm{0~yrON3MH#Ryur zx5P=O!m zpw3e@Uh-iQL^z^Pc?W65udI}KX|%5FnG7fQNk*di6J!DMXbLt9q%-a=CMRQ8wyTsf zb@bw7gxsrSC?X6hBA8dK zlJin|3$|U&u$R44vE0K{?#w@5C9OO14*Z){GP5IZ%`dEyYdi9`{O&4w2YBrfmh33+ zcSM%R?1a+x=PFs;3B8N!YK3RL5ntyzBO7>hM(fahwcL@bj!5a;LZLlnjWpE#VG{pu z7oGY1|BTwmWnCakau<-SRwMxm;mr50mVP7N;$kBoc7bbrjTJk;wIYy?HOv24!AlIH zfvXT_M;iC!=4<5ZUfjhH5E$EvKS$JRjoi_hw~)QNLgTm-?#ko%sx`7;n6a$0eA5-` z-m#{Fsb@MOe*YT0+*2;tjCAhB&sWZ|kigi<2kDsj2orI9P}0=v#yzzcfI}-_+X|`c ztgTSuzuiFm)lOWfx~!F{eIYe4?!4XFx0Y;^fhD`Gtq{{f0%KRPsiLxpPTjd9Vzpc~ z3$aL)mmly}wo#b%hWqJ&-=?_CS08=UVC8g9q_C z>kRQ`^x*Ee(cjqvWjSM=YGU;L*6fK)p9{Eb3BazhxG$8l3CJ=z_Vk1{53e(<1Hipv z4|jBAxct5s+?!-lZ*+9{?8y)Tz0kGfDbzr1()u#Rg-ZOzetex~y{wh_e`Q?@P?g6O zhNC|LN(ov9pTR3yH53Ie#u#c9ZPNN^gfOOcj6p#jB3`&$L_ri^NeQSRQ91bH4PM~B zc-|n@nwiwrn#S~zXr^hklhoMMSZv~STI0}fckc@`6U4G>X?j`drStXH2C(woir8H7mO1{FvbfG7mwqg+rXo1nShKh_>f z;*jEXg8-LGO=M#(l;SWT4Vi8h9Ehu?Ci2o;3Pz@5+eYa~vBw!`t(IzbnTw0-Dg!Mf zlUbPk1T_v|bb<>=KsJAA|5!eq2gTbAFc7nujd`?^{%jU5=dO|u(SDwXRmfe@*&MFQ zM{G{Y$8d=wjo656&j)KSbcj$qTa-@ZR3j#(CyXF@RgkQuKX!;HE?ZnEMWx;Aa9O|P zRctZE79c6W0fqufq{E#e9Jo06tN^)DXQ#`BTw|*?L4i_yzeEX6O>aafk-9=jv~~wb z<7i|s-!);nde|xCpGix*JS>GV>fkW*c8qk52&!vLSbM(G<;&qWXhtA^s_No~tr)et z{yb{wV#jvOZ-46IxNM9dqKKk{|Bj~CuJd~l_Iq&#oGYgY<}}H|)x}uGVZ(O3w#Xt9 z%CtSOB*5YPs0adI#EW}mL-DfCsb#tJ)l|(=eau(fh-mt zF7d&Ha^+5>s_**H{Z7!`@}&bNRQ5%IRvsyJS2q;H*Pz^D@V(5+HAhg8Ujjbol|Twf zR-RtwgNeeCy_ZVhvZYqJd>5kv^-TV-1YTcj6?`Spkd>G1qHOxq%5R@>*N)pwWAUYo z(J#~{7U@zTvLjKzlS`59PeTcoPp(G8S(en7Qb3USYHcn`vB&X^(wUTC8{JPJ&ZWGx z8}da1I)8jFv>RJLr%*jwRL9{n8y6e~U&F5>#4g^0u+hi=DnST$BXo4p#;JSg8TzXY zvXA9=_F(n?sZEJTQYDvRT{(tzW$=L@JL9~xtG$bR;rO9;k&`zaz~X7R3>n7+z*!zR zoOAag$BDP|tva7-dIoq9n2Y=bdY|;pB%u{xLiFiK8WY_;(49F zNullmMQ=E~gANrts^Y#k6V$;DC3GnbxtMHmD7*4tI77^+-3}jVfBhO#f_ELtekGy6 z@DE;xTYlhh8Ac5M9GamA-inhcpxaYNuZ4AcC}&3DGs^D*#v$i&=ytJ-uJH}%HliH2 z^8GU*aIntJ|>q#^jo?W^ODL?4og4O%}Fg#hQxePP9gXTTV1||`@$}kV{$l+ zHWrIE7P>C*Yws2Vi^VnK#d4GC0tobiAm&@@t;Mh0HDWlrLO5u*(2MM2BF9yLkL%sS za;EXo!g+~y$ z-ji*ApZ?dw^PACi@^Nep1=Us|w;tciv5g89!AaF{+LKjy5izBg6Hg!w2S(2!)d-$5 z*ieIY01ydUOt0AeE~vpsCBbktG#>BUQtVOK&eC3`A9NSNz(nD_$;wexBU!6KBzU=( zYs_vY!rlaPsiL<$%>e2w(NPNPfuuaZLC8$f4Wa>R!eSxT!KR_H|r>!miH;+KutZRc!5a1b`p{_@G?ds zJ^2*)FXj2CXgyMz`Ny%9yX}ma#ZN=Q4^gPKq4`~0bBea|zSEdOZC-c;F!lHGxHEX& zc>#DC_;I%UEby26gcCeR@As*w4di(K-dT+4W}gW97}HrOX1GrUK3Uvx7B=?ZJ{2M) z=Jr{rH=tjIHh~FN-@F$3MfQ6u;&_mFD=fCL3;klbpdMma&W?I4T7KNGMEYJmjBR=Y z++%&e@b>%l&|V(y)uWxDXaYO$H-NXwe$_dES=yVR)N@TE77h~{QP|!uoZ?kF-!G@@ z+9oLdswlY8FSP{3Dq1)oryD#c_`FK84~S0U=?ebB%TXG}yiK zDgfi~!^(X;|7X|-u6apfMem9Tb1 ziUgk4js@XLHnw9yxEUlabFrCWRuzC<`5WNzyyzU3V8`E5)-N%4&tZH`Kx@sQ%~DLd zOA_cWkJ0LQrx~)+@li7(_WVIl&LgV?b)e4`KqmOKv#JAI=RbW6Spg(v4JwJsy1(gw z&+O!z9h9zBfZA>KooG`0`m<}~n*eh|C+v4%&}GrU97`XH&@O|@HCRbCy9@hVe|W5_ zsS8!V8dRZqngzg!iwgkQx9CD95ybu$yeXS<-ZKzcw%a0?Hsuz)by&do6Fo-n_py42 z_lw|AE8bdJhB(zqxM*)ktb5a}h$o4AXsmV}Ft+Tiq?h^N-vDAq-U@dy+AzY;03&+@ zJWk{(;$BDjMIq3Tr63boiuN^N3{k+(*bzp8e<9X<65eO0nE{c26E`wG!1@kfu!B!M ze{QE)VNb3uG8JtrG8E}DicI+DjB?P`fWVMBSvlLbn=<)7161I=?WFjkfWTx^{yPoM T$hl+U{r#VJrpz1j!IJ+2&<6eC diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Configuration/AssemblyInfo.cs b/src/AddIns/Misc/ResourceToolkit/Project/Configuration/AssemblyInfo.cs new file mode 100644 index 0000000000..c88b5563e3 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Configuration/AssemblyInfo.cs @@ -0,0 +1,33 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Resources; +using System.Security.Permissions; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("Hornung.ResourceToolkit")] +[assembly: AssemblyDescription("Assists in working with resources")] +#if DEBUG +[assembly: AssemblyConfiguration("Debug")] +#else +[assembly: AssemblyConfiguration("Release")] +#endif +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution=true)] +[assembly: FileIOPermission(SecurityAction.RequestMinimum, AllLocalFiles=FileIOPermissionAccess.AllAccess)] +[assembly: UIPermission(SecurityAction.RequestMinimum, Clipboard=UIPermissionClipboard.OwnClipboard, Window=UIPermissionWindow.AllWindows)] diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin b/src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin new file mode 100644 index 0000000000..a2863466fa --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Hornung.ResourceToolkit.addin @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj b/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj new file mode 100644 index 0000000000..2c2c0740ba --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/ResourceToolkit.csproj @@ -0,0 +1,132 @@ + + + Library + Hornung.ResourceToolkit + Hornung.ResourceToolkit + Debug + AnyCPU + {461606BD-E824-4D0A-8CBA-01810B1F5E02} + ..\..\..\..\..\AddIns\AddIns\Misc\ResourceToolkit\ + False + False + False + Auto + 4194304 + AnyCPU + 4096 + 4 + false + + + obj\ + obj\Debug\ + False + DEBUG;TRACE + true + Full + True + + + obj\ + obj\Release\ + True + TRACE + False + None + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Configuration\GlobalAssemblyInfo.cs + + + + + {924EE450-603D-49C1-A8E5-4AFAA31CE6F3} + ICSharpCode.SharpDevelop.Dom + False + + + {2748AD25-9C63-4E12-877B-4DCE96FBED54} + ICSharpCode.SharpDevelop + False + + + {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} + ICSharpCode.Core + False + + + Always + + + + + + + + + + + + + + {2D18BE89-D210-49EB-A9DD-2246FBB3DF6D} + ICSharpCode.TextEditor + False + + + {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} + NRefactory + False + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Resources/EditStringResourceDialog.xfrm b/src/AddIns/Misc/ResourceToolkit/Project/Resources/EditStringResourceDialog.xfrm new file mode 100644 index 0000000000..7af0720b43 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Resources/EditStringResourceDialog.xfrm @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs new file mode 100644 index 0000000000..713f933375 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/AbstractNRefactoryResourceCodeCompletionBinding.cs @@ -0,0 +1,59 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.NRefactory.PrettyPrinter; +using ICSharpCode.TextEditor.Gui.CompletionWindow; + +using Hornung.ResourceToolkit.Resolver; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + ///

+ /// Provides a base class for code completion for inserting resource keys using NRefactory. + /// + public abstract class AbstractNRefactoryResourceCodeCompletionBinding : DefaultCodeCompletionBinding + { + + public override bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch) + { + + if (this.CompletionPossible(editor, ch)) { + + ResourceResolveResult result = ResourceResolverService.Resolve(editor); + if (result != null) { + if (result.ResourceFileContent != null) { + editor.ShowCompletionWindow(new ResourceCodeCompletionDataProvider(result.ResourceFileContent, this.OutputVisitor, result.CallingClass != null ? result.CallingClass.Name+"." : null), ch); + return true; + } + } + + } + + return false; + } + + // ******************************************************************************************************************************** + + /// + /// Determines if the specified character should trigger resource resolve attempt and possibly code completion at the current position. + /// + protected abstract bool CompletionPossible(SharpDevelopTextAreaControl editor, char ch); + + /// + /// Gets an NRefactory output visitor used to generate the inserted code. + /// + protected abstract IOutputAstVisitor OutputVisitor { + get; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/CSharpResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/CSharpResourceCodeCompletionBinding.cs new file mode 100644 index 0000000000..0f9b6f3f47 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/CSharpResourceCodeCompletionBinding.cs @@ -0,0 +1,40 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.NRefactory.PrettyPrinter; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Provides code completion for inserting resource keys in C#. + /// + public class CSharpResourceCodeCompletionBinding : AbstractNRefactoryResourceCodeCompletionBinding + { + + /// + /// Determines if the specified character should trigger resource resolve attempt and possibly code completion at the current position. + /// + protected override bool CompletionPossible(SharpDevelopTextAreaControl editor, char ch) + { + return ch == '(' || ch == '['; + } + + /// + /// Gets a CSharpOutputVisitor used to generate the inserted code. + /// + protected override IOutputAstVisitor OutputVisitor { + get { + return new CSharpOutputVisitor(); + } + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs new file mode 100644 index 0000000000..3af384223a --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ICSharpCodeCoreResourceCodeCompletionBinding.cs @@ -0,0 +1,69 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.TextEditor.Gui.CompletionWindow; + +using Hornung.ResourceToolkit.Resolver; +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Provides code completion for inserting resource keys + /// for ICSharpCode.Core resources references ("${res:...}"). + /// + public class ICSharpCodeCoreResourceCodeCompletionBinding : DefaultCodeCompletionBinding + { + + public override bool HandleKeyPress(SharpDevelopTextAreaControl editor, char ch) + { + + if (ch == ':') { + + if (editor.ActiveTextAreaControl.Caret.Offset >= 5 && editor.Document.GetText(editor.ActiveTextAreaControl.Caret.Offset-5, 5) == "${res") { + + IResourceFileContent content = null; + string localFile = ICSharpCodeCoreResourceResolver.GetICSharpCodeCoreLocalResourceFileName(editor.FileName); + if (localFile != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: Found local ICSharpCode.Core resource file: "+localFile); + #endif + content = ResourceFileContentRegistry.GetResourceFileContent(localFile); + } + + IResourceFileContent hostContent; + string hostFile = ICSharpCodeCoreResourceResolver.GetICSharpCodeCoreHostResourceFileName(editor.FileName); + if (hostFile != null && (hostContent = ResourceFileContentRegistry.GetResourceFileContent(hostFile)) != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: Found host ICSharpCode.Core resource file: "+hostFile); + #endif + if (content != null) { + content = new MergedResourceFileContent(content, new IResourceFileContent[] { hostContent }); + } else { + content = hostContent; + } + } + + if (content != null) { + editor.ShowCompletionWindow(new ResourceCodeCompletionDataProvider(content, null, null), ch); + return true; + } + + } + + } + + return false; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/NewResourceCodeCompletionData.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/NewResourceCodeCompletionData.cs new file mode 100644 index 0000000000..3dfc8adadf --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/NewResourceCodeCompletionData.cs @@ -0,0 +1,63 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Globalization; +using System.Windows.Forms; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.NRefactory.PrettyPrinter; +using ICSharpCode.TextEditor; + +using Hornung.ResourceToolkit.Gui; +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Provides a code completion entry used to add a new string resource. + /// + public class NewResourceCodeCompletionData : ResourceCodeCompletionData + { + + readonly IResourceFileContent content; + readonly string preEnteredName; + + public NewResourceCodeCompletionData(IResourceFileContent content, IOutputAstVisitor outputVisitor, string preEnteredName) + : base(StringParser.Parse("${res:Hornung.ResourceToolkit.CodeCompletion.AddNewEntry}"), String.Format(CultureInfo.CurrentCulture, StringParser.Parse("${res:Hornung.ResourceToolkit.CodeCompletion.AddNewDescription}"), content.FileName), outputVisitor) + { + this.content = content; + this.preEnteredName = preEnteredName; + } + + /// + /// Present a form to the user where he enters the name for the new + /// string resource and then insert the key value into the text editor. + /// + /// TextArea to insert the completion data in. + /// Character that should be inserted after the completion data. + /// \0 when no character should be inserted. + /// Returns true when the insert action has processed the character + /// ; false when the character was not processed. + public override bool InsertAction(TextArea textArea, char ch) + { + + EditStringResourceDialog dialog = new EditStringResourceDialog(this.content, this.preEnteredName, null, true); + dialog.Text = this.Description; + if (dialog.ShowDialog(WorkbenchSingleton.MainForm) != DialogResult.OK) { + return false; + } + + this.Text = dialog.Key; + + this.content.Add(dialog.Key, dialog.Value); + + return base.InsertAction(textArea, ch); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionData.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionData.cs new file mode 100644 index 0000000000..95a762996e --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionData.cs @@ -0,0 +1,70 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.PrettyPrinter; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Gui.CompletionWindow; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Represents a code completion data entry for resource keys. + /// + public class ResourceCodeCompletionData : DefaultCompletionData + { + + readonly IOutputAstVisitor outputVisitor; + + /// + /// Initializes a new instance of the class. + /// + /// The resource key. + /// The resource description. + /// The NRefactory output visitor to be used to generate the inserted code. If null, the key is inserted literally. + public ResourceCodeCompletionData(string key, string description, IOutputAstVisitor outputVisitor) + : base(key, description, ClassBrowserIconService.GotoArrowIndex) + { + this.outputVisitor = outputVisitor; + } + + /// + /// Insert the element represented by the completion data into the text + /// editor. + /// + /// TextArea to insert the completion data in. + /// Character that should be inserted after the completion data. + /// \0 when no character should be inserted. + /// Returns true when the insert action has processed the character + /// ; false when the character was not processed. + public override bool InsertAction(TextArea textArea, char ch) + { + string insertString; + + if (this.outputVisitor != null) { + PrimitiveExpression pre = new PrimitiveExpression(this.Text, this.Text); + pre.AcceptVisitor(this.outputVisitor, null); + insertString = this.outputVisitor.Text; + } else { + insertString = this.Text; + } + + textArea.InsertString(insertString); + if (ch == insertString[insertString.Length - 1]) { + return true; + } + return false; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionDataProvider.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionDataProvider.cs new file mode 100644 index 0000000000..49bbb545c8 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/ResourceCodeCompletionDataProvider.cs @@ -0,0 +1,75 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.NRefactory.PrettyPrinter; +using ICSharpCode.TextEditor.Gui.CompletionWindow; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Provides code completion data for resource keys. + /// + public class ResourceCodeCompletionDataProvider : AbstractCompletionDataProvider + { + readonly IResourceFileContent content; + readonly IOutputAstVisitor outputVisitor; + readonly string preEnteredName; + + /// + /// Initializes a new instance of the class. + /// + /// The resource file content to be presented to the user. + /// The NRefactory output visitor to be used to generate the inserted code. If null, the key is inserted literally. + /// The type name which should be pre-entered in the 'add new' dialog box if the user selects the 'add new' entry. + public ResourceCodeCompletionDataProvider(IResourceFileContent content, IOutputAstVisitor outputVisitor, string preEnteredName) + { + if (content == null) { + throw new ArgumentNullException("content"); + } + this.content = content; + this.outputVisitor = outputVisitor; + this.preEnteredName = preEnteredName; + this.InsertSpace = false; + } + + /// + /// Generates the completion data. This method is called by the text editor control. + /// + public override ICompletionData[] GenerateCompletionData(string fileName, ICSharpCode.TextEditor.TextArea textArea, char charTyped) + { + List list = new List(); + + list.Add(new NewResourceCodeCompletionData(this.content, this.outputVisitor, this.preEnteredName)); + + foreach (KeyValuePair entry in this.content.Data) { + list.Add(new ResourceCodeCompletionData(entry.Key, ResourceResolverService.FormatResourceDescription(this.content, entry.Key), this.outputVisitor)); + } + + return list.ToArray(); + } + + /// + /// Gets if pressing 'key' should trigger the insertion of the currently selected element. + /// + public override CompletionDataProviderKeyResult ProcessKey(char key) + { + if (key == '.') { + // don't auto-complete on pressing '.' (this character is commonly used in resource key names) + return CompletionDataProviderKeyResult.NormalKey; + } + return base.ProcessKey(key); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/VBNetResourceCodeCompletionBinding.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/VBNetResourceCodeCompletionBinding.cs new file mode 100644 index 0000000000..41d5b231a7 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/CodeCompletion/VBNetResourceCodeCompletionBinding.cs @@ -0,0 +1,40 @@ +// +// +// +// +// $Revision$ +// + +using System; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.NRefactory.PrettyPrinter; + +namespace Hornung.ResourceToolkit.CodeCompletion +{ + /// + /// Provides code completion for inserting resource keys in VB. + /// + public class VBNetResourceCodeCompletionBinding : AbstractNRefactoryResourceCodeCompletionBinding + { + + /// + /// Determines if the specified character should trigger resource resolve attempt and possibly code completion at the current position. + /// + protected override bool CompletionPossible(SharpDevelopTextAreaControl editor, char ch) + { + return ch == '('; + } + + /// + /// Gets a VBNetOutputVisitor used to generate the inserted code. + /// + protected override IOutputAstVisitor OutputVisitor { + get { + return new VBNetOutputVisitor(); + } + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs new file mode 100644 index 0000000000..7502bda4bc --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/RefactoringCommands.cs @@ -0,0 +1,57 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Refactoring; + +using Hornung.ResourceToolkit.Gui; +using Hornung.ResourceToolkit.Refactoring; + +namespace Hornung.ResourceToolkit.Commands +{ + /// + /// Find missing resource keys in the whole solution. + /// + public class FindMissingResourceKeysCommand : AbstractMenuCommand + { + public override void Run() + { + FindReferencesAndRenameHelper.ShowAsSearchResults(StringParser.Parse("${res:Hornung.ResourceToolkit.ReferencesToMissingKeys}"), + ResourceRefactoringService.FindReferencesToMissingKeys()); + } + } + + /// + /// Find unused resource keys in the whole solution. + /// + public class FindUnusedResourceKeysCommand : AbstractMenuCommand + { + public override void Run() + { + ICollection> unusedKeys = ResourceRefactoringService.FindUnusedKeys(); + + if (unusedKeys == null) { + return; + } + + if (unusedKeys.Count == 0) { + MessageService.ShowMessage("${res:Hornung.ResourceToolkit.UnusedResourceKeys.NotFound}"); + return; + } + + IWorkbench workbench = WorkbenchSingleton.Workbench; + if (workbench != null) { + UnusedResourceKeysViewContent vc = new UnusedResourceKeysViewContent(unusedKeys); + workbench.ShowView(vc); + } + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs new file mode 100644 index 0000000000..d959b9f0dc --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Commands/TextEditorContextMenuBuilder.cs @@ -0,0 +1,150 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Refactoring; +using ICSharpCode.TextEditor; + +using Hornung.ResourceToolkit.Gui; +using Hornung.ResourceToolkit.Refactoring; +using Hornung.ResourceToolkit.Resolver; +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Commands +{ + /// + /// Builds context menu for editing string resources. + /// + public class TextEditorContextMenuBuilder : ISubmenuBuilder + { + public ToolStripItem[] BuildSubmenu(Codon codon, object owner) + { + TextEditorControl editor = owner as TextEditorControl; + + if (editor == null) { + return new ToolStripItem[0]; + } + + ResourceResolveResult result = ResourceResolverService.Resolve(editor); + if (result != null && result.ResourceFileContent != null && result.Key != null) { + + List items = new List(); + MenuCommand cmd; + + // add resource (if key does not exist) / edit resource (if key exists) + if (result.ResourceFileContent.ContainsKey(result.Key)) { + cmd = new MenuCommand("${res:Hornung.ResourceToolkit.TextEditorContextMenu.EditResource}", this.EditResource); + } else { + cmd = new MenuCommand("${res:Hornung.ResourceToolkit.TextEditorContextMenu.AddResource}", this.EditResource); + } + cmd.Tag = result; + items.Add(cmd); + + // find references + cmd = new MenuCommand("${res:SharpDevelop.Refactoring.FindReferencesCommand}", this.FindReferences); + cmd.Tag = result; + items.Add(cmd); + + // rename + cmd = new MenuCommand("${res:SharpDevelop.Refactoring.RenameCommand}", this.Rename); + cmd.Tag = result; + items.Add(cmd); + + + // put the resource menu items into a submenu + // with the resource key as title + ToolStripMenuItem subMenu = new ToolStripMenuItem(result.Key); + subMenu.DropDownItems.AddRange(items.ToArray()); + return new ToolStripItem[] { subMenu, new MenuSeparator() }; + + } + + return new ToolStripItem[0]; + } + + // ******************************************************************************************************************************** + + void EditResource(object sender, EventArgs e) + { + MenuCommand cmd = sender as MenuCommand; + if (cmd == null) { + return; + } + + ResourceResolveResult result = cmd.Tag as ResourceResolveResult; + if (result == null) { + return; + } + + object value; + string svalue = null; + if (result.ResourceFileContent.TryGetValue(result.Key, out value)) { + svalue = value as string; + if (svalue == null) { + MessageService.ShowWarning("${res:Hornung.ResourceToolkit.ResourceTypeNotSupported}"); + return; + } + } + + EditStringResourceDialog dialog = new EditStringResourceDialog(result.ResourceFileContent, result.Key, svalue, false); + if (svalue == null) { + dialog.Text = String.Format(CultureInfo.CurrentCulture, StringParser.Parse("${res:Hornung.ResourceToolkit.CodeCompletion.AddNewDescription}"), result.ResourceFileContent.FileName); + } + if (dialog.ShowDialog(WorkbenchSingleton.MainForm) == DialogResult.OK) { + if (svalue == null) { + // Add new resource. + result.ResourceFileContent.Add(dialog.Key, dialog.Value); + } else { + // Modify existing resource. + result.ResourceFileContent.SetValue(result.Key, dialog.Value); + } + } + + } + + // ******************************************************************************************************************************** + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body")] + void FindReferences(object sender, EventArgs e) + { + MenuCommand cmd = sender as MenuCommand; + if (cmd == null) { + return; + } + + ResourceResolveResult result = cmd.Tag as ResourceResolveResult; + if (result == null) { + return; + } + + FindReferencesAndRenameHelper.ShowAsSearchResults(StringParser.Parse("${res:Hornung.ResourceToolkit.ReferencesToResource}", new string[,] { {"ResourceFileName", System.IO.Path.GetFileName(result.FileName)}, {"ResourceKey", result.Key} }), + ResourceRefactoringService.FindReferences(result.FileName, result.Key)); + } + + void Rename(object sender, EventArgs e) + { + MenuCommand cmd = sender as MenuCommand; + if (cmd == null) { + return; + } + + ResourceResolveResult result = cmd.Tag as ResourceResolveResult; + if (result == null) { + return; + } + + ResourceRefactoringService.Rename(result); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/EditStringResourceDialog.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/EditStringResourceDialog.cs new file mode 100644 index 0000000000..ca3c78caf8 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/EditStringResourceDialog.cs @@ -0,0 +1,83 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.ComponentModel; +using System.Windows.Forms; +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui.XmlForms; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Gui +{ + /// + /// A dialog where the user can edit a string resource key and value. + /// + public class EditStringResourceDialog : BaseSharpDevelopForm + { + + readonly IResourceFileContent content; + + public EditStringResourceDialog(IResourceFileContent content, string key, string value, bool allowEditKey) : base() + { + this.content = content; + key = key ?? String.Empty; + value = value ?? String.Empty; + + InitializeComponent(); + + if (allowEditKey) { + this.Get("key").Validating += this.KeyValidating; + } else { + this.Get("key").ReadOnly = true; + } + + this.Get("key").Text = key; + this.Get("value").Text = value; + + if (allowEditKey) { + this.Get("key").Select(); + this.Get("key").Select(key.Length, 0); + } else { + this.Get("value").Select(); + this.Get("value").Select(value.Length, 0); + } + + } + + void InitializeComponent() + { + SetupFromXmlStream(this.GetType().Assembly.GetManifestResourceStream("Hornung.ResourceToolkit.Resources.EditStringResourceDialog.xfrm")); + } + + void KeyValidating(object sender, CancelEventArgs e) + { + TextBox textBox = (TextBox)sender; + if (textBox.Text.Trim().Length == 0) { + e.Cancel = true; + MessageService.ShowWarning("${res:Hornung.ResourceToolkit.EditStringResourceDialog.KeyIsEmpty}"); + } else if (this.content.ContainsKey(textBox.Text.Trim())) { + e.Cancel = true; + MessageService.ShowWarning("${res:Hornung.ResourceToolkit.EditStringResourceDialog.DuplicateKey}"); + } + } + + public string Key { + get { + return this.Get("key").Text.Trim(); + } + } + + public string Value { + get { + return this.Get("value").Text; + } + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/UnusedResourceKeysViewContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/UnusedResourceKeysViewContent.cs new file mode 100644 index 0000000000..880a6b6fbf --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Gui/UnusedResourceKeysViewContent.cs @@ -0,0 +1,316 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Globalization; +using System.IO; +using System.Windows.Forms; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Gui; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Gui +{ + /// + /// Displays unused resource keys in a list and allows the user to delete them. + /// + public class UnusedResourceKeysViewContent : AbstractViewContent, IClipboardHandler + { + readonly ICollection> unusedKeys; + Panel panel; + ListView listView; + + public override System.Windows.Forms.Control Control { + get { + return this.panel; + } + } + + /// + /// Gets the ListView control that shows the unused resource keys. + /// + public System.Windows.Forms.ListView ListView { + get { + return this.listView; + } + } + + /// + /// Gets a collection of key/value pairs where the values are the resource file names and the keys are the unused resource keys. + /// + public ICollection> UnusedKeys { + get { + return this.unusedKeys; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// A collection of key/value pairs where the values are the resource file names and the keys are the unused resource keys. + public UnusedResourceKeysViewContent(ICollection> unusedKeys) + : base(StringParser.Parse("${res:Hornung.ResourceToolkit.UnusedResourceKeys.Title}")) + { + LoggingService.Debug("ResourceToolkit: Creating new UnusedResourceKeysViewContent"); + + if (unusedKeys == null) { + throw new ArgumentNullException("unusedKeys"); + } + this.unusedKeys = unusedKeys; + + this.panel = new Panel(); + this.panel.SuspendLayout(); + this.panel.Dock = DockStyle.Fill; + + this.listView = new ListView(); + this.ListView.Columns.Add(StringParser.Parse("${res:Hornung.ResourceToolkit.FileName}"), 60); + this.ListView.Columns.Add(StringParser.Parse("${res:Hornung.ResourceToolkit.Key}"), 140); + this.ListView.Columns.Add(StringParser.Parse("${res:Hornung.ResourceToolkit.Value}"), 140); + this.ListView.CheckBoxes = true; + this.ListView.View = View.Details; + this.ListView.FullRowSelect = true; + this.ListView.ShowItemToolTips = true; + this.ListView.ListViewItemSorter = new ResourceListViewItemComparer(); + this.ListView.Dock = DockStyle.Fill; + this.ListView.Resize += delegate { + if (this.ListView != null && !this.ListView.IsDisposed && !this.ListView.Disposing && this.ListView.Columns.Count >= 3) { + this.ListView.Columns[0].Width = Convert.ToInt32(this.ListView.Width * 0.20); + this.ListView.Columns[1].Width = Convert.ToInt32(this.ListView.Width * 0.45); + this.ListView.Columns[2].Width = Convert.ToInt32(this.ListView.Width * 0.30); + } + }; + this.ListView.HandleCreated += this.ListViewHandleCreated; + this.ListView.ContextMenuStrip = MenuService.CreateContextMenu(this, "/AddIns/ResourceToolkit/ViewContent/UnusedResourceKeys/ListViewContextMenu"); + + ToolStrip toolStrip = ToolbarService.CreateToolStrip(this, "/AddIns/ResourceToolkit/ViewContent/UnusedResourceKeys/Toolbar"); + toolStrip.Dock = DockStyle.Top; + toolStrip.Stretch = true; + + this.panel.Controls.Add(this.ListView); + this.panel.Controls.Add(toolStrip); + this.panel.ResumeLayout(); + } + + void ListViewHandleCreated(object sender, EventArgs e) + { + this.ListView.HandleCreated -= this.ListViewHandleCreated; + this.ListView.BeginInvoke(new Action>>(this.FillListView), this.UnusedKeys); + } + + public override void Dispose() + { + this.panel.Controls.Clear(); + this.ListView.Dispose(); + this.listView = null; + this.panel.Dispose(); + this.panel = null; + base.Dispose(); + } + + // ******************************************************************************************************************************** + + class ResourceListViewItemComparer : System.Collections.IComparer + { + public int Compare(object x, object y) + { + ListViewItem a = (ListViewItem)x; + ListViewItem b = (ListViewItem)y; + return String.Compare(String.Concat(a.Text, a.SubItems[1].Text), String.Concat(b.Text, b.SubItems[1].Text)); + } + } + + /// + /// Fills the list view with the specified resource keys. + /// + /// A collection of key/value pairs where the values are the resource file names and the keys are the resource keys. + public void FillListView(ICollection> resources) + { + Application.DoEvents(); + Cursor oldCursor = Cursor.Current; + Cursor.Current = Cursors.WaitCursor; + try { + + this.ListView.Items.Clear(); + this.ListView.Groups.Clear(); + this.ListView.BeginUpdate(); + + Dictionary fileGroups = new Dictionary(); + + // Create the ListViewItems. + foreach (KeyValuePair entry in resources) { + IResourceFileContent c = ResourceFileContentRegistry.GetResourceFileContent(entry.Value); + object o; + + // only add the file name to save space + // and show the full path as tooltip + ListViewItem item = new ListViewItem(Path.GetFileName(entry.Value)); + item.ToolTipText = entry.Value; + item.SubItems.Add(entry.Key); + if (c.TryGetValue(entry.Key, out o)) { + item.SubItems.Add((o ?? (object)"<>").ToString()); + } else { + throw new InvalidOperationException("The key '"+entry.Key+"' in file '"+entry.Value+"' does not exist although it was reported as unused."); + } + + // Use ListViewGroups to group by file names + ListViewGroup grp; + if (!fileGroups.TryGetValue(entry.Value, out grp)) { + grp = new ListViewGroup(entry.Value); + fileGroups.Add(entry.Value, grp); + this.ListView.Groups.Add(grp); + } + grp.Items.Add(item); + + this.ListView.Items.Add(item); + } + + this.ListView.EndUpdate(); + + } finally { + Cursor.Current = oldCursor; + } + } + + // ******************************************************************************************************************************** + + #region IClipboardHandler implementation + + public bool EnableCut { + get { + return false; + } + } + + public bool EnableCopy { + get { + return false; + } + } + + public bool EnablePaste { + get { + return false; + } + } + + public bool EnableDelete { + get { + return this.ListView.SelectedItems.Count > 0; + } + } + + public bool EnableSelectAll { + get { + return this.ListView.Items.Count > 0; + } + } + + public void Cut() + { + throw new NotImplementedException(); + } + + public void Copy() + { + throw new NotImplementedException(); + } + + public void Paste() + { + throw new NotImplementedException(); + } + + public void Delete() + { + if (this.ListView.SelectedItems.Count > 0) { + + bool ok; + + if (this.ListView.SelectedItems.Count == 1) { + ok = MessageService.AskQuestion(StringParser.Parse("${res:Hornung.ResourceToolkit.DeleteSingleResourceKeyQuestion}", new string[,] { {"Key", this.ListView.SelectedItems[0].SubItems[1].Text}, {"FileName", this.ListView.SelectedItems[0].Group.Header} })); + } else { + ok = MessageService.AskQuestion(StringParser.Parse("${res:Hornung.ResourceToolkit.DeleteAllSelectedResourceKeysQuestion}", new string[,] { {"Count", this.ListView.SelectedItems.Count.ToString(CultureInfo.CurrentCulture)} })); + } + + if (ok) { + this.DeleteResources(this.ListView.SelectedItems); + } + + } + } + + public void SelectAll() + { + foreach (ListViewItem item in this.ListView.Items) { + item.Selected = true; + } + } + + #endregion + + // ******************************************************************************************************************************** + + /// + /// Deletes the resource keys represented by the specified ListViewItems. + /// + public void DeleteResources(System.Collections.IEnumerable itemsToDelete) + { + Application.DoEvents(); + Cursor oldCursor = Cursor.Current; + Cursor.Current = Cursors.WaitCursor; + try { + + // The collection must not be modified during the enumeration. + // -> Save the items that should be deleted in a separate list. + List items = new List(); + foreach (ListViewItem item in itemsToDelete) { + DeleteResourceKey(item.Group.Header, item.SubItems[1].Text); + items.Add(item); + } + + items.ForEach(this.ListView.Items.Remove); + + } finally { + Cursor.Current = oldCursor; + } + } + + /// + /// Deletes the specified resource key in the resource file and all dependent localized + /// resource files permanently. + /// + /// The master resource file that contains the key to be deleted. + /// The key to be deleted. + protected static void DeleteResourceKey(string fileName, string key) + { + IResourceFileContent content = ResourceFileContentRegistry.GetResourceFileContent(fileName); + if (content != null) { + if (content.ContainsKey(key)) { + LoggingService.Debug("ResourceToolkit: Remove key '"+key+"' from resource file '"+fileName+"'"); + content.RemoveKey(key); + } else { + MessageService.ShowWarningFormatted("${res:Hornung.ResourceToolkit.KeyNotFoundWarning}", key, fileName); + } + } else { + MessageService.ShowWarning("ResoureToolkit: Could not get ResourceFileContent for '"+fileName+"' key +'"+key+"'."); + } + + foreach (KeyValuePair entry in ResourceFileContentRegistry.GetLocalizedContents(fileName)) { + LoggingService.Debug("ResourceToolkit: Looking in localized resource file: '"+entry.Value.FileName+"'"); + if (entry.Value.ContainsKey(key)) { + LoggingService.Debug("ResourceToolkit: -> Key found, removing."); + entry.Value.RemoveKey(key); + } + } + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs new file mode 100644 index 0000000000..2836df1538 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ProjectFileDictionaryService.cs @@ -0,0 +1,90 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; + +namespace Hornung.ResourceToolkit +{ + /// + /// Provides a way to find out which project a certain file belongs to + /// and caches the results to improve performance. + /// + public static class ProjectFileDictionaryService + { + static Dictionary files = new Dictionary(); + + static ProjectFileDictionaryService() + { + // Remove file from dictionary when file is removed from project + ProjectService.ProjectItemRemoved += delegate(object sender, ProjectItemEventArgs e) { + if (e.ProjectItem != null && e.ProjectItem.FileName != null) { + files.Remove(e.ProjectItem.FileName); + } + }; + // Clear cache when solution is closed + ProjectService.SolutionClosed += delegate { files.Clear(); }; + } + + /// + /// Gets the project that contains the specified file. + /// + /// The file to find the project for. + /// The project that contains the specified file. If the file is not found in any project or there is no open project, the current project is returned, which may be null. + public static IProject GetProjectForFile(string fileName) + { + if (!String.IsNullOrEmpty(fileName)) { + + IProject p; + + if (files.TryGetValue(fileName, out p)) { + return p; + } + + if ((p = GetProjectForFileInternal(fileName)) != null) { + files[fileName] = p; + return p; + } + + } + + LoggingService.Debug("ResourceToolkit: ProjectFileDictionary: Could not determine project for file '"+(fileName ?? "")+"'."); + + return ProjectService.CurrentProject; + } + + /// + /// Gets the project that contains the specified file. + /// + /// The file to find the project for. + /// The project that contains the specified file. If the file is not found in any project or there is no open project, null is returned. + static IProject GetProjectForFileInternal(string fileName) + { + if (ProjectService.OpenSolution != null) { + IProject p; + if ((p = ProjectService.OpenSolution.FindProjectContainingFile(fileName)) != null) { + return p; + } + } + return null; + } + + /// + /// Adds a file name to the project dictionary or sets the file's project if + /// it is already listed. + /// + /// The file to add. + /// The project the specified file belongs to. + public static void AddFile(string file, IProject project) + { + files[file] = project; + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/AnyResourceReferenceFinder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/AnyResourceReferenceFinder.cs new file mode 100644 index 0000000000..18e3afef48 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/AnyResourceReferenceFinder.cs @@ -0,0 +1,83 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +using Hornung.ResourceToolkit.Resolver; + +namespace Hornung.ResourceToolkit.Refactoring +{ + /// + /// Finds references to resources in a text document. + /// + public class AnyResourceReferenceFinder : IResourceReferenceFinder + { + /// + /// Returns the offset of the next possible resource reference in the file + /// after prevOffset. + /// Returns -1, if there are no more possible references. + /// + /// The name of the file that is currently being searched in. + /// The text content of the file. + /// The offset of the last found reference or -1, if this is the first call in the current file. + public int GetNextPossibleOffset(string fileName, string fileContent, int prevOffset) + { + int pos = -1; + int i; + + foreach (string pattern in GetPossiblePatternsForFile(fileName)) { + if ((i = fileContent.IndexOf(pattern, prevOffset+1, StringComparison.InvariantCultureIgnoreCase)) >= 0) { + if (pos == -1 || i < pos) { + pos = i; + } + } + } + + return pos; + } + + /// + /// Determines whether the specified ResourceResolveResult describes + /// a resource that should be included in the search result. + /// + public bool IsReferenceToResource(ResourceResolveResult result) + { + return true; + } + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by any + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public static IEnumerable GetPossiblePatternsForFile(string fileName) + { + List patterns = new List(); + foreach (IResourceResolver resolver in ResourceResolverService.Resolvers) { + if (resolver.SupportsFile(fileName)) { + foreach (string pattern in resolver.GetPossiblePatternsForFile(fileName)) { + if (!patterns.Contains(pattern)) { + patterns.Add(pattern); + } + } + } + } + return patterns; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public AnyResourceReferenceFinder() + { + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/IResourceReferenceFinder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/IResourceReferenceFinder.cs new file mode 100644 index 0000000000..4e72e4644c --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/IResourceReferenceFinder.cs @@ -0,0 +1,35 @@ +// +// +// +// +// $Revision$ +// + +using System; + +using Hornung.ResourceToolkit.Resolver; + +namespace Hornung.ResourceToolkit.Refactoring +{ + /// + /// Describes an object that finds resource references in a text document. + /// + public interface IResourceReferenceFinder + { + /// + /// Returns the offset of the next possible resource reference in the file + /// after prevOffset. + /// Returns -1, if there are no more possible references. + /// + /// The name of the file that is currently being searched in. + /// The text content of the file. + /// The offset of the last found reference or -1, if this is the first call in the current file. + int GetNextPossibleOffset(string fileName, string fileContent, int prevOffset); + + /// + /// Determines whether the specified ResourceResolveResult describes + /// a resource that should be included in the search result. + /// + bool IsReferenceToResource(ResourceResolveResult result); + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs new file mode 100644 index 0000000000..76eefe6566 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/ResourceRefactoringService.cs @@ -0,0 +1,364 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.SharpDevelop.Refactoring; +using ICSharpCode.TextEditor.Document; + +using Hornung.ResourceToolkit.Resolver; +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Refactoring +{ + /// + /// Provides facilities for refactoring resources. + /// + public static class ResourceRefactoringService + { + + /// + /// Finds all references to the specified resource (except the definition). + /// + /// The name of the resource file that contains the resource key to find. + /// The resource key to find. + /// A list of references to this resource. + public static List FindReferences(string resourceFileName, string key) + { + return FindReferences(new SpecificResourceReferenceFinder(resourceFileName, key)); + } + + /// + /// Finds all references to resources (except the definition) using the specified + /// object. + /// + /// The to use to find resource references. + /// A list of references to resources. + public static List FindReferences(IResourceReferenceFinder finder) + { + if (finder == null) { + throw new ArgumentNullException("finder"); + } + + if (ParserService.LoadSolutionProjectsThreadRunning) { + MessageService.ShowMessage("${res:SharpDevelop.Refactoring.LoadSolutionProjectsThreadRunning}"); + return null; + } + + DateTime startTime = DateTime.UtcNow; + + List references = new List(); + + try { + + NRefactoryAstCacheService.EnableCache(); + + foreach (string fileName in GetPossibleFiles()) { + + IDocument doc = null; + try { + // The following line throws an exception if the file does not exist. + // But the file may be in an unsaved view content (which would be found by GetDocumentInformation), + // so we cannot simply loop on !File.Exists(...). + doc = FindReferencesAndRenameHelper.GetDocumentInformation(fileName).CreateDocument(); + } catch (FileNotFoundException) { + } + if (doc == null) { + continue; + } + + string fileContent = doc.TextContent; + if (String.IsNullOrEmpty(fileContent)) { + continue; + } + + int pos = -1; + while ((pos = finder.GetNextPossibleOffset(fileName, fileContent, pos)) >= 0) { + + Point docPos = doc.OffsetToPosition(pos); + ResourceResolveResult rrr = ResourceResolverService.Resolve(fileName, doc, docPos.Y, docPos.X); + + if (rrr != null && rrr.ResourceFileContent != null && rrr.Key != null) { + if (finder.IsReferenceToResource(rrr)) { + + // The actual location of the key string may be after 'pos' because + // the resolvers may find an expression just before it. + string keyString = rrr.Key; + int keyPos = fileContent.IndexOf(keyString, pos, StringComparison.InvariantCultureIgnoreCase); + + if (keyPos < pos) { + // The key may be escaped in some way in the document. + // Try using the code generator to find this out. + keyPos = FindStringLiteral(fileName, fileContent, rrr.Key, pos, out keyString); + } + + if (keyPos < pos) { + MessageService.ShowWarning("ResourceToolkit: The key '"+rrr.Key+"' could not be located at the resolved position in the file '"+fileName+"'."); + } else { + references.Add(new Reference(fileName, keyPos, keyString.Length, keyString, rrr)); + } + + } + } + + } + + } + + LoggingService.Info("ResourceToolkit: FindReferences finished in "+(DateTime.UtcNow - startTime).TotalSeconds.ToString(System.Globalization.CultureInfo.CurrentCulture)+"s"); + + } finally { + NRefactoryAstCacheService.DisableCache(); + } + + return references; + } + + /// + /// Finds all references to resources (except the definitions). + /// + /// A list of references to resources. + public static List FindAllReferences() + { + return FindReferences(new AnyResourceReferenceFinder()); + } + + /// + /// Finds all references to missing resource keys. + /// + /// A list of all references to missing resource keys. + public static List FindReferencesToMissingKeys() + { + List references = FindAllReferences(); + if (references == null) { + return null; + } + return references.FindAll(IsReferenceToMissingKey); + } + + /// + /// Determines whether the specified reference is a resource reference + /// to a missing key. + /// + /// The reference to examine. + /// true, if the specified reference is a resource reference to a missing key, otherwise false. + public static bool IsReferenceToMissingKey(Reference reference) + { + ResourceResolveResult rrr = reference.ResolveResult as ResourceResolveResult; + if (rrr == null || rrr.Key == null) { + return false; + } + if (rrr.ResourceFileContent == null) { + return true; + } + return !rrr.ResourceFileContent.ContainsKey(rrr.Key); + } + + /// + /// Finds all unused resource keys in all resource files that are referenced + /// in code at least once in the whole solution. + /// + /// A collection of key/value pairs where the values are the resource file names and the keys are the unused resource keys. + public static ICollection> FindUnusedKeys() + { + List references = FindAllReferences(); + if (references == null) { + return null; + } + + DateTime startTime = DateTime.UtcNow; + List> unused = new List>(); + + // Get a list of all referenced resource files. + // Generate a dictonary of resource file names and the + // corresponding referenced keys. + Dictionary> referencedKeys = new Dictionary>(); + foreach (Reference reference in references) { + ResourceResolveResult rrr = (ResourceResolveResult)reference.ResolveResult; + if (rrr.ResourceFileContent != null) { + string fileName = rrr.FileName; + if (!referencedKeys.ContainsKey(fileName)) { + referencedKeys.Add(fileName, new List()); + } + if (rrr.Key != null && !referencedKeys[fileName].Contains(rrr.Key)) { + referencedKeys[fileName].Add(rrr.Key); + } + } else { + MessageService.ShowWarning("Found a resource reference that could not be resolved."+Environment.NewLine+(reference.FileName ?? "")+":"+reference.Offset+Environment.NewLine+"Expression: "+(reference.Expression ?? "")); + } + } + + // Find keys that are not referenced anywhere. + foreach (string fileName in referencedKeys.Keys) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: FindUnusedKeys: Referenced resource file '"+fileName+"'"); + #endif + foreach (KeyValuePair entry in ResourceFileContentRegistry.GetResourceFileContent(fileName).Data) { + if (!referencedKeys[fileName].Contains(entry.Key)) { + unused.Add(new KeyValuePair(entry.Key, fileName)); + } + } + } + + LoggingService.Info("ResourceToolkit: FindUnusedKeys finished in "+(DateTime.UtcNow - startTime).TotalSeconds.ToString(System.Globalization.CultureInfo.CurrentCulture)+"s"); + + return unused.AsReadOnly(); + } + + // ******************************************************************************************************************************** + + /// + /// Renames all references to a resource including the definition. + /// Asks the user for a new name. + /// + /// The resource to be renamed. + public static void Rename(ResourceResolveResult rrr) + { + string newKey = MessageService.ShowInputBox("${res:SharpDevelop.Refactoring.Rename}", "${res:Hornung.ResourceToolkit.RenameResourceText}", rrr.Key); + if (!String.IsNullOrEmpty(newKey) && !newKey.Equals(rrr.Key)) { + Rename(rrr, newKey); + } + } + + /// + /// Renames all references to a resource including the definition. + /// + /// The resource to be renamed. + /// The new name of the resource key. + public static void Rename(ResourceResolveResult rrr, string newKey) + { + // Prevent duplicate key names + if (rrr.ResourceFileContent.ContainsKey(newKey)) { + MessageService.ShowWarning("${res:Hornung.ResourceToolkit.EditStringResourceDialog.DuplicateKey}"); + return; + } + + List references = FindReferences(rrr.FileName, rrr.Key); + if (references == null) { + return; + } + + // rename references + // FIXME: RenameReferences does not enforce escaping rules. May be a problem if someone uses double-quotes in the new resource key name. + FindReferencesAndRenameHelper.RenameReferences(references, newKey); + + // rename definition (if present) + if (rrr.ResourceFileContent.ContainsKey(rrr.Key)) { + rrr.ResourceFileContent.RenameKey(rrr.Key, newKey); + } else { + MessageService.ShowWarning("${res:Hornung.ResourceToolkit.RenameKeyDefinitionNotFoundWarning}"); + } + + // rename definitions in localized resource files + foreach (KeyValuePair entry in ResourceFileContentRegistry.GetLocalizedContents(rrr.FileName)) { + if (entry.Value.ContainsKey(rrr.Key)) { + entry.Value.RenameKey(rrr.Key, newKey); + } + } + } + + // ******************************************************************************************************************************** + + /// + /// Gets a list of names of files which can possibly contain resource references. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public static List GetPossibleFiles() + { + List files = new List(); + + if (ProjectService.OpenSolution == null) { + + foreach (IViewContent vc in WorkbenchSingleton.Workbench.ViewContentCollection) { + string name = vc.FileName ?? vc.UntitledName; + if (IsPossibleFile(name)) { + files.Add(name); + } + } + + } else { + + foreach (IProject p in ProjectService.OpenSolution.Projects) { + foreach (ProjectItem pi in p.Items) { + if (pi is FileProjectItem) { + string name = pi.FileName; + if (IsPossibleFile(name)) { + files.Add(name); + // Add the file to the project dictionary here. + // This saves the lookup time when the corresponding project + // is needed later. + ProjectFileDictionaryService.AddFile(name, p); + } + } + } + } + + } + + return files; + } + + /// + /// Determines whether the specified file could possibly contain resource references + /// that can be detected by at least one registered resource resolver. + /// + public static bool IsPossibleFile(string name) + { + foreach (IResourceResolver resolver in ResourceResolverService.Resolvers) { + if (resolver.SupportsFile(name)) { + return true; + } + } + return false; + } + + // ******************************************************************************************************************************** + + /// + /// Finds a string literal in a source code file with respect to escaping rules + /// of the language. + /// + /// The name of the file to search in. + /// The text content of the file. + /// The string literal to find. + /// The position to start searching at. + /// Receives the unquoted program code that represents the specified string literal in the language this file is written in. + /// The next index where the specified string literal appears, or -1 if there is no match or the language cannot be determined. + public static int FindStringLiteral(string fileName, string fileContent, string literal, int startOffset, out string code) + { + ICSharpCode.SharpDevelop.Dom.LanguageProperties lp = NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName); + + if (lp != null && lp.CodeGenerator != null) { + + code = lp.CodeGenerator.GenerateCode(new PrimitiveExpression(literal, literal), String.Empty); + + if (!String.IsNullOrEmpty(code)) { + // Unquote the string if possible. + if (code.StartsWith("\"") || code.StartsWith("'")) { + code = code.Substring(1); + } + if (code.EndsWith("\"") || code.EndsWith("'")) { + code = code.Remove(code.Length-1); + } + return fileContent.IndexOf(code, startOffset, StringComparison.InvariantCultureIgnoreCase); + } + + } + + code = null; + return -1; + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/SpecificResourceReferenceFinder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/SpecificResourceReferenceFinder.cs new file mode 100644 index 0000000000..bad0467907 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Refactoring/SpecificResourceReferenceFinder.cs @@ -0,0 +1,93 @@ +// +// +// +// +// $Revision$ +// + +using System; + +using ICSharpCode.Core; + +using Hornung.ResourceToolkit.Resolver; + +namespace Hornung.ResourceToolkit.Refactoring +{ + /// + /// Finds references to a specific resource in a text document. + /// + public class SpecificResourceReferenceFinder : IResourceReferenceFinder + { + readonly string resourceFileName; + readonly string key; + + /// + /// Gets the name of the resource file that contains the resource to find. + /// + public string ResourceFileName { + get { + return resourceFileName; + } + } + + /// + /// Gets the resource key to find. + /// + public string Key { + get { + return key; + } + } + + // ******************************************************************************************************************************** + + /// + /// Returns the offset of the next possible resource reference in the file + /// after prevOffset. + /// Returns -1, if there are no more possible references. + /// + /// The name of the file that is currently being searched in. + /// The text content of the file. + /// The offset of the last found reference or -1, if this is the first call in the current file. + public int GetNextPossibleOffset(string fileName, string fileContent, int prevOffset) + { + string code; + int pos = ResourceRefactoringService.FindStringLiteral(fileName, fileContent, this.Key, prevOffset+1, out code); + if (pos == -1) { + // if the code generator search fails, try a direct search + pos = fileContent.IndexOf(this.Key, prevOffset+1, StringComparison.InvariantCultureIgnoreCase); + } + return pos; + } + + /// + /// Determines whether the specified ResourceResolveResult describes + /// a resource that should be included in the search result. + /// + public bool IsReferenceToResource(ResourceResolveResult result) + { + return FileUtility.IsEqualFileName(this.ResourceFileName, result.FileName) && + result.Key.Equals(this.Key, StringComparison.InvariantCultureIgnoreCase); + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + /// The name of the resource file that contains the resource to find. + /// The resource key to find. + public SpecificResourceReferenceFinder(string resourceFileName, string key) + { + if (resourceFileName == null) { + throw new ArgumentNullException("resourceFileName"); + } + if (key == null) { + throw new ArgumentNullException("key"); + } + + this.resourceFileName = resourceFileName; + this.key = key; + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs new file mode 100644 index 0000000000..1f37f44535 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/AbstractResourceResolver.cs @@ -0,0 +1,112 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Abstract base class for resource resolvers. + /// + public abstract class AbstractResourceResolver : IResourceResolver + { + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 0-based line in the file that contains the expression to be resolved. + /// The 0-based column position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the specified position in the specified file, or null if that expression does not reference a (known) resource or if the specified position is invalid. + public ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn) + { + if (fileName == null || document == null) { + LoggingService.Debug("ResourceToolkit: "+this.GetType().ToString()+".Resolve called with null fileName or document argument"); + return null; + } + if (caretLine < 0 || caretColumn < 0 || caretLine >= document.TotalNumberOfLines || caretColumn >= document.GetLineSegment(caretLine).TotalLength) { + LoggingService.Debug("ResourceToolkit: "+this.GetType().ToString()+".Resolve called with invalid position arguments"); + return null; + } + return this.Resolve(fileName, document, caretLine, caretColumn, document.PositionToOffset(new Point(caretColumn, caretLine))); + } + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The text editor for which a resource resolution attempt should be performed. + /// A that describes which resource is referenced by the expression at the caret in the specified editor, or null if that expression does not reference a (known) resource. + public ResourceResolveResult Resolve(TextEditorControl editor) + { + return this.Resolve(editor.FileName, editor.Document, editor.ActiveTextAreaControl.Caret.Line, editor.ActiveTextAreaControl.Caret.Column); + } + + // ******************************************************************************************************************************** + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 0-based line in the file that contains the expression to be resolved. + /// The 0-based column position of the expression to be resolved. + /// The offset of the position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the specified position in the specified file, or null if that expression does not reference a (known) resource. + protected abstract ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset); + + /// + /// Determines whether this resolver supports resolving resources in the given file. + /// + /// The name of the file to examine. + /// true, if this resolver supports resolving resources in the given file, false otherwise. + public abstract bool SupportsFile(string fileName); + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public abstract IEnumerable GetPossiblePatternsForFile(string fileName); + + // ******************************************************************************************************************************** + + /// + /// Tries to find a resource file with the given name in the given directory by + /// trying all known resource file extensions. + /// + protected static string FindResourceFileName(string fileName) + { + string f; + if (File.Exists(f = Path.ChangeExtension(fileName, ".resources"))) { + return f; + } + if (File.Exists(f = Path.ChangeExtension(fileName, ".resx"))) { + return f; + } + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + protected AbstractResourceResolver() + { + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs new file mode 100644 index 0000000000..d0d4a79a52 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/BclNRefactoryResourceResolver.cs @@ -0,0 +1,458 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Detects and resolves resource references using the standard .NET + /// framework provided resource access methods (ResourceManager and derived + /// classes). + /// + public class BclNRefactoryResourceResolver : INRefactoryResourceResolver + { + + /// + /// Tries to find a resource reference in the specified expression. + /// + /// The ExpressionResult for the expression. + /// The AST representation of the expression. + /// SharpDevelop's ResolveResult for the expression. + /// The line where the expression is located. + /// The column where the expression is located. + /// The name of the source file where the expression is located. + /// The content of the source file where the expression is located. + /// A ResourceResolveResult describing the referenced resource, or null, if this expression does not reference a resource using the standard .NET framework classes. + public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent) + { + IResourceFileContent rfc = null; + + MemberResolveResult mrr = resolveResult as MemberResolveResult; + if (mrr != null) { + rfc = ResolveResourceFileContent(mrr.ResolvedMember); + } + + LocalResolveResult lrr = resolveResult as LocalResolveResult; + if (lrr != null) { + if (!lrr.IsParameter) { + rfc = ResolveResourceFileContent(lrr.Field); + } + } + + + if (rfc != null) { + string key = GetKeyFromExpression(expr); + + // TODO: Add information about return type (of the resource, if present). + return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, rfc, key); + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Tries to determine the resource file content which is referenced by the + /// resource manager which is assigned to the specified member. + /// + /// + /// The IResourceFileContent, if successful, or a null reference, if the + /// specified member is not a resource manager or if the + /// resource file cannot be determined. + /// + static IResourceFileContent ResolveResourceFileContent(IMember member) + { + if (member != null && member.ReturnType != null) { + if (IsResourceManager(member.ReturnType) && member.DeclaringType != null && member.DeclaringType.CompilationUnit != null) { + + string declaringFileName = member.DeclaringType.CompilationUnit.FileName; + if (declaringFileName != null) { + + SupportedLanguage? language = NRefactoryResourceResolver.GetFileLanguage(declaringFileName); + if (language == null) { + return null; + } + + CompilationUnit cu = NRefactoryAstCacheService.GetFullAst(language.Value, declaringFileName); + if (cu != null) { + + ResourceManagerInitializationFindVisitor visitor = new ResourceManagerInitializationFindVisitor(member); + cu.AcceptVisitor(visitor, null); + if (visitor.FoundFileName != null) { + + return ResourceFileContentRegistry.GetResourceFileContent(visitor.FoundFileName); + + } + + } + + } + + } + } + return null; + } + + /// + /// Determines if the specified type is a ResourceManager type that can + /// be handled by this resolver. + /// + static bool IsResourceManager(IReturnType type) + { + IClass resourceManager = ParserService.CurrentProjectContent.GetClass("System.Resources.ResourceManager"); + if (resourceManager == null) { + return false; + } + + IClass c = type.GetUnderlyingClass(); + if (c == null) { + return false; + } + + return (c.CompareTo(resourceManager) == 0 || c.IsTypeInInheritanceTree(resourceManager)); + } + + // ******************************************************************************************************************************** + + #region ResourceManagerInitializationFindVisitor + + /// + /// Finds an initialization statement for a resource manager member and + /// tries to infer the referenced resource file from the parameters + /// given to the resource manager constructor. + /// + class ResourceManagerInitializationFindVisitor : PositionTrackingAstVisitor + { + + readonly IMember resourceManagerMember; + readonly bool isLocalVariable; + + CompilationUnit compilationUnit; + + string foundFileName; + + /// + /// Gets the resource file name which the resource manager accesses, or a null reference if the file could not be determined or does not exist. + /// + public string FoundFileName { + get { + return this.foundFileName; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The member which the resource manager to be found is assigned to. + public ResourceManagerInitializationFindVisitor(IMember resourceManagerMember) : base() + { + this.resourceManagerMember = resourceManagerMember; + IField resourceManagerField = resourceManagerMember as IField; + if (resourceManagerField != null && resourceManagerField.IsLocalVariable) { + this.isLocalVariable = true; + } + } + + public override object TrackedVisit(CompilationUnit compilationUnit, object data) + { + this.compilationUnit = compilationUnit; + return base.TrackedVisit(compilationUnit, data); + } + + public override object TrackedVisit(LocalVariableDeclaration localVariableDeclaration, object data) + { + return base.TrackedVisit(localVariableDeclaration, localVariableDeclaration); + } + + public override object TrackedVisit(FieldDeclaration fieldDeclaration, object data) + { + return base.TrackedVisit(fieldDeclaration, fieldDeclaration); + } + + public override object TrackedVisit(VariableDeclaration variableDeclaration, object data) + { + LocalVariableDeclaration localVariableDeclaration = data as LocalVariableDeclaration; + if (this.isLocalVariable && localVariableDeclaration != null) { + if (variableDeclaration.Name == this.resourceManagerMember.Name) { + // Make sure we got the right declaration by comparing the positions. + // Both must have the same start position. + if (localVariableDeclaration.StartLocation.X == this.resourceManagerMember.Region.BeginColumn && localVariableDeclaration.StartLocation.Y == this.resourceManagerMember.Region.BeginLine) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found local variable declaration: "+localVariableDeclaration.ToString()+" at "+localVariableDeclaration.StartLocation.ToString()); + #endif + data = true; + } + + } + } + FieldDeclaration fieldDeclaration = data as FieldDeclaration; + if (!this.isLocalVariable && fieldDeclaration != null) { + if (variableDeclaration.Name == this.resourceManagerMember.Name) { + // Make sure we got the right declaration by comparing the positions. + // Both must have the same start position. + if (fieldDeclaration.StartLocation.X == this.resourceManagerMember.Region.BeginColumn && fieldDeclaration.StartLocation.Y == this.resourceManagerMember.Region.BeginLine) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found field declaration: "+fieldDeclaration.ToString()+" at "+fieldDeclaration.StartLocation.ToString()); + #endif + data = true; + } + + } + } + return base.TrackedVisit(variableDeclaration, data); + } + + public override object TrackedVisit(AssignmentExpression assignmentExpression, object data) + { + if (this.FoundFileName == null && // skip if already found to improve performance + assignmentExpression.Op == AssignmentOperatorType.Assign && this.PositionAvailable && + (!this.isLocalVariable || this.resourceManagerMember.Region.IsInside(this.CurrentNodeStartLocation.Y, this.CurrentNodeStartLocation.X)) // skip if local variable is out of scope + ) { + + MemberResolveResult mrr = this.Resolve(assignmentExpression.Left, this.resourceManagerMember) as MemberResolveResult; + if (mrr != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: Resolved member: "+mrr.ResolvedMember.ToString()); + #endif + + // HACK: The GetType()s are necessary because the DOM IComparable implementations try to cast the parameter object to their own interface type which may fail. + if (mrr.ResolvedMember.GetType().Equals(this.resourceManagerMember.GetType()) && mrr.ResolvedMember.CompareTo(this.resourceManagerMember) == 0) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to field: "+assignmentExpression.ToString()); + #endif + data = true; + + // Resolving the property association only makes sense if + // there is a possible relationship between the return types + // of the resolved member and the member we are looking for. + } else if (this.compilationUnit != null && !this.isLocalVariable && + ( + mrr.ResolvedMember.ReturnType.Equals(this.resourceManagerMember.ReturnType) || + ( + mrr.ResolvedMember.ReturnType.GetUnderlyingClass() != null && this.resourceManagerMember.ReturnType.GetUnderlyingClass() != null && + ( + mrr.ResolvedMember.ReturnType.GetUnderlyingClass().IsTypeInInheritanceTree(this.resourceManagerMember.ReturnType.GetUnderlyingClass()) || + this.resourceManagerMember.ReturnType.GetUnderlyingClass().IsTypeInInheritanceTree(mrr.ResolvedMember.ReturnType.GetUnderlyingClass()) + ) + ) + )) { + + if (this.resourceManagerMember is IProperty && mrr.ResolvedMember is IField) { + // Find out if the resourceManagerMember is a property whose get block returns the value of the resolved member. + + PropertyFieldAssociationVisitor visitor = new PropertyFieldAssociationVisitor((IProperty)this.resourceManagerMember); + this.compilationUnit.AcceptVisitor(visitor, null); + if (visitor.AssociatedField != null && visitor.AssociatedField.CompareTo(mrr.ResolvedMember) == 0) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to field: "+assignmentExpression.ToString()); + #endif + data = true; + } + + } else if (this.resourceManagerMember is IField && mrr.ResolvedMember is IProperty) { + // Find out if the resolved member is a property whose set block assigns the value to the resourceManagerMember. + + PropertyFieldAssociationVisitor visitor = new PropertyFieldAssociationVisitor((IField)this.resourceManagerMember); + this.compilationUnit.AcceptVisitor(visitor, null); + if (visitor.AssociatedProperty != null && visitor.AssociatedProperty.CompareTo(mrr.ResolvedMember) == 0) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found assignment to property: "+assignmentExpression.ToString()); + #endif + data = true; + } + + } + + } + + } + + } + return base.TrackedVisit(assignmentExpression, data); + } + + public override object TrackedVisit(ObjectCreateExpression objectCreateExpression, object data) + { + if (data as bool? ?? false) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found object initialization: "+objectCreateExpression.ToString()); + #endif + + // Resolve the constructor. + // A type derived from the declaration type is also allowed. + MemberResolveResult mrr = this.Resolve(objectCreateExpression, this.resourceManagerMember) as MemberResolveResult; + + #if DEBUG + if (mrr != null) { + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver: resolved constructor: "+mrr.ResolvedMember.ToString()); + } + #endif + + if (mrr != null && + mrr.ResolvedMember is IMethod && + (mrr.ResolvedMember.DeclaringType.CompareTo(this.resourceManagerMember.ReturnType.GetUnderlyingClass()) == 0 || + mrr.ResolvedMember.DeclaringType.IsTypeInInheritanceTree(this.resourceManagerMember.ReturnType.GetUnderlyingClass())) + ) { + + // This most probably is the resource manager initialization we are looking for. + // Find a parameter that indicates the resources being referenced. + + foreach (Expression param in objectCreateExpression.Parameters) { + + PrimitiveExpression p = param as PrimitiveExpression; + if (p != null) { + string pValue = p.Value as string; + if (pValue != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found string parameter: '"+pValue+"'"); + #endif + + string fileName = NRefactoryResourceResolver.GetResourceFileNameByResourceName(this.resourceManagerMember.DeclaringType.CompilationUnit.FileName, pValue); + if (fileName != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found resource file: "+fileName); + #endif + this.foundFileName = fileName; + break; + } + + } + + continue; + } + + // Support typeof(...) + TypeOfExpression t = param as TypeOfExpression; + if (t != null && this.PositionAvailable) { + TypeResolveResult trr = this.Resolve(new TypeReferenceExpression(t.TypeReference), this.resourceManagerMember) as TypeResolveResult; + if (trr != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found typeof(...) parameter, type: '"+trr.ResolvedType.ToString()+"'"); + #endif + + string fileName = NRefactoryResourceResolver.GetResourceFileNameByResourceName(this.resourceManagerMember.DeclaringType.CompilationUnit.FileName, trr.ResolvedType.FullyQualifiedName); + if (fileName != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found resource file: "+fileName); + #endif + this.foundFileName = fileName; + break; + } + + } + } + + } + + } + + } + + return base.TrackedVisit(objectCreateExpression, data); + } + + } + + #endregion + + // ******************************************************************************************************************************** + + /// + /// Tries to infer the resource key being referenced from the given expression. + /// + static string GetKeyFromExpression(Expression expr) + { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver trying to get key from expression: "+expr.ToString()); + #endif + + IndexerExpression indexer = expr as IndexerExpression; + if (indexer != null) { + foreach (Expression index in indexer.Indexes) { + PrimitiveExpression p = index as PrimitiveExpression; + if (p != null) { + string key = p.Value as string; + if (key != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found key: "+key); + #endif + return key; + } + } + } + } + + InvocationExpression invocation = expr as InvocationExpression; + if (invocation != null) { + FieldReferenceExpression fre = invocation.TargetObject as FieldReferenceExpression; + if (fre != null) { + if (fre.FieldName == "GetString" || fre.FieldName == "GetObject" || fre.FieldName == "GetStream") { + if (invocation.Arguments.Count > 0) { + PrimitiveExpression p = invocation.Arguments[0] as PrimitiveExpression; + if (p != null) { + string key = p.Value as string; + if (key != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: BclNRefactoryResourceResolver found key: "+key); + #endif + return key; + } + } + } + } + } + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public IEnumerable GetPossiblePatternsForFile(string fileName) + { + return new string[] { + "GetString", + "GetObject", + "GetStream", + (NRefactoryResourceResolver.GetLanguagePropertiesForFile(fileName) ?? LanguageProperties.None).IndexerExpressionStartToken + }; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public BclNRefactoryResourceResolver() + { + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs new file mode 100644 index 0000000000..d6bb2abc6b --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreNRefactoryResourceResolver.cs @@ -0,0 +1,154 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop.Dom; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Detects and resolves resource references when using the ICSharpCode.Core + /// ResourceService class. + /// + public class ICSharpCodeCoreNRefactoryResourceResolver : INRefactoryResourceResolver + { + + /// + /// Tries to find a resource reference in the specified expression. + /// + /// The ExpressionResult for the expression. + /// The AST representation of the expression. + /// SharpDevelop's ResolveResult for the expression. + /// The line where the expression is located. + /// The column where the expression is located. + /// The name of the source file where the expression is located. + /// The content of the source file where the expression is located. + /// A ResourceResolveResult describing the referenced resource, or null, if this expression does not reference a resource using the ICSharpCode.Core.ResourceService class. + public ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent) + { + IMember member = null; + + // "ResourceService.GetString(..." may be a MemberResolveResult or + // MethodResolveResult, dependent on how much of the expression + // has already been typed. + MemberResolveResult mrr = resolveResult as MemberResolveResult; + if (mrr != null) { + member = mrr.ResolvedMember; + } else { + MethodResolveResult methrr = resolveResult as MethodResolveResult; + if (methrr != null) { + member = methrr.GetMethodIfSingleOverload(); + } + } + + if (member is IMethod && + LanguageProperties.CSharp.NameComparer.Equals(member.FullyQualifiedName, "ICSharpCode.Core.ResourceService.GetString") + ) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreNRefactoryResourceResolver: ResourceService resource access detected"); + #endif + + string key = GetKeyFromExpression(expr); + string localResourceFileName = ICSharpCodeCoreResourceResolver.GetICSharpCodeCoreLocalResourceFileName(fileName); + string hostResourceFileName = ICSharpCodeCoreResourceResolver.GetICSharpCodeCoreHostResourceFileName(fileName); + IResourceFileContent content = null; + + // Merge the local and host resource file contents if available. + + if (!String.IsNullOrEmpty(localResourceFileName)) { + content = ResourceFileContentRegistry.GetResourceFileContent(localResourceFileName); + } + + if (!String.IsNullOrEmpty(hostResourceFileName)) { + if (content == null) { + content = ResourceFileContentRegistry.GetResourceFileContent(hostResourceFileName); + } else { + IResourceFileContent hostContent = ResourceFileContentRegistry.GetResourceFileContent(hostResourceFileName); + if (hostContent != null) { + content = new MergedResourceFileContent(content, new IResourceFileContent[] { hostContent }); + } + } + } + + if (content != null) { + // TODO: Add information about return type (of the resource, if present). + return new ResourceResolveResult(resolveResult.CallingClass, resolveResult.CallingMember, null, content, key); + } + + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Tries to infer the resource key being referenced from the given expression. + /// + static string GetKeyFromExpression(Expression expr) + { + #if DEBUG + LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreNRefactoryResourceResolver trying to get key from expression: "+expr.ToString()); + #endif + + InvocationExpression invocation = expr as InvocationExpression; + if (invocation != null) { + FieldReferenceExpression fre = invocation.TargetObject as FieldReferenceExpression; + if (fre != null) { + if (fre.FieldName == "GetString") { + if (invocation.Arguments.Count > 0) { + PrimitiveExpression p = invocation.Arguments[0] as PrimitiveExpression; + if (p != null) { + string key = p.Value as string; + if (key != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreNRefactoryResourceResolver found key: "+key); + #endif + return key; + } + } + } + } + } + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public IEnumerable GetPossiblePatternsForFile(string fileName) + { + return new string[] { + "GetString" + }; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public ICSharpCodeCoreNRefactoryResourceResolver() + { + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs new file mode 100644 index 0000000000..f356c99296 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ICSharpCodeCoreResourceResolver.cs @@ -0,0 +1,299 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.TextEditor.Document; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Resolves references to resources that are accessed using ICSharpCode.Core + /// ("${res:...}"). + /// + public class ICSharpCodeCoreResourceResolver : AbstractResourceResolver + { + + /// + /// Initializes a new instance of the class. + /// + public ICSharpCodeCoreResourceResolver() : base() + { + } + + // ******************************************************************************************************************************** + + /// + /// Determines whether this resolver supports resolving resources in the given file. + /// + /// The name of the file to examine. + /// true, if this resolver supports resolving resources in the given file, false otherwise. + public override bool SupportsFile(string fileName) + { + // Any parseable source code file may contain references + if (ICSharpCode.SharpDevelop.ParserService.GetParser(fileName) != null) { + return true; + } + + // Support additional files by extension + switch(Path.GetExtension(fileName).ToLowerInvariant()) { + case ".addin": + case ".xfrm": + case ".xml": + return true; + default: + break; + } + + return false; + } + + static readonly string[] possiblePatterns = new string[] { + "${res:" + }; + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public override IEnumerable GetPossiblePatternsForFile(string fileName) + { + if (this.SupportsFile(fileName)) { + return possiblePatterns; + } + return new string[0]; + } + + // ******************************************************************************************************************************** + + /// + /// The token that indicates a reference to an ICSharpCode.Core resource. + /// + public const string ResourceReferenceToken = @"${res:"; + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 0-based line in the file that contains the expression to be resolved. + /// The 0-based column position of the expression to be resolved. + /// The offset of the position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the specified position in the specified file, or null if that expression does not reference a (known) resource. + protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset) + { + // Find $ character to the left of the caret. + caretOffset += 1; + char ch; + do { + ch = document.GetCharAt(--caretOffset); + } while (!Char.IsWhiteSpace(ch) && ch != '$' && caretOffset > 0); + + if (caretOffset + 6 >= document.TextLength || document.GetText(caretOffset, 6) != ResourceReferenceToken) { + return null; + } + caretOffset += 6; + + // Read resource key. + StringBuilder key = new StringBuilder(); + while (caretOffset < document.TextLength && !Char.IsWhiteSpace(ch = document.GetCharAt(caretOffset++)) && ch != '}') { + key.Append(ch); + } + if (ch != '}') { + key = null; + #if DEBUG + } else { + LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreResourceResolver found resource key: "+key.ToString()); + #endif + } + + string resourceFile = ResolveICSharpCodeCoreResourceFileName(key == null ? null : key.ToString(), fileName); + + if (resourceFile != null) { + // TODO: Add information about callingClass, callingMember, returnType + return new ResourceResolveResult(null, null, null, ResourceFileContentRegistry.GetResourceFileContent(resourceFile), key == null ? null : key.ToString()); + } else { + LoggingService.Info("ResourceToolkit: ICSharpCodeCoreResourceResolver: Could not find the ICSharpCode.Core resource file name for the source file '"+fileName+"', key '"+(key == null ? "" : key.ToString())+"'."); + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Tries to find the name of the resource file which serves as source for + /// the resources accessed by the ICSharpCode.Core. + /// + /// The resource key to look for. May be null. + /// The name of the source code file that contains the reference to the resource. + static string ResolveICSharpCodeCoreResourceFileName(string key, string sourceFileName) + { + + // As there is no easy way to find out the actual location of the resources + // based on the source code, we just look in some standard directories. + + // Local file (SD addin or standalone application with standard directory structure) + string localFile = GetICSharpCodeCoreLocalResourceFileName(sourceFileName); + + // Prefer local file, especially if the key is there. + if (localFile != null) { + if (key != null) { + IResourceFileContent localContent = ResourceFileContentRegistry.GetResourceFileContent(localFile); + if (localContent != null) { + if (localContent.ContainsKey(key)) { + return localFile; + } + } + } else { + return localFile; + } + } + + // Resource file of the host application + string hostFile = GetICSharpCodeCoreHostResourceFileName(sourceFileName); + if (key != null) { + if (hostFile != null) { + IResourceFileContent hostContent = ResourceFileContentRegistry.GetResourceFileContent(hostFile); + if (hostContent != null) { + if (hostContent.ContainsKey(key)) { + return hostFile; + } + } + } + } + + // Use local file also if the key is not there + // (allows adding of a new key) + return localFile == null ? hostFile : localFile; + } + + /// + /// Tries to find an ICSharpCode.Core resource file in the given path + /// according to the file names defined in the AddIn tree. + /// + static string FindICSharpCodeCoreResourceFile(string path) + { + string file; + foreach (string fileName in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/ResourceFileNames", null, false)) { + if ((file = FindResourceFileName(Path.Combine(path, fileName))) != null) { + return file; + } + } + return null; + } + + /// + /// Tries to find the local string resource file used for ICSharpCode.Core resource access. + /// + /// The name of the source code file which to find the ICSharpCode.Core resource file for. + public static string GetICSharpCodeCoreLocalResourceFileName(string sourceFileName) + { + IProject project = ProjectFileDictionaryService.GetProjectForFile(sourceFileName); + if (project == null || String.IsNullOrEmpty(project.Directory)) { + return null; + } + + string localFile; + foreach (string relativePath in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/LocalResourcesLocations", null, false)) { + if ((localFile = FindICSharpCodeCoreResourceFile(Path.GetFullPath(Path.Combine(project.Directory, relativePath)))) != null) { + return localFile; + } + } + return null; + } + + /// + /// Tries to find the string resource file of the host application for ICSharpCode.Core resource access. + /// + /// The name of the source code file which to find the ICSharpCode.Core resource file for. + public static string GetICSharpCodeCoreHostResourceFileName(string sourceFileName) + { + IProject project = ProjectFileDictionaryService.GetProjectForFile(sourceFileName); + if (project == null || String.IsNullOrEmpty(project.Directory)) { + return null; + } + + // Get SD directory using the reference to ICSharpCode.Core + string coreAssemblyFullPath = GetICSharpCodeCoreFullPath(project); + + if (coreAssemblyFullPath == null) { + // Look for the ICSharpCode.Core project using all available projects. + if (ProjectService.OpenSolution != null) { + foreach (IProject p in ProjectService.OpenSolution.Projects) { + if ((coreAssemblyFullPath = GetICSharpCodeCoreFullPath(p)) != null) { + break; + } + } + } + } + + if (coreAssemblyFullPath != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: ICSharpCodeCoreResourceResolver coreAssemblyFullPath = "+coreAssemblyFullPath); + #endif + + string hostFile; + foreach (string relativePath in AddInTree.BuildItems("/AddIns/ResourceToolkit/ICSharpCodeCoreResourceResolver/HostResourcesLocations", null, false)) { + if ((hostFile = FindICSharpCodeCoreResourceFile(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(coreAssemblyFullPath), relativePath)))) != null) { + return hostFile; + } + } + + } + + return null; + } + + static string GetICSharpCodeCoreFullPath(IProject sourceProject) + { + string coreAssemblyFullPath = null; + + if (sourceProject.Name.Equals("ICSharpCode.Core", StringComparison.InvariantCultureIgnoreCase)) { + + // This is the ICSharpCode.Core project itself. + coreAssemblyFullPath = sourceProject.OutputAssemblyFullPath; + + } else { + + // Get the ICSharpCode.Core.dll path by using the project reference. + foreach (ProjectItem item in sourceProject.Items) { + ProjectReferenceProjectItem prpi = item as ProjectReferenceProjectItem; + if (prpi != null) { + if (prpi.ReferencedProject != null) { + if (prpi.ReferencedProject.Name.Equals("ICSharpCode.Core", StringComparison.InvariantCultureIgnoreCase) && prpi.ReferencedProject.OutputAssemblyFullPath != null) { + coreAssemblyFullPath = prpi.ReferencedProject.OutputAssemblyFullPath; + break; + } + } + } + ReferenceProjectItem rpi = item as ReferenceProjectItem; + if (rpi != null) { + if (rpi.Name.Equals("ICSharpCode.Core", StringComparison.InvariantCultureIgnoreCase) && rpi.FileName != null) { + coreAssemblyFullPath = rpi.FileName; + break; + } + } + } + + } + + return coreAssemblyFullPath; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs new file mode 100644 index 0000000000..986999e35a --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/INRefactoryResourceResolver.cs @@ -0,0 +1,44 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop.Dom; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Detects and resolves resource references using SharpDevelop.Dom and + /// NRefactory. At this stage the parser and resolver have already been + /// called. + /// + public interface INRefactoryResourceResolver + { + /// + /// Tries to find a resource reference in the specified expression. + /// + /// The ExpressionResult for the expression. + /// The AST representation of the expression. + /// SharpDevelop's ResolveResult for the expression. + /// The line where the expression is located. + /// The column where the expression is located. + /// The name of the source file where the expression is located. + /// The content of the source file where the expression is located. + /// A ResourceResolveResult describing the referenced resource, or null, if this expression does not reference a resource in a known way. + ResourceResolveResult Resolve(ExpressionResult expressionResult, Expression expr, ResolveResult resolveResult, int caretLine, int caretColumn, string fileName, string fileContent); + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + IEnumerable GetPossiblePatternsForFile(string fileName); + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs new file mode 100644 index 0000000000..a5b922525d --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/IResourceResolver.cs @@ -0,0 +1,56 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Describes an object that is able to find out if an expression + /// references a resource and if so, in which file and which key. + /// + public interface IResourceResolver + { + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 1-based line in the file that contains the expression to be resolved. + /// The 1-based column position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the specified position in the specified file, or null if that expression does not reference a (known) resource. + ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn); + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The text editor for which a resource resolution attempt should be performed. + /// A that describes which resource is referenced by the expression at the caret in the specified editor, or null if that expression does not reference a (known) resource. + ResourceResolveResult Resolve(TextEditorControl editor); + + /// + /// Determines whether this resolver supports resolving resources in the given file. + /// + /// The name of the file to examine. + /// true, if this resolver supports resolving resources in the given file, false otherwise. + bool SupportsFile(string fileName); + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + IEnumerable GetPossiblePatternsForFile(string fileName); + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs new file mode 100644 index 0000000000..188e66a02b --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryAstCacheService.cs @@ -0,0 +1,94 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.SharpDevelop; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Parses files using NRefactory and caches the AST on demand. + /// + public static class NRefactoryAstCacheService + { + static bool cacheEnabled = false; + static Dictionary cachedAstInfo = new Dictionary(); + + /// + /// Gets a flag that indicates whether the AST cache is currently enabled. + /// + public static bool CacheEnabled { + get { + return cacheEnabled; + } + } + + /// + /// Enables the AST cache. + /// + /// The AST cache is already enabled. + public static void EnableCache() + { + if (CacheEnabled) { + throw new InvalidOperationException("The AST cache is already enabled."); + } + cacheEnabled = true; + LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService cache enabled"); + } + + /// + /// Disables the AST cache. + /// + public static void DisableCache() + { + cacheEnabled = false; + cachedAstInfo.Clear(); + LoggingService.Info("ResourceToolkit: NRefactoryAstCacheService cache disabled and cleared"); + } + + /// + /// Gets the complete NRefactory AST for the specified file. + /// + /// The language of the file. + /// The file to get the AST for. + /// A that contains the AST for the specified file, or null if the file cannot be parsed. + /// Between calls to and the file is parsed only once. On subsequent accesses the AST is retrieved from the cache. + public static CompilationUnit GetFullAst(SupportedLanguage language, string fileName) + { + CompilationUnit cu; + if (!CacheEnabled || !cachedAstInfo.TryGetValue(fileName, out cu)) { + cu = Parse(language, fileName); + if (cu != null && CacheEnabled) { + cachedAstInfo.Add(fileName, cu); + } + } + return cu; + } + + static CompilationUnit Parse(SupportedLanguage language, string fileName) + { + using(ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser(language, new StringReader(ParserService.GetParseableFileContent(fileName)))) { + if (parser != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryAstCacheService: Parsing file '"+fileName+"'"); + #endif + parser.ParseMethodBodies = true; + parser.Parse(); + return parser.CompilationUnit; + } + } + return null; + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs new file mode 100644 index 0000000000..161fb2e3b2 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NRefactoryResourceResolver.cs @@ -0,0 +1,390 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Parser; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.Project; +using ICSharpCode.TextEditor.Document; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Resolves resource references using NRefactory. + /// + public class NRefactoryResourceResolver : AbstractResourceResolver + { + + /// + /// The AddIn tree path where the NRefactory resource resolvers are registered. + /// + public const string NRefactoryResourceResolversAddInTreePath = "/AddIns/ResourceToolkit/NRefactoryResourceResolver/Resolvers"; + + // ******************************************************************************************************************************** + + static List resolvers; + + /// + /// Gets a list of all registered NRefactory resource resolvers. + /// + public static IEnumerable Resolvers { + get { + if (resolvers == null) { + resolvers = AddInTree.BuildItems(NRefactoryResourceResolversAddInTreePath, null, false); + } + return resolvers; + } + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public NRefactoryResourceResolver() : base() + { + } + + // ******************************************************************************************************************************** + + /// + /// Determines whether this resolver supports resolving resources in the given file. + /// + /// The name of the file to examine. + /// true, if this resolver supports resolving resources in the given file, false otherwise. + public override bool SupportsFile(string fileName) + { + // Any source code file supported by NRefactory is supported + return (GetFileLanguage(fileName) != null); + } + + /// + /// Gets a list of patterns that can be searched for in the specified file + /// to find possible resource references that are supported by this + /// resolver. + /// + /// The name of the file to get a list of possible patterns for. + public override IEnumerable GetPossiblePatternsForFile(string fileName) + { + if (this.SupportsFile(fileName)) { + List patterns = new List(); + foreach (INRefactoryResourceResolver resolver in Resolvers) { + foreach (string pattern in resolver.GetPossiblePatternsForFile(fileName)) { + if (!patterns.Contains(pattern)) { + patterns.Add(pattern); + } + } + } + return patterns; + } + return new string[0]; + } + + // ******************************************************************************************************************************** + + /// + /// Attempts to resolve a reference to a resource. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 0-based line in the file that contains the expression to be resolved. + /// The 0-based column position of the expression to be resolved. + /// The offset of the position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the specified position in the specified file, or null if that expression does not reference a (known) resource. + protected override ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn, int caretOffset) + { + IExpressionFinder ef = ParserService.GetExpressionFinder(fileName); + if (ef == null) { + return null; + } + + ExpressionResult result = ef.FindFullExpression(document.TextContent, caretOffset); + + if (result.Expression == null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver could not find expression on first try"); + #endif + // may happen if in string + while (--caretOffset > 0 && (result = ef.FindFullExpression(document.TextContent, caretOffset)).Expression == null) { + if (document.GetLineNumberForOffset(caretOffset) != caretLine) { + // only look in same line + break; + } + } + } + + if (result.Expression != null) { + + ResourceResolveResult rrr = null; + + // The full expression is parsed here because + // we will need to modify the result in the next step. + Expression expr = null; + SupportedLanguage? language = GetFileLanguage(fileName); + if (language != null) { + using(ICSharpCode.NRefactory.IParser parser = ParserFactory.CreateParser(language.Value, new StringReader(result.Expression))) { + if (parser != null) { + expr = parser.ParseExpression(); + } + } + } + + // The resolve routine needs the member which contains the actual member being referenced. + // If a complete expression is given, the expression needs to be reduced to + // the member reference. + while (result.Expression != null && result.Expression.Length > 0) { + if ((rrr = TryResolve(result, expr, caretLine, caretColumn, fileName, document.TextContent)) != null) { + break; + } + result.Expression = ef.RemoveLastPart(result.Expression); + } + + return rrr; + + } else { + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver could not find an expression"); + #endif + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Tries to resolve the resource reference using all available + /// NRefactory resource resolvers. + /// + static ResourceResolveResult TryResolve(ExpressionResult result, Expression expr, int caretLine, int caretColumn, string fileName, string fileContent) + { + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver trying to resolve expression: "+result.ToString()); + #endif + + ResolveResult rr = ParserService.Resolve(result, caretLine, caretColumn, fileName, fileContent); + if (rr != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver: The expression resolved to: "+rr.ToString()); + #endif + + ResourceResolveResult rrr; + foreach (INRefactoryResourceResolver resolver in Resolvers) { + if ((rrr = resolver.Resolve(result, expr, rr, caretLine, caretColumn, fileName, fileContent)) != null) { + return rrr; + } + } + + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Determines the file which contains the resources referenced by the specified manifest resource name. + /// + /// The name of the source code file which the reference occurs in. + /// The manifest resource name to find the resource file for. + /// The name of the file that contains the resources with the specified manifest resource name, or null if the file name cannot be determined. + /// The parameter is null. + public static string GetResourceFileNameByResourceName(string sourceFileName, string resourceName) + { + if (resourceName == null) { + throw new ArgumentNullException("resourceName"); + } + + IProject p = ProjectFileDictionaryService.GetProjectForFile(sourceFileName); + + if (p != null) { + + string fileName = null; + + if (resourceName.StartsWith(p.RootNamespace, StringComparison.InvariantCultureIgnoreCase)) { + + // Look for a resource file in the project with the exact name. + if ((fileName = FindResourceFileName(Path.Combine(p.Directory, resourceName.Substring(p.RootNamespace.Length+1).Replace('.', Path.DirectorySeparatorChar)))) != null) { + return fileName; + } + + } + + // SharpDevelop silently strips the (hard-coded) folder names + // "src" and "source" when generating the default namespace name + // for new files. + // When MSBuild generates the manifest resource names for the + // forms designer resources, it uses the type name of the + // first class in the file. So we should find all files + // that contain a type with the name in resourceName + // and then look for dependent resource files or resource files + // with the same name in the same directory as the source files. + + // Find all source files that contain a type with the same + // name as the resource we are looking for. + List possibleSourceFiles = new List(); + IProjectContent pc = ParserService.GetProjectContent(p); + if (pc != null) { + + IClass resourceClass = pc.GetClass(resourceName); + + if (resourceClass != null) { + CompoundClass cc = resourceClass.GetCompoundClass() as CompoundClass; + + foreach (IClass c in (cc == null ? new IClass[] { resourceClass } : (IEnumerable)cc.Parts)) { + if (c.CompilationUnit != null && c.CompilationUnit.FileName != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver found file '"+c.CompilationUnit.FileName+"' to contain the type '"+resourceName+"'"); + #endif + + possibleSourceFiles.Add(c.CompilationUnit.FileName); + + } + } + + } + + } + + foreach (string possibleSourceFile in possibleSourceFiles) { + string possibleSourceFileName = Path.GetFileName(possibleSourceFile); + + // Find resource files dependent on these source files. + foreach (ProjectItem pi in p.Items) { + FileProjectItem fpi = pi as FileProjectItem; + if (fpi != null) { + if (fpi.DependentUpon != null && + (fpi.ItemType == ItemType.EmbeddedResource || fpi.ItemType == ItemType.Resource || fpi.ItemType == ItemType.None) && + FileUtility.IsEqualFileName(fpi.DependentUpon, possibleSourceFileName)) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver trying to use dependent file '"+fpi.FileName+"' as resource file"); + #endif + + if ((fileName = FindResourceFileName(fpi.FileName)) != null) { + return fileName; + } + + } + } + } + + // Find resource files with the same name as the source file + // and in the same directory. + if ((fileName = FindResourceFileName(possibleSourceFile)) != null) { + return fileName; + } + + } + + } else { + + LoggingService.Info("ResourceToolkit: NRefactoryResourceResolver.GetResourceFileNameByResourceName could not determine the project for the source file '"+(sourceFileName ?? "")+"'."); + + if (sourceFileName != null) { + + // The project could not be determined. + // Try a simple file search. + + string directory = Path.GetDirectoryName(sourceFileName); + string resourcePart = resourceName; + string fileName; + + while (true) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: NRefactoryResourceResolver.GetResourceFileNameByResourceName: looking for a resource file like '"+Path.Combine(directory, resourcePart)+"'"); + #endif + + if ((fileName = FindResourceFileName(Path.Combine(directory, resourcePart.Replace('.', Path.DirectorySeparatorChar)))) != null) { + return fileName; + } + if ((fileName = FindResourceFileName(Path.Combine(directory, resourcePart))) != null) { + return fileName; + } + + if (resourcePart.Contains(".")) { + resourcePart = resourcePart.Substring(resourcePart.IndexOf('.')+1); + } else { + break; + } + + } + + } + + } + + LoggingService.Info("ResourceToolkit: NRefactoryResourceResolver.GetResourceFileNameByResourceName is unable to find a suitable resource file for '"+resourceName+"'"); + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Gets the NRefactory language for the specified file name. + /// + public static SupportedLanguage? GetFileLanguage(string fileName) + { + string ext = Path.GetExtension(fileName); + if (ext.Equals(".cs", StringComparison.InvariantCultureIgnoreCase)) + return SupportedLanguage.CSharp; + if (ext.Equals(".vb", StringComparison.InvariantCultureIgnoreCase)) + return SupportedLanguage.VBNet; + return null; + } + + /// + /// Gets the language properties for the project the specified member + /// belongs to. + /// Returns null if the language cannot be determined. + /// + public static LanguageProperties GetLanguagePropertiesForMember(IMember member) + { + if (member == null) { + return null; + } + if (member.DeclaringType == null) { + return null; + } + if (member.DeclaringType.CompilationUnit == null) { + return null; + } + if (member.DeclaringType.CompilationUnit.ProjectContent == null) { + return null; + } + return member.DeclaringType.CompilationUnit.ProjectContent.Language; + } + + /// + /// Gets the language properties for the specified file. + /// + /// The file to get the language properties for. + /// The language properties of the specified file, or null if the language cannot be determined. + public static LanguageProperties GetLanguagePropertiesForFile(string fileName) + { + ICSharpCode.SharpDevelop.Dom.IParser p = ParserService.GetParser(fileName); + if (p == null) { + return null; + } + return p.Language; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NodeTrackingAstVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NodeTrackingAstVisitor.cs new file mode 100644 index 0000000000..3e3443b1a5 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/NodeTrackingAstVisitor.cs @@ -0,0 +1,1144 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.42 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Hornung.ResourceToolkit.Resolver { + using System; + using ICSharpCode.NRefactory.Ast; + + + /// + /// The NodeTrackingAstVisitor will iterate through the whole AST, + /// just like the AbstractAstVisitor, and calls the virtual methods + /// BeginVisit and EndVisit for each node being visited. + /// + /// + /// To enable the tracking functionality, you must override + /// the TrackedVisit methods instead of the Visit methods! + /// + public abstract class NodeTrackingAstVisitor : ICSharpCode.NRefactory.Visitors.AbstractAstVisitor { + + protected virtual void BeginVisit(INode node) { + } + + protected virtual void EndVisit(INode node) { + } + + public override object VisitAddHandlerStatement(AddHandlerStatement addHandlerStatement, object data) { + this.BeginVisit(addHandlerStatement); + object result = this.TrackedVisit(addHandlerStatement, data); + this.EndVisit(addHandlerStatement); + return result; + } + + public override object VisitAddressOfExpression(AddressOfExpression addressOfExpression, object data) { + this.BeginVisit(addressOfExpression); + object result = this.TrackedVisit(addressOfExpression, data); + this.EndVisit(addressOfExpression); + return result; + } + + public override object VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data) { + this.BeginVisit(anonymousMethodExpression); + object result = this.TrackedVisit(anonymousMethodExpression, data); + this.EndVisit(anonymousMethodExpression); + return result; + } + + public override object VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression, object data) { + this.BeginVisit(arrayCreateExpression); + object result = this.TrackedVisit(arrayCreateExpression, data); + this.EndVisit(arrayCreateExpression); + return result; + } + + public override object VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression, object data) { + this.BeginVisit(arrayInitializerExpression); + object result = this.TrackedVisit(arrayInitializerExpression, data); + this.EndVisit(arrayInitializerExpression); + return result; + } + + public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) { + this.BeginVisit(assignmentExpression); + object result = this.TrackedVisit(assignmentExpression, data); + this.EndVisit(assignmentExpression); + return result; + } + + public override object VisitAttribute(ICSharpCode.NRefactory.Ast.Attribute attribute, object data) { + this.BeginVisit(attribute); + object result = this.TrackedVisit(attribute, data); + this.EndVisit(attribute); + return result; + } + + public override object VisitAttributeSection(AttributeSection attributeSection, object data) { + this.BeginVisit(attributeSection); + object result = this.TrackedVisit(attributeSection, data); + this.EndVisit(attributeSection); + return result; + } + + public override object VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression, object data) { + this.BeginVisit(baseReferenceExpression); + object result = this.TrackedVisit(baseReferenceExpression, data); + this.EndVisit(baseReferenceExpression); + return result; + } + + public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) { + this.BeginVisit(binaryOperatorExpression); + object result = this.TrackedVisit(binaryOperatorExpression, data); + this.EndVisit(binaryOperatorExpression); + return result; + } + + public override object VisitBlockStatement(BlockStatement blockStatement, object data) { + this.BeginVisit(blockStatement); + object result = this.TrackedVisit(blockStatement, data); + this.EndVisit(blockStatement); + return result; + } + + public override object VisitBreakStatement(BreakStatement breakStatement, object data) { + this.BeginVisit(breakStatement); + object result = this.TrackedVisit(breakStatement, data); + this.EndVisit(breakStatement); + return result; + } + + public override object VisitCaseLabel(CaseLabel caseLabel, object data) { + this.BeginVisit(caseLabel); + object result = this.TrackedVisit(caseLabel, data); + this.EndVisit(caseLabel); + return result; + } + + public override object VisitCastExpression(CastExpression castExpression, object data) { + this.BeginVisit(castExpression); + object result = this.TrackedVisit(castExpression, data); + this.EndVisit(castExpression); + return result; + } + + public override object VisitCatchClause(CatchClause catchClause, object data) { + this.BeginVisit(catchClause); + object result = this.TrackedVisit(catchClause, data); + this.EndVisit(catchClause); + return result; + } + + public override object VisitCheckedExpression(CheckedExpression checkedExpression, object data) { + this.BeginVisit(checkedExpression); + object result = this.TrackedVisit(checkedExpression, data); + this.EndVisit(checkedExpression); + return result; + } + + public override object VisitCheckedStatement(CheckedStatement checkedStatement, object data) { + this.BeginVisit(checkedStatement); + object result = this.TrackedVisit(checkedStatement, data); + this.EndVisit(checkedStatement); + return result; + } + + public override object VisitClassReferenceExpression(ClassReferenceExpression classReferenceExpression, object data) { + this.BeginVisit(classReferenceExpression); + object result = this.TrackedVisit(classReferenceExpression, data); + this.EndVisit(classReferenceExpression); + return result; + } + + public override object VisitCompilationUnit(CompilationUnit compilationUnit, object data) { + this.BeginVisit(compilationUnit); + object result = this.TrackedVisit(compilationUnit, data); + this.EndVisit(compilationUnit); + return result; + } + + public override object VisitConditionalExpression(ConditionalExpression conditionalExpression, object data) { + this.BeginVisit(conditionalExpression); + object result = this.TrackedVisit(conditionalExpression, data); + this.EndVisit(conditionalExpression); + return result; + } + + public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) { + this.BeginVisit(constructorDeclaration); + object result = this.TrackedVisit(constructorDeclaration, data); + this.EndVisit(constructorDeclaration); + return result; + } + + public override object VisitConstructorInitializer(ConstructorInitializer constructorInitializer, object data) { + this.BeginVisit(constructorInitializer); + object result = this.TrackedVisit(constructorInitializer, data); + this.EndVisit(constructorInitializer); + return result; + } + + public override object VisitContinueStatement(ContinueStatement continueStatement, object data) { + this.BeginVisit(continueStatement); + object result = this.TrackedVisit(continueStatement, data); + this.EndVisit(continueStatement); + return result; + } + + public override object VisitDeclareDeclaration(DeclareDeclaration declareDeclaration, object data) { + this.BeginVisit(declareDeclaration); + object result = this.TrackedVisit(declareDeclaration, data); + this.EndVisit(declareDeclaration); + return result; + } + + public override object VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression, object data) { + this.BeginVisit(defaultValueExpression); + object result = this.TrackedVisit(defaultValueExpression, data); + this.EndVisit(defaultValueExpression); + return result; + } + + public override object VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data) { + this.BeginVisit(delegateDeclaration); + object result = this.TrackedVisit(delegateDeclaration, data); + this.EndVisit(delegateDeclaration); + return result; + } + + public override object VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data) { + this.BeginVisit(destructorDeclaration); + object result = this.TrackedVisit(destructorDeclaration, data); + this.EndVisit(destructorDeclaration); + return result; + } + + public override object VisitDirectionExpression(DirectionExpression directionExpression, object data) { + this.BeginVisit(directionExpression); + object result = this.TrackedVisit(directionExpression, data); + this.EndVisit(directionExpression); + return result; + } + + public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) { + this.BeginVisit(doLoopStatement); + object result = this.TrackedVisit(doLoopStatement, data); + this.EndVisit(doLoopStatement); + return result; + } + + public override object VisitElseIfSection(ElseIfSection elseIfSection, object data) { + this.BeginVisit(elseIfSection); + object result = this.TrackedVisit(elseIfSection, data); + this.EndVisit(elseIfSection); + return result; + } + + public override object VisitEmptyStatement(EmptyStatement emptyStatement, object data) { + this.BeginVisit(emptyStatement); + object result = this.TrackedVisit(emptyStatement, data); + this.EndVisit(emptyStatement); + return result; + } + + public override object VisitEndStatement(EndStatement endStatement, object data) { + this.BeginVisit(endStatement); + object result = this.TrackedVisit(endStatement, data); + this.EndVisit(endStatement); + return result; + } + + public override object VisitEraseStatement(EraseStatement eraseStatement, object data) { + this.BeginVisit(eraseStatement); + object result = this.TrackedVisit(eraseStatement, data); + this.EndVisit(eraseStatement); + return result; + } + + public override object VisitErrorStatement(ErrorStatement errorStatement, object data) { + this.BeginVisit(errorStatement); + object result = this.TrackedVisit(errorStatement, data); + this.EndVisit(errorStatement); + return result; + } + + public override object VisitEventAddRegion(EventAddRegion eventAddRegion, object data) { + this.BeginVisit(eventAddRegion); + object result = this.TrackedVisit(eventAddRegion, data); + this.EndVisit(eventAddRegion); + return result; + } + + public override object VisitEventDeclaration(EventDeclaration eventDeclaration, object data) { + this.BeginVisit(eventDeclaration); + object result = this.TrackedVisit(eventDeclaration, data); + this.EndVisit(eventDeclaration); + return result; + } + + public override object VisitEventRaiseRegion(EventRaiseRegion eventRaiseRegion, object data) { + this.BeginVisit(eventRaiseRegion); + object result = this.TrackedVisit(eventRaiseRegion, data); + this.EndVisit(eventRaiseRegion); + return result; + } + + public override object VisitEventRemoveRegion(EventRemoveRegion eventRemoveRegion, object data) { + this.BeginVisit(eventRemoveRegion); + object result = this.TrackedVisit(eventRemoveRegion, data); + this.EndVisit(eventRemoveRegion); + return result; + } + + public override object VisitExitStatement(ExitStatement exitStatement, object data) { + this.BeginVisit(exitStatement); + object result = this.TrackedVisit(exitStatement, data); + this.EndVisit(exitStatement); + return result; + } + + public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) { + this.BeginVisit(expressionStatement); + object result = this.TrackedVisit(expressionStatement, data); + this.EndVisit(expressionStatement); + return result; + } + + public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) { + this.BeginVisit(fieldDeclaration); + object result = this.TrackedVisit(fieldDeclaration, data); + this.EndVisit(fieldDeclaration); + return result; + } + + public override object VisitFieldReferenceExpression(FieldReferenceExpression fieldReferenceExpression, object data) { + this.BeginVisit(fieldReferenceExpression); + object result = this.TrackedVisit(fieldReferenceExpression, data); + this.EndVisit(fieldReferenceExpression); + return result; + } + + public override object VisitFixedStatement(FixedStatement fixedStatement, object data) { + this.BeginVisit(fixedStatement); + object result = this.TrackedVisit(fixedStatement, data); + this.EndVisit(fixedStatement); + return result; + } + + public override object VisitForeachStatement(ForeachStatement foreachStatement, object data) { + this.BeginVisit(foreachStatement); + object result = this.TrackedVisit(foreachStatement, data); + this.EndVisit(foreachStatement); + return result; + } + + public override object VisitForNextStatement(ForNextStatement forNextStatement, object data) { + this.BeginVisit(forNextStatement); + object result = this.TrackedVisit(forNextStatement, data); + this.EndVisit(forNextStatement); + return result; + } + + public override object VisitForStatement(ForStatement forStatement, object data) { + this.BeginVisit(forStatement); + object result = this.TrackedVisit(forStatement, data); + this.EndVisit(forStatement); + return result; + } + + public override object VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement, object data) { + this.BeginVisit(gotoCaseStatement); + object result = this.TrackedVisit(gotoCaseStatement, data); + this.EndVisit(gotoCaseStatement); + return result; + } + + public override object VisitGotoStatement(GotoStatement gotoStatement, object data) { + this.BeginVisit(gotoStatement); + object result = this.TrackedVisit(gotoStatement, data); + this.EndVisit(gotoStatement); + return result; + } + + public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data) { + this.BeginVisit(identifierExpression); + object result = this.TrackedVisit(identifierExpression, data); + this.EndVisit(identifierExpression); + return result; + } + + public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) { + this.BeginVisit(ifElseStatement); + object result = this.TrackedVisit(ifElseStatement, data); + this.EndVisit(ifElseStatement); + return result; + } + + public override object VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data) { + this.BeginVisit(indexerDeclaration); + object result = this.TrackedVisit(indexerDeclaration, data); + this.EndVisit(indexerDeclaration); + return result; + } + + public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data) { + this.BeginVisit(indexerExpression); + object result = this.TrackedVisit(indexerExpression, data); + this.EndVisit(indexerExpression); + return result; + } + + public override object VisitInnerClassTypeReference(InnerClassTypeReference innerClassTypeReference, object data) { + this.BeginVisit(innerClassTypeReference); + object result = this.TrackedVisit(innerClassTypeReference, data); + this.EndVisit(innerClassTypeReference); + return result; + } + + public override object VisitInterfaceImplementation(InterfaceImplementation interfaceImplementation, object data) { + this.BeginVisit(interfaceImplementation); + object result = this.TrackedVisit(interfaceImplementation, data); + this.EndVisit(interfaceImplementation); + return result; + } + + public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) { + this.BeginVisit(invocationExpression); + object result = this.TrackedVisit(invocationExpression, data); + this.EndVisit(invocationExpression); + return result; + } + + public override object VisitLabelStatement(LabelStatement labelStatement, object data) { + this.BeginVisit(labelStatement); + object result = this.TrackedVisit(labelStatement, data); + this.EndVisit(labelStatement); + return result; + } + + public override object VisitLocalVariableDeclaration(LocalVariableDeclaration localVariableDeclaration, object data) { + this.BeginVisit(localVariableDeclaration); + object result = this.TrackedVisit(localVariableDeclaration, data); + this.EndVisit(localVariableDeclaration); + return result; + } + + public override object VisitLockStatement(LockStatement lockStatement, object data) { + this.BeginVisit(lockStatement); + object result = this.TrackedVisit(lockStatement, data); + this.EndVisit(lockStatement); + return result; + } + + public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) { + this.BeginVisit(methodDeclaration); + object result = this.TrackedVisit(methodDeclaration, data); + this.EndVisit(methodDeclaration); + return result; + } + + public override object VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression, object data) { + this.BeginVisit(namedArgumentExpression); + object result = this.TrackedVisit(namedArgumentExpression, data); + this.EndVisit(namedArgumentExpression); + return result; + } + + public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) { + this.BeginVisit(namespaceDeclaration); + object result = this.TrackedVisit(namespaceDeclaration, data); + this.EndVisit(namespaceDeclaration); + return result; + } + + public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) { + this.BeginVisit(objectCreateExpression); + object result = this.TrackedVisit(objectCreateExpression, data); + this.EndVisit(objectCreateExpression); + return result; + } + + public override object VisitOnErrorStatement(OnErrorStatement onErrorStatement, object data) { + this.BeginVisit(onErrorStatement); + object result = this.TrackedVisit(onErrorStatement, data); + this.EndVisit(onErrorStatement); + return result; + } + + public override object VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) { + this.BeginVisit(operatorDeclaration); + object result = this.TrackedVisit(operatorDeclaration, data); + this.EndVisit(operatorDeclaration); + return result; + } + + public override object VisitOptionDeclaration(OptionDeclaration optionDeclaration, object data) { + this.BeginVisit(optionDeclaration); + object result = this.TrackedVisit(optionDeclaration, data); + this.EndVisit(optionDeclaration); + return result; + } + + public override object VisitParameterDeclarationExpression(ParameterDeclarationExpression parameterDeclarationExpression, object data) { + this.BeginVisit(parameterDeclarationExpression); + object result = this.TrackedVisit(parameterDeclarationExpression, data); + this.EndVisit(parameterDeclarationExpression); + return result; + } + + public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) { + this.BeginVisit(parenthesizedExpression); + object result = this.TrackedVisit(parenthesizedExpression, data); + this.EndVisit(parenthesizedExpression); + return result; + } + + public override object VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data) { + this.BeginVisit(pointerReferenceExpression); + object result = this.TrackedVisit(pointerReferenceExpression, data); + this.EndVisit(pointerReferenceExpression); + return result; + } + + public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { + this.BeginVisit(primitiveExpression); + object result = this.TrackedVisit(primitiveExpression, data); + this.EndVisit(primitiveExpression); + return result; + } + + public override object VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) { + this.BeginVisit(propertyDeclaration); + object result = this.TrackedVisit(propertyDeclaration, data); + this.EndVisit(propertyDeclaration); + return result; + } + + public override object VisitPropertyGetRegion(PropertyGetRegion propertyGetRegion, object data) { + this.BeginVisit(propertyGetRegion); + object result = this.TrackedVisit(propertyGetRegion, data); + this.EndVisit(propertyGetRegion); + return result; + } + + public override object VisitPropertySetRegion(PropertySetRegion propertySetRegion, object data) { + this.BeginVisit(propertySetRegion); + object result = this.TrackedVisit(propertySetRegion, data); + this.EndVisit(propertySetRegion); + return result; + } + + public override object VisitRaiseEventStatement(RaiseEventStatement raiseEventStatement, object data) { + this.BeginVisit(raiseEventStatement); + object result = this.TrackedVisit(raiseEventStatement, data); + this.EndVisit(raiseEventStatement); + return result; + } + + public override object VisitReDimStatement(ReDimStatement reDimStatement, object data) { + this.BeginVisit(reDimStatement); + object result = this.TrackedVisit(reDimStatement, data); + this.EndVisit(reDimStatement); + return result; + } + + public override object VisitRemoveHandlerStatement(RemoveHandlerStatement removeHandlerStatement, object data) { + this.BeginVisit(removeHandlerStatement); + object result = this.TrackedVisit(removeHandlerStatement, data); + this.EndVisit(removeHandlerStatement); + return result; + } + + public override object VisitResumeStatement(ResumeStatement resumeStatement, object data) { + this.BeginVisit(resumeStatement); + object result = this.TrackedVisit(resumeStatement, data); + this.EndVisit(resumeStatement); + return result; + } + + public override object VisitReturnStatement(ReturnStatement returnStatement, object data) { + this.BeginVisit(returnStatement); + object result = this.TrackedVisit(returnStatement, data); + this.EndVisit(returnStatement); + return result; + } + + public override object VisitSizeOfExpression(SizeOfExpression sizeOfExpression, object data) { + this.BeginVisit(sizeOfExpression); + object result = this.TrackedVisit(sizeOfExpression, data); + this.EndVisit(sizeOfExpression); + return result; + } + + public override object VisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data) { + this.BeginVisit(stackAllocExpression); + object result = this.TrackedVisit(stackAllocExpression, data); + this.EndVisit(stackAllocExpression); + return result; + } + + public override object VisitStopStatement(StopStatement stopStatement, object data) { + this.BeginVisit(stopStatement); + object result = this.TrackedVisit(stopStatement, data); + this.EndVisit(stopStatement); + return result; + } + + public override object VisitSwitchSection(SwitchSection switchSection, object data) { + this.BeginVisit(switchSection); + object result = this.TrackedVisit(switchSection, data); + this.EndVisit(switchSection); + return result; + } + + public override object VisitSwitchStatement(SwitchStatement switchStatement, object data) { + this.BeginVisit(switchStatement); + object result = this.TrackedVisit(switchStatement, data); + this.EndVisit(switchStatement); + return result; + } + + public override object VisitTemplateDefinition(TemplateDefinition templateDefinition, object data) { + this.BeginVisit(templateDefinition); + object result = this.TrackedVisit(templateDefinition, data); + this.EndVisit(templateDefinition); + return result; + } + + public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data) { + this.BeginVisit(thisReferenceExpression); + object result = this.TrackedVisit(thisReferenceExpression, data); + this.EndVisit(thisReferenceExpression); + return result; + } + + public override object VisitThrowStatement(ThrowStatement throwStatement, object data) { + this.BeginVisit(throwStatement); + object result = this.TrackedVisit(throwStatement, data); + this.EndVisit(throwStatement); + return result; + } + + public override object VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data) { + this.BeginVisit(tryCatchStatement); + object result = this.TrackedVisit(tryCatchStatement, data); + this.EndVisit(tryCatchStatement); + return result; + } + + public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) { + this.BeginVisit(typeDeclaration); + object result = this.TrackedVisit(typeDeclaration, data); + this.EndVisit(typeDeclaration); + return result; + } + + public override object VisitTypeOfExpression(TypeOfExpression typeOfExpression, object data) { + this.BeginVisit(typeOfExpression); + object result = this.TrackedVisit(typeOfExpression, data); + this.EndVisit(typeOfExpression); + return result; + } + + public override object VisitTypeOfIsExpression(TypeOfIsExpression typeOfIsExpression, object data) { + this.BeginVisit(typeOfIsExpression); + object result = this.TrackedVisit(typeOfIsExpression, data); + this.EndVisit(typeOfIsExpression); + return result; + } + + public override object VisitTypeReference(TypeReference typeReference, object data) { + this.BeginVisit(typeReference); + object result = this.TrackedVisit(typeReference, data); + this.EndVisit(typeReference); + return result; + } + + public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data) { + this.BeginVisit(typeReferenceExpression); + object result = this.TrackedVisit(typeReferenceExpression, data); + this.EndVisit(typeReferenceExpression); + return result; + } + + public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) { + this.BeginVisit(unaryOperatorExpression); + object result = this.TrackedVisit(unaryOperatorExpression, data); + this.EndVisit(unaryOperatorExpression); + return result; + } + + public override object VisitUncheckedExpression(UncheckedExpression uncheckedExpression, object data) { + this.BeginVisit(uncheckedExpression); + object result = this.TrackedVisit(uncheckedExpression, data); + this.EndVisit(uncheckedExpression); + return result; + } + + public override object VisitUncheckedStatement(UncheckedStatement uncheckedStatement, object data) { + this.BeginVisit(uncheckedStatement); + object result = this.TrackedVisit(uncheckedStatement, data); + this.EndVisit(uncheckedStatement); + return result; + } + + public override object VisitUnsafeStatement(UnsafeStatement unsafeStatement, object data) { + this.BeginVisit(unsafeStatement); + object result = this.TrackedVisit(unsafeStatement, data); + this.EndVisit(unsafeStatement); + return result; + } + + public override object VisitUsing(Using @using, object data) { + this.BeginVisit(@using); + object result = this.TrackedVisit(@using, data); + this.EndVisit(@using); + return result; + } + + public override object VisitUsingDeclaration(UsingDeclaration usingDeclaration, object data) { + this.BeginVisit(usingDeclaration); + object result = this.TrackedVisit(usingDeclaration, data); + this.EndVisit(usingDeclaration); + return result; + } + + public override object VisitUsingStatement(UsingStatement usingStatement, object data) { + this.BeginVisit(usingStatement); + object result = this.TrackedVisit(usingStatement, data); + this.EndVisit(usingStatement); + return result; + } + + public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data) { + this.BeginVisit(variableDeclaration); + object result = this.TrackedVisit(variableDeclaration, data); + this.EndVisit(variableDeclaration); + return result; + } + + public override object VisitWithStatement(WithStatement withStatement, object data) { + this.BeginVisit(withStatement); + object result = this.TrackedVisit(withStatement, data); + this.EndVisit(withStatement); + return result; + } + + public override object VisitYieldStatement(YieldStatement yieldStatement, object data) { + this.BeginVisit(yieldStatement); + object result = this.TrackedVisit(yieldStatement, data); + this.EndVisit(yieldStatement); + return result; + } + + public virtual object TrackedVisit(AddHandlerStatement addHandlerStatement, object data) { + return base.VisitAddHandlerStatement(addHandlerStatement, data); + } + + public virtual object TrackedVisit(AddressOfExpression addressOfExpression, object data) { + return base.VisitAddressOfExpression(addressOfExpression, data); + } + + public virtual object TrackedVisit(AnonymousMethodExpression anonymousMethodExpression, object data) { + return base.VisitAnonymousMethodExpression(anonymousMethodExpression, data); + } + + public virtual object TrackedVisit(ArrayCreateExpression arrayCreateExpression, object data) { + return base.VisitArrayCreateExpression(arrayCreateExpression, data); + } + + public virtual object TrackedVisit(ArrayInitializerExpression arrayInitializerExpression, object data) { + return base.VisitArrayInitializerExpression(arrayInitializerExpression, data); + } + + public virtual object TrackedVisit(AssignmentExpression assignmentExpression, object data) { + return base.VisitAssignmentExpression(assignmentExpression, data); + } + + public virtual object TrackedVisit(ICSharpCode.NRefactory.Ast.Attribute attribute, object data) { + return base.VisitAttribute(attribute, data); + } + + public virtual object TrackedVisit(AttributeSection attributeSection, object data) { + return base.VisitAttributeSection(attributeSection, data); + } + + public virtual object TrackedVisit(BaseReferenceExpression baseReferenceExpression, object data) { + return base.VisitBaseReferenceExpression(baseReferenceExpression, data); + } + + public virtual object TrackedVisit(BinaryOperatorExpression binaryOperatorExpression, object data) { + return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data); + } + + public virtual object TrackedVisit(BlockStatement blockStatement, object data) { + return base.VisitBlockStatement(blockStatement, data); + } + + public virtual object TrackedVisit(BreakStatement breakStatement, object data) { + return base.VisitBreakStatement(breakStatement, data); + } + + public virtual object TrackedVisit(CaseLabel caseLabel, object data) { + return base.VisitCaseLabel(caseLabel, data); + } + + public virtual object TrackedVisit(CastExpression castExpression, object data) { + return base.VisitCastExpression(castExpression, data); + } + + public virtual object TrackedVisit(CatchClause catchClause, object data) { + return base.VisitCatchClause(catchClause, data); + } + + public virtual object TrackedVisit(CheckedExpression checkedExpression, object data) { + return base.VisitCheckedExpression(checkedExpression, data); + } + + public virtual object TrackedVisit(CheckedStatement checkedStatement, object data) { + return base.VisitCheckedStatement(checkedStatement, data); + } + + public virtual object TrackedVisit(ClassReferenceExpression classReferenceExpression, object data) { + return base.VisitClassReferenceExpression(classReferenceExpression, data); + } + + public virtual object TrackedVisit(CompilationUnit compilationUnit, object data) { + return base.VisitCompilationUnit(compilationUnit, data); + } + + public virtual object TrackedVisit(ConditionalExpression conditionalExpression, object data) { + return base.VisitConditionalExpression(conditionalExpression, data); + } + + public virtual object TrackedVisit(ConstructorDeclaration constructorDeclaration, object data) { + return base.VisitConstructorDeclaration(constructorDeclaration, data); + } + + public virtual object TrackedVisit(ConstructorInitializer constructorInitializer, object data) { + return base.VisitConstructorInitializer(constructorInitializer, data); + } + + public virtual object TrackedVisit(ContinueStatement continueStatement, object data) { + return base.VisitContinueStatement(continueStatement, data); + } + + public virtual object TrackedVisit(DeclareDeclaration declareDeclaration, object data) { + return base.VisitDeclareDeclaration(declareDeclaration, data); + } + + public virtual object TrackedVisit(DefaultValueExpression defaultValueExpression, object data) { + return base.VisitDefaultValueExpression(defaultValueExpression, data); + } + + public virtual object TrackedVisit(DelegateDeclaration delegateDeclaration, object data) { + return base.VisitDelegateDeclaration(delegateDeclaration, data); + } + + public virtual object TrackedVisit(DestructorDeclaration destructorDeclaration, object data) { + return base.VisitDestructorDeclaration(destructorDeclaration, data); + } + + public virtual object TrackedVisit(DirectionExpression directionExpression, object data) { + return base.VisitDirectionExpression(directionExpression, data); + } + + public virtual object TrackedVisit(DoLoopStatement doLoopStatement, object data) { + return base.VisitDoLoopStatement(doLoopStatement, data); + } + + public virtual object TrackedVisit(ElseIfSection elseIfSection, object data) { + return base.VisitElseIfSection(elseIfSection, data); + } + + public virtual object TrackedVisit(EmptyStatement emptyStatement, object data) { + return base.VisitEmptyStatement(emptyStatement, data); + } + + public virtual object TrackedVisit(EndStatement endStatement, object data) { + return base.VisitEndStatement(endStatement, data); + } + + public virtual object TrackedVisit(EraseStatement eraseStatement, object data) { + return base.VisitEraseStatement(eraseStatement, data); + } + + public virtual object TrackedVisit(ErrorStatement errorStatement, object data) { + return base.VisitErrorStatement(errorStatement, data); + } + + public virtual object TrackedVisit(EventAddRegion eventAddRegion, object data) { + return base.VisitEventAddRegion(eventAddRegion, data); + } + + public virtual object TrackedVisit(EventDeclaration eventDeclaration, object data) { + return base.VisitEventDeclaration(eventDeclaration, data); + } + + public virtual object TrackedVisit(EventRaiseRegion eventRaiseRegion, object data) { + return base.VisitEventRaiseRegion(eventRaiseRegion, data); + } + + public virtual object TrackedVisit(EventRemoveRegion eventRemoveRegion, object data) { + return base.VisitEventRemoveRegion(eventRemoveRegion, data); + } + + public virtual object TrackedVisit(ExitStatement exitStatement, object data) { + return base.VisitExitStatement(exitStatement, data); + } + + public virtual object TrackedVisit(ExpressionStatement expressionStatement, object data) { + return base.VisitExpressionStatement(expressionStatement, data); + } + + public virtual object TrackedVisit(FieldDeclaration fieldDeclaration, object data) { + return base.VisitFieldDeclaration(fieldDeclaration, data); + } + + public virtual object TrackedVisit(FieldReferenceExpression fieldReferenceExpression, object data) { + return base.VisitFieldReferenceExpression(fieldReferenceExpression, data); + } + + public virtual object TrackedVisit(FixedStatement fixedStatement, object data) { + return base.VisitFixedStatement(fixedStatement, data); + } + + public virtual object TrackedVisit(ForeachStatement foreachStatement, object data) { + return base.VisitForeachStatement(foreachStatement, data); + } + + public virtual object TrackedVisit(ForNextStatement forNextStatement, object data) { + return base.VisitForNextStatement(forNextStatement, data); + } + + public virtual object TrackedVisit(ForStatement forStatement, object data) { + return base.VisitForStatement(forStatement, data); + } + + public virtual object TrackedVisit(GotoCaseStatement gotoCaseStatement, object data) { + return base.VisitGotoCaseStatement(gotoCaseStatement, data); + } + + public virtual object TrackedVisit(GotoStatement gotoStatement, object data) { + return base.VisitGotoStatement(gotoStatement, data); + } + + public virtual object TrackedVisit(IdentifierExpression identifierExpression, object data) { + return base.VisitIdentifierExpression(identifierExpression, data); + } + + public virtual object TrackedVisit(IfElseStatement ifElseStatement, object data) { + return base.VisitIfElseStatement(ifElseStatement, data); + } + + public virtual object TrackedVisit(IndexerDeclaration indexerDeclaration, object data) { + return base.VisitIndexerDeclaration(indexerDeclaration, data); + } + + public virtual object TrackedVisit(IndexerExpression indexerExpression, object data) { + return base.VisitIndexerExpression(indexerExpression, data); + } + + public virtual object TrackedVisit(InnerClassTypeReference innerClassTypeReference, object data) { + return base.VisitInnerClassTypeReference(innerClassTypeReference, data); + } + + public virtual object TrackedVisit(InterfaceImplementation interfaceImplementation, object data) { + return base.VisitInterfaceImplementation(interfaceImplementation, data); + } + + public virtual object TrackedVisit(InvocationExpression invocationExpression, object data) { + return base.VisitInvocationExpression(invocationExpression, data); + } + + public virtual object TrackedVisit(LabelStatement labelStatement, object data) { + return base.VisitLabelStatement(labelStatement, data); + } + + public virtual object TrackedVisit(LocalVariableDeclaration localVariableDeclaration, object data) { + return base.VisitLocalVariableDeclaration(localVariableDeclaration, data); + } + + public virtual object TrackedVisit(LockStatement lockStatement, object data) { + return base.VisitLockStatement(lockStatement, data); + } + + public virtual object TrackedVisit(MethodDeclaration methodDeclaration, object data) { + return base.VisitMethodDeclaration(methodDeclaration, data); + } + + public virtual object TrackedVisit(NamedArgumentExpression namedArgumentExpression, object data) { + return base.VisitNamedArgumentExpression(namedArgumentExpression, data); + } + + public virtual object TrackedVisit(NamespaceDeclaration namespaceDeclaration, object data) { + return base.VisitNamespaceDeclaration(namespaceDeclaration, data); + } + + public virtual object TrackedVisit(ObjectCreateExpression objectCreateExpression, object data) { + return base.VisitObjectCreateExpression(objectCreateExpression, data); + } + + public virtual object TrackedVisit(OnErrorStatement onErrorStatement, object data) { + return base.VisitOnErrorStatement(onErrorStatement, data); + } + + public virtual object TrackedVisit(OperatorDeclaration operatorDeclaration, object data) { + return base.VisitOperatorDeclaration(operatorDeclaration, data); + } + + public virtual object TrackedVisit(OptionDeclaration optionDeclaration, object data) { + return base.VisitOptionDeclaration(optionDeclaration, data); + } + + public virtual object TrackedVisit(ParameterDeclarationExpression parameterDeclarationExpression, object data) { + return base.VisitParameterDeclarationExpression(parameterDeclarationExpression, data); + } + + public virtual object TrackedVisit(ParenthesizedExpression parenthesizedExpression, object data) { + return base.VisitParenthesizedExpression(parenthesizedExpression, data); + } + + public virtual object TrackedVisit(PointerReferenceExpression pointerReferenceExpression, object data) { + return base.VisitPointerReferenceExpression(pointerReferenceExpression, data); + } + + public virtual object TrackedVisit(PrimitiveExpression primitiveExpression, object data) { + return base.VisitPrimitiveExpression(primitiveExpression, data); + } + + public virtual object TrackedVisit(PropertyDeclaration propertyDeclaration, object data) { + return base.VisitPropertyDeclaration(propertyDeclaration, data); + } + + public virtual object TrackedVisit(PropertyGetRegion propertyGetRegion, object data) { + return base.VisitPropertyGetRegion(propertyGetRegion, data); + } + + public virtual object TrackedVisit(PropertySetRegion propertySetRegion, object data) { + return base.VisitPropertySetRegion(propertySetRegion, data); + } + + public virtual object TrackedVisit(RaiseEventStatement raiseEventStatement, object data) { + return base.VisitRaiseEventStatement(raiseEventStatement, data); + } + + public virtual object TrackedVisit(ReDimStatement reDimStatement, object data) { + return base.VisitReDimStatement(reDimStatement, data); + } + + public virtual object TrackedVisit(RemoveHandlerStatement removeHandlerStatement, object data) { + return base.VisitRemoveHandlerStatement(removeHandlerStatement, data); + } + + public virtual object TrackedVisit(ResumeStatement resumeStatement, object data) { + return base.VisitResumeStatement(resumeStatement, data); + } + + public virtual object TrackedVisit(ReturnStatement returnStatement, object data) { + return base.VisitReturnStatement(returnStatement, data); + } + + public virtual object TrackedVisit(SizeOfExpression sizeOfExpression, object data) { + return base.VisitSizeOfExpression(sizeOfExpression, data); + } + + public virtual object TrackedVisit(StackAllocExpression stackAllocExpression, object data) { + return base.VisitStackAllocExpression(stackAllocExpression, data); + } + + public virtual object TrackedVisit(StopStatement stopStatement, object data) { + return base.VisitStopStatement(stopStatement, data); + } + + public virtual object TrackedVisit(SwitchSection switchSection, object data) { + return base.VisitSwitchSection(switchSection, data); + } + + public virtual object TrackedVisit(SwitchStatement switchStatement, object data) { + return base.VisitSwitchStatement(switchStatement, data); + } + + public virtual object TrackedVisit(TemplateDefinition templateDefinition, object data) { + return base.VisitTemplateDefinition(templateDefinition, data); + } + + public virtual object TrackedVisit(ThisReferenceExpression thisReferenceExpression, object data) { + return base.VisitThisReferenceExpression(thisReferenceExpression, data); + } + + public virtual object TrackedVisit(ThrowStatement throwStatement, object data) { + return base.VisitThrowStatement(throwStatement, data); + } + + public virtual object TrackedVisit(TryCatchStatement tryCatchStatement, object data) { + return base.VisitTryCatchStatement(tryCatchStatement, data); + } + + public virtual object TrackedVisit(TypeDeclaration typeDeclaration, object data) { + return base.VisitTypeDeclaration(typeDeclaration, data); + } + + public virtual object TrackedVisit(TypeOfExpression typeOfExpression, object data) { + return base.VisitTypeOfExpression(typeOfExpression, data); + } + + public virtual object TrackedVisit(TypeOfIsExpression typeOfIsExpression, object data) { + return base.VisitTypeOfIsExpression(typeOfIsExpression, data); + } + + public virtual object TrackedVisit(TypeReference typeReference, object data) { + return base.VisitTypeReference(typeReference, data); + } + + public virtual object TrackedVisit(TypeReferenceExpression typeReferenceExpression, object data) { + return base.VisitTypeReferenceExpression(typeReferenceExpression, data); + } + + public virtual object TrackedVisit(UnaryOperatorExpression unaryOperatorExpression, object data) { + return base.VisitUnaryOperatorExpression(unaryOperatorExpression, data); + } + + public virtual object TrackedVisit(UncheckedExpression uncheckedExpression, object data) { + return base.VisitUncheckedExpression(uncheckedExpression, data); + } + + public virtual object TrackedVisit(UncheckedStatement uncheckedStatement, object data) { + return base.VisitUncheckedStatement(uncheckedStatement, data); + } + + public virtual object TrackedVisit(UnsafeStatement unsafeStatement, object data) { + return base.VisitUnsafeStatement(unsafeStatement, data); + } + + public virtual object TrackedVisit(Using @using, object data) { + return base.VisitUsing(@using, data); + } + + public virtual object TrackedVisit(UsingDeclaration usingDeclaration, object data) { + return base.VisitUsingDeclaration(usingDeclaration, data); + } + + public virtual object TrackedVisit(UsingStatement usingStatement, object data) { + return base.VisitUsingStatement(usingStatement, data); + } + + public virtual object TrackedVisit(VariableDeclaration variableDeclaration, object data) { + return base.VisitVariableDeclaration(variableDeclaration, data); + } + + public virtual object TrackedVisit(WithStatement withStatement, object data) { + return base.VisitWithStatement(withStatement, data); + } + + public virtual object TrackedVisit(YieldStatement yieldStatement, object data) { + return base.VisitYieldStatement(yieldStatement, data); + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs new file mode 100644 index 0000000000..562e55579e --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PositionTrackingAstVisitor.cs @@ -0,0 +1,142 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Drawing; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Provides contextual position information while iterating through + /// the AST and the ability to resolve expressions in-place. + /// + public abstract class PositionTrackingAstVisitor : NodeTrackingAstVisitor + { + + private Stack parentNodes; + + protected override void BeginVisit(INode node) + { + base.BeginVisit(node); + // Only push nodes on the stack which have valid position information. + if (node != null && + node.StartLocation.X >= 1 && node.StartLocation.Y >= 1 && + node.EndLocation.X >= 1 && node.EndLocation.Y >= 1) { + this.parentNodes.Push(node); + } + } + + protected override void EndVisit(INode node) + { + base.EndVisit(node); + // Only remove those nodes which have actually been pushed before. + if (this.parentNodes.Count > 0 && INode.ReferenceEquals(this.parentNodes.Peek(), node)) { + this.parentNodes.Pop(); + } + } + + // ******************************************************************************************************************************** + + /// + /// Gets a flag that indicates whether the current node is located + /// inside a block which position information is available for. + /// + protected bool PositionAvailable { + get { + return this.parentNodes.Count > 0; + } + } + + /// + /// Gets the start location of the current innermost node with valid position information + /// as 1-based coordinates in the parsed document. + /// X = column number, Y = line number. + /// + protected Location CurrentNodeStartLocation { + get { + return this.parentNodes.Peek().StartLocation; + } + } + + /// + /// Gets the end location of the current innermost node with valid position information + /// as 1-based coordinates in the parsed document. + /// X = column number, Y = line number. + /// + protected Location CurrentNodeEndLocation { + get { + return this.parentNodes.Peek().EndLocation; + } + } + + // ******************************************************************************************************************************** + + /// + /// Resolves an expression in the current node's context. + /// + /// The expression to be resolved. + /// Any member declared in the source file in question. Used to get the language, file name and file content. + public ResolveResult Resolve(Expression expression, IMember memberInThisFile) + { + if (!this.PositionAvailable) { + LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Resolve failed due to position information being unavailable. Expression: "+expression.ToString()); + return null; + } + + // In order to resolve expression, we need the original code. + // HACK: To get the code belonging to this expression, we pass it through the code generator. + // (Is there a better way?) + + string code = null; + LanguageProperties lp = NRefactoryResourceResolver.GetLanguagePropertiesForMember(memberInThisFile); + if (lp != null && lp.CodeGenerator != null) { + code = lp.CodeGenerator.GenerateCode(expression, String.Empty); + } + + if (!String.IsNullOrEmpty(code)) { + + // Now resolve the expression in the current context. + #if DEBUG + LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: Resolving an expression, code (re-generated): '"+code+"'"); + #endif + ResolveResult rr = ParserService.Resolve(new ExpressionResult(code, ExpressionContext.Default), this.CurrentNodeStartLocation.Y-1, this.CurrentNodeStartLocation.X, memberInThisFile.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(memberInThisFile.DeclaringType.CompilationUnit.FileName)); + + #if DEBUG + if (rr != null) { + LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: The expression resolved to: "+rr.ToString()); + } else { + LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor: The expression could not be resolved."); + } + #endif + + return rr; + + } else { + LoggingService.Debug("ResourceToolkit: PositionTrackingAstVisitor could not re-generate code for the expression: "+expression.ToString()); + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + protected PositionTrackingAstVisitor() : base() + { + this.parentNodes = new Stack(); + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs new file mode 100644 index 0000000000..ad4f0cbedb --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/PropertyFieldAssociationVisitor.cs @@ -0,0 +1,242 @@ +// +// +// +// +// $Revision$ +// + +using System; + +using ICSharpCode.Core; +using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Dom; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Finds connections between fields and properties. + /// TODO: This currently only works if the field and the property are declared in the same source file. + /// + public class PropertyFieldAssociationVisitor : PositionTrackingAstVisitor + { + IMember memberToFind; + IMember associatedMember; + + /// + /// Gets the field that has been found to be associated with the property specified at the constructor call. + /// + public IField AssociatedField { + get { + return this.associatedMember as IField; + } + } + + /// + /// Gets the property that has been found to be associated with the field specified at the constructor call. + /// + public IProperty AssociatedProperty { + get { + return this.associatedMember as IProperty; + } + } + + // ******************************************************************************************************************************** + + private enum VisitorContext + { + Default, + PropertyGetRegion, + PropertySetRegion + } + + private VisitorContext currentContext = VisitorContext.Default; + + protected override void BeginVisit(INode node) + { + base.BeginVisit(node); + if (node is PropertyGetRegion) { + this.currentContext = VisitorContext.PropertyGetRegion; + } else if (node is PropertySetRegion) { + this.currentContext = VisitorContext.PropertySetRegion; + } + } + + protected override void EndVisit(INode node) + { + if (node is PropertyGetRegion || node is PropertySetRegion) { + this.currentContext = VisitorContext.Default; + } + base.EndVisit(node); + } + + public override object TrackedVisit(PropertyDeclaration propertyDeclaration, object data) + { + + if (this.memberToFind is IProperty) { + + // If we are looking for a specified property: + // find out if this is the one by comparing the location. + if (propertyDeclaration.StartLocation.X == this.memberToFind.Region.BeginColumn && + propertyDeclaration.StartLocation.Y == this.memberToFind.Region.BeginLine) { + data = true; + } + + } else if (this.memberToFind is IField) { + + // If we are looking for a specifield field: + // store the property info for future reference. + data = propertyDeclaration; + + } + + return base.TrackedVisit(propertyDeclaration, data); + } + + public override object TrackedVisit(ReturnStatement returnStatement, object data) + { + // If we are in a property get region, + // this may be the statement where the field value is returned. + if (this.associatedMember == null && // skip if already found to improve performance + this.currentContext == VisitorContext.PropertyGetRegion && data != null) { + + // Resolve the expression. + MemberResolveResult mrr = this.Resolve(returnStatement.Expression, this.memberToFind) as MemberResolveResult; + if (mrr != null && mrr.ResolvedMember is IField) { + + PropertyDeclaration pd; + + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, resolved field: "+mrr.ResolvedMember.ToString()); + #endif + + if (data as bool? ?? false) { + + // We are looking for this property. + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, this property seems to reference field "+mrr.ResolvedMember.ToString()); + #endif + this.associatedMember = mrr.ResolvedMember; + + } else if ((pd = (data as PropertyDeclaration)) != null) { + + // We are looking for the field in this.memberToFind. + if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0) { + + // Resolve the property. + MemberResolveResult prr = ParserService.Resolve(new ExpressionResult(pd.Name, ExpressionContext.Default), pd.StartLocation.Y-1, pd.StartLocation.X, this.memberToFind.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(this.memberToFind.DeclaringType.CompilationUnit.FileName)) as MemberResolveResult; + if (prr != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, resolved property: "+prr.ResolvedMember.ToString()); + #endif + + if (prr.ResolvedMember is IProperty) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertyGetRegion, property "+prr.ResolvedMember.ToString()+" seems to reference field "+mrr.ResolvedMember.ToString()); + #endif + this.associatedMember = prr.ResolvedMember; + } + + } + + } + + } + + } + + } + + return base.TrackedVisit(returnStatement, data); + } + + public override object TrackedVisit(AssignmentExpression assignmentExpression, object data) + { + // If we are in a property set region, + // this may be the statement where the field value is assigned. + if (this.associatedMember == null && // skip if already found to improve performance + this.currentContext == VisitorContext.PropertySetRegion && + assignmentExpression.Op == AssignmentOperatorType.Assign && data != null) { + + // Resolve the expression. + MemberResolveResult mrr = this.Resolve(assignmentExpression.Left, this.memberToFind) as MemberResolveResult; + if (mrr != null && mrr.ResolvedMember is IField && !((IField)mrr.ResolvedMember).IsLocalVariable) { + + PropertyDeclaration pd; + + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, resolved field: "+mrr.ResolvedMember.ToString()); + #endif + + if (data as bool? ?? false) { + + // We are looking for this property. + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, this property seems to reference field "+mrr.ResolvedMember.ToString()); + #endif + this.associatedMember = mrr.ResolvedMember; + + } else if ((pd = (data as PropertyDeclaration)) != null) { + + // We are looking for the field in this.memberToFind. + if (this.memberToFind.CompareTo(mrr.ResolvedMember) == 0) { + + // Resolve the property. + MemberResolveResult prr = ParserService.Resolve(new ExpressionResult(pd.Name, ExpressionContext.Default), pd.StartLocation.Y-1, pd.StartLocation.X, this.memberToFind.DeclaringType.CompilationUnit.FileName, ParserService.GetParseableFileContent(this.memberToFind.DeclaringType.CompilationUnit.FileName)) as MemberResolveResult; + if (prr != null) { + + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, resolved property: "+prr.ResolvedMember.ToString()); + #endif + + if (prr.ResolvedMember is IProperty) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: PropertyFieldAssociationVisitor, inside PropertySetRegion, property "+prr.ResolvedMember.ToString()+" seems to reference field "+mrr.ResolvedMember.ToString()); + #endif + this.associatedMember = prr.ResolvedMember; + } + + } + + } + + } + + } + + } + + return base.TrackedVisit(assignmentExpression, data); + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + /// The property to find the associated field for. + public PropertyFieldAssociationVisitor(IProperty property) : base() + { + if (property == null) { + throw new ArgumentNullException("property"); + } + this.memberToFind = property; + } + + /// + /// Initializes a new instance of the class. + /// + /// The field to find the associated property for. + public PropertyFieldAssociationVisitor(IField field) : base() + { + if (field == null) { + throw new ArgumentNullException("field"); + } else if (field.IsLocalVariable) { + throw new ArgumentException("The specified IField must not be a local variable.", "field"); + } + this.memberToFind = field; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs new file mode 100644 index 0000000000..ed17274fd1 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/Resolver/ResourceResolveResult.cs @@ -0,0 +1,80 @@ +// +// +// +// +// $Revision$ +// + +using System; + +using ICSharpCode.SharpDevelop.Dom; + +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit.Resolver +{ + /// + /// Describes a reference to a resource. + /// + public class ResourceResolveResult : ResolveResult + { + + IResourceFileContent resourceFileContent; + string key; + + /// + /// Gets the of the resource being referenced. + /// + public IResourceFileContent ResourceFileContent { + get { + return this.resourceFileContent; + } + } + + /// + /// Gets the resource key being referenced. May be null if the key is unknown/not yet typed. + /// + public string Key { + get { + return this.key; + } + } + + /// + /// Gets the resource file name that contains the resource being referenced. + /// Only valid if both and are not null. + /// + public string FileName { + get { + + if (this.ResourceFileContent == null || this.Key == null) { + return null; + } + + IMultiResourceFileContent mrfc = this.ResourceFileContent as IMultiResourceFileContent; + if (mrfc != null) { + return mrfc.GetFileNameForKey(this.Key); + } else { + return this.ResourceFileContent.FileName; + } + + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The class that contains the reference to the resource. + /// The member that contains the reference to the resource. + /// The type of the resource being referenced. + /// The that contains the resource being referenced. + /// The resource key being referenced. + public ResourceResolveResult(IClass callingClass, IMember callingMember, IReturnType returnType, IResourceFileContent resourceFileContent, string key) + : base(callingClass, callingMember, returnType) + { + this.resourceFileContent = resourceFileContent; + this.key = key; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultBclResourceFileContentFactory.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultBclResourceFileContentFactory.cs new file mode 100644 index 0000000000..02721d1e1d --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultBclResourceFileContentFactory.cs @@ -0,0 +1,63 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.IO; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Creates resource file contents for .resources and .resx files. + /// + public class DefaultBclResourceFileContentFactory : IResourceFileContentFactory + { + /// + /// Determines whether this factory can create a resource file content + /// for the specified file. + /// + /// The file name to examine. + /// true, if this factory can create a resource file content for the specified file, otherwise false. + public bool CanCreateContentForFile(string fileName) + { + string ext = Path.GetExtension(fileName); + + if (ext.Equals(".resources", StringComparison.OrdinalIgnoreCase) || + ext.Equals(".resx", StringComparison.OrdinalIgnoreCase)) { + return true; + } + + return false; + } + + /// + /// Creates a resource file content for the specified file. + /// + /// The name of the file to create the resource file content for. + /// A new instance of a class that implements and represents the content of the specified file, or null, if this class cannot handle the file format. + public IResourceFileContent CreateContentForFile(string fileName) + { + string ext = Path.GetExtension(fileName); + + if (ext.Equals(".resources", StringComparison.OrdinalIgnoreCase)) { + return new ResourcesResourceFileContent(fileName); + } else if (ext.Equals(".resx", StringComparison.OrdinalIgnoreCase)) { + return new ResXResourceFileContent(fileName); + } + + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public DefaultBclResourceFileContentFactory() + { + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultFileLocalizedResourcesFinder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultFileLocalizedResourcesFinder.cs new file mode 100644 index 0000000000..e560c776f8 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/DefaultFileLocalizedResourcesFinder.cs @@ -0,0 +1,109 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +using ICSharpCode.Core; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Finds localized resources that follow the standard .NET pattern + /// MyResources.(culture).(extension). + /// + public class DefaultFileLocalizedResourcesFinder : ILocalizedResourcesFinder + { + /// + /// Gets localized resources that belong to the master resource file. + /// + /// The name of the master resource file. + /// A dictionary of culture names and associated resource file contents, or null, if there are none. + public IDictionary GetLocalizedContents(string fileName) + { + #if DEBUG + LoggingService.Debug("ResourceToolkit: DefaultFileLocalizedResourcesFinder.GetLocalizedContents called, fileName: '"+fileName+"'"); + #endif + + string fileNameWithoutExtension = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName)); + string culture = Path.GetExtension(fileNameWithoutExtension); + if (!String.IsNullOrEmpty(culture)) { + try { + CultureInfo dummy = CultureInfo.GetCultureInfo(culture); + // the specified file is a localized resource file itself + LoggingService.Debug("ResourceToolkit: DefaultFileLocalizedResourcesFinder.GetLocalizedContents: Returning null for file '"+fileName+"' because it has been detected as being a localized resource file itself."); + return null; + } catch (ArgumentException) { + } + } + + return FindLocalizedResourceFiles(fileNameWithoutExtension, Path.GetExtension(fileName)); + } + + /// + /// Finds all localized resource files that follow the pattern + /// <>.<culture><>. + /// + /// The full path and name of the master resource file without extension. + /// The extension of the master resource file (with leading dot). + /// A dictionary of culture names and associated resource file contents. + public static IDictionary FindLocalizedResourceFiles(string fileNameWithoutExtension, string extension) + { + Dictionary list = new Dictionary(); + + #if DEBUG + LoggingService.Debug("ResourceToolkit: Finding localized resource files (DefaultFileLocalizedResourcesFinder.FindLocalizedResourceFiles)."); + LoggingService.Debug(" -> fileNameWithoutExtension: '"+fileNameWithoutExtension+"'"); + LoggingService.Debug(" -> extension: '"+extension+"'"); + #endif + + foreach (string fileName in Directory.GetFiles(Path.GetDirectoryName(fileNameWithoutExtension), Path.GetFileName(fileNameWithoutExtension)+".*"+extension)) { + #if DEBUG + LoggingService.Debug(" -> possible file: '"+fileName+"'"); + #endif + + string culture = Path.GetExtension(Path.GetFileNameWithoutExtension(fileName)); + #if DEBUG + LoggingService.Debug(" -> culture = '"+(culture ?? "")+"'"); + #endif + + if (!String.IsNullOrEmpty(culture)) { + + try { + + CultureInfo ci = CultureInfo.GetCultureInfo(culture.Substring(1)); // need to remove leading dot from culture + IResourceFileContent content = ResourceFileContentRegistry.GetResourceFileContent(fileName); + if (content != null) { + #if DEBUG + LoggingService.Debug(" -> culture name: '"+ci.Name+"'"); + #endif + list.Add(ci.Name, content); + } + + } catch (ArgumentException) { + continue; + } + + } + + } + + return list; + } + + // ******************************************************************************************************************************** + + /// + /// Initializes a new instance of the class. + /// + public DefaultFileLocalizedResourcesFinder() + { + } + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ILocalizedResourcesFinder.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ILocalizedResourcesFinder.cs new file mode 100644 index 0000000000..e18a88ec6c --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ILocalizedResourcesFinder.cs @@ -0,0 +1,26 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes an object that can find localized resources that belong to a + /// master resource. + /// + public interface ILocalizedResourcesFinder + { + /// + /// Gets localized resources that belong to the master resource file. + /// + /// The name of the master resource file. + /// A dictionary of culture names and associated resource file contents, or null, if there are none. + IDictionary GetLocalizedContents(string fileName); + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IMultiResourceFileContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IMultiResourceFileContent.cs new file mode 100644 index 0000000000..e4595ad6ea --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IMultiResourceFileContent.cs @@ -0,0 +1,26 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes the content of multiple resource files. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Multi")] + public interface IMultiResourceFileContent : IResourceFileContent + { + + /// + /// Gets the file name of the resource file the specified key is in. + /// + /// The name of the resource file the specified key is in, or null if the key cannot be found in any resource file this instance represents. + string GetFileNameForKey(string key); + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContent.cs new file mode 100644 index 0000000000..738cc3e942 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContent.cs @@ -0,0 +1,82 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes the content of a resource file. + /// + public interface IResourceFileContent + { + + /// + /// Gets the file name of the resource file this instance represents. + /// If this instance represents multiple resource files, it's the name + /// of the resource file which new entries are added to. + /// + string FileName { + get; + } + + /// + /// Gets the culture of the resource file this instance represents. + /// + CultureInfo Culture { + get; + } + + /// + /// Gets an iterator that can be used to iterate over all key/value pairs in this resource. + /// + IEnumerable> Data { + get; + } + + /// + /// Determines if the resource file this instance represents contains the specified key. + /// + bool ContainsKey(string key); + + /// + /// Tries to get the value of the resource with the specified key. + /// + /// true, if the key exists, otherwise false. + bool TryGetValue(string key, out object value); + + /// + /// Adds a new key to the resource file. + /// + /// A key with the same name already exists. + void Add(string key, object value); + + /// + /// Modify the value of an existing entry. + /// + /// The specified key does not exist. + void SetValue(string key, object value); + + /// + /// Renames a resource key. + /// + /// The old name of the resource key to rename. + /// The new name of the resource key. + /// The specified key does not exist. + void RenameKey(string oldName, string newName); + + /// + /// Removes the specified resource key permanently. + /// + /// The resource key to remove. + /// The specified key does not exist. + void RemoveKey(string key); + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContentFactory.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContentFactory.cs new file mode 100644 index 0000000000..c45367e017 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/IResourceFileContentFactory.cs @@ -0,0 +1,33 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes an object that can create instances of classes that + /// implement . + /// + public interface IResourceFileContentFactory + { + /// + /// Determines whether this factory can create a resource file content + /// for the specified file. + /// + /// The file name to examine. + /// true, if this factory can create a resource file content for the specified file, otherwise false. + bool CanCreateContentForFile(string fileName); + + /// + /// Creates a resource file content for the specified file. + /// + /// The name of the file to create the resource file content for. + /// A new instance of a class that implements and represents the content of the specified file, or null, if this class cannot handle the file format. + IResourceFileContent CreateContentForFile(string fileName); + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/MergedResourceFileContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/MergedResourceFileContent.cs new file mode 100644 index 0000000000..ce57402cd1 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/MergedResourceFileContent.cs @@ -0,0 +1,213 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Makes multiple implementations accessible + /// through a single one. All contents are merged into a single dictionary. + /// When adding new entries, they are added to the master content. + /// + public class MergedResourceFileContent : IMultiResourceFileContent + { + + IResourceFileContent masterContent; + IResourceFileContent[] otherContents; + + /// + /// Initializes a new instance of the class. + /// + /// The master resource file content. + /// Additional resource file contents. + /// The cultures of the specified resource file contents do not match. + public MergedResourceFileContent(IResourceFileContent masterContent, IResourceFileContent[] otherContents) + { + this.masterContent = masterContent; + this.otherContents = otherContents; + + // Ensure that all contents are for the same culture + foreach (IResourceFileContent c in this.otherContents) { + if (!c.Culture.Equals(this.masterContent.Culture)) { + throw new ArgumentException("The cultures of the specified resource file contents do not match."); + } + } + } + + // ******************************************************************************************************************************** + + /// + /// Gets the file name of the master resource file. + /// + public string FileName { + get { + return this.masterContent.FileName; + } + } + + /// + /// Gets the culture of the resource files this instance represents. + /// + public CultureInfo Culture { + get { + return this.masterContent.Culture; + } + } + + /// + /// Gets an iterator that can be used to iterate over all key/value pairs in all resource files this instance represents. + /// + public IEnumerable> Data { + get { + foreach (KeyValuePair entry in this.masterContent.Data) { + yield return entry; + } + foreach (IResourceFileContent c in this.otherContents) { + foreach (KeyValuePair entry in c.Data) { + yield return entry; + } + } + } + } + + /// + /// Determines if any of the resource files this instance represents contains the specified key. + /// + public bool ContainsKey(string key) + { + if (this.masterContent.ContainsKey(key)) { + return true; + } + foreach (IResourceFileContent c in this.otherContents) { + if (c.ContainsKey(key)) { + return true; + } + } + return false; + } + + /// + /// Tries to get the value of the resource with the specified key. + /// + /// true, if the key exists, otherwise false. + public bool TryGetValue(string key, out object value) + { + if (this.masterContent.TryGetValue(key, out value)) { + return true; + } + foreach (IResourceFileContent c in this.otherContents) { + if (c.TryGetValue(key, out value)) { + return true; + } + } + return false; + } + + /// + /// Adds a new key to the master resource file. + /// + /// A key with the same name already exists. + public void Add(string key, object value) + { + this.masterContent.Add(key, value); + } + + /// + /// Modify the value of an existing entry. + /// + /// The specified key does not exist. + public void SetValue(string key, object value) + { + if (this.masterContent.ContainsKey(key)) { + this.masterContent.SetValue(key, value); + return; + } else { + foreach (IResourceFileContent c in this.otherContents) { + if (c.ContainsKey(key)) { + c.SetValue(key, value); + return; + } + } + } + throw new ArgumentException("The key '"+key+"' does not exist.", "key"); + } + + /// + /// Renames a resource key. + /// + /// The old name of the resource key to rename. + /// The new name of the resource key. + /// The specified key does not exist or the new key does already exist. + public void RenameKey(string oldName, string newName) + { + if (this.masterContent.ContainsKey(oldName)) { + this.masterContent.RenameKey(oldName, newName); + return; + } else { + foreach (IResourceFileContent c in this.otherContents) { + if (c.ContainsKey(oldName)) { + c.RenameKey(oldName, newName); + return; + } + } + } + throw new ArgumentException("The key '"+oldName+"' does not exist.", "oldName"); + } + + /// + /// Removes the specified resource key permanently. + /// + /// The resource key to remove. + /// The specified key does not exist. + public void RemoveKey(string key) + { + if (this.masterContent.ContainsKey(key)) { + this.masterContent.RemoveKey(key); + return; + } else { + foreach (IResourceFileContent c in this.otherContents) { + if (c.ContainsKey(key)) { + c.RemoveKey(key); + return; + } + } + } + throw new ArgumentException("The key '"+key+"' does not exist.", "key"); + } + + /// + /// Gets the file name of the resource file the specified key is in. + /// + /// The name of the resource file the specified key is in, or null if the key cannot be found in any resource file this instance represents. + public string GetFileNameForKey(string key) + { + string fileName; + IMultiResourceFileContent mrfc; + if ((mrfc = (this.masterContent as IMultiResourceFileContent)) != null) { + if ((fileName = mrfc.GetFileNameForKey(key)) != null) { + return fileName; + } + } else if (this.masterContent.ContainsKey(key)) { + return this.masterContent.FileName; + } + foreach (IResourceFileContent c in this.otherContents) { + if ((mrfc = (c as IMultiResourceFileContent)) != null) { + if ((fileName = mrfc.GetFileNameForKey(key)) != null) { + return fileName; + } + } else if (c.ContainsKey(key)) { + return c.FileName; + } + } + return null; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResXResourceFileContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResXResourceFileContent.cs new file mode 100644 index 0000000000..e6de768a3d --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResXResourceFileContent.cs @@ -0,0 +1,89 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Resources; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes the content of a .resx resource file. + /// + public class ResXResourceFileContent : ResourcesResourceFileContent + { + + Dictionary metadata; + + /// + /// Initializes a new instance of the class. + /// + /// The file name of the resource file this instance represents. + public ResXResourceFileContent(string fileName) : base(fileName) + { + } + + // ******************************************************************************************************************************** + + /// + /// Initializes all instance fields in preparation for loading of the file content. + /// + protected override void InitializeContent() + { + base.InitializeContent(); + this.metadata = new Dictionary(); + } + + /// + /// Loads the content of the specified into the cache. + /// + /// The to be used to read the resource content. + protected override void LoadContent(IResourceReader reader) + { + base.LoadContent(reader); + IDictionaryEnumerator en = ((ResXResourceReader)reader).GetMetadataEnumerator(); + while (en.MoveNext()) { + this.metadata.Add((string)en.Key, en.Value); + } + } + + /// + /// Gets a resx resource reader for the resource file represented by this instance. + /// + /// A resx resource reader for the resource file represented by this instance. + protected override IResourceReader GetResourceReader() + { + return new ResXResourceReader(this.FileName); + } + + // ******************************************************************************************************************************** + + /// + /// Save changes done to the resource content to disk. + /// + /// The to be used to save the resource content. + protected override void SaveContent(IResourceWriter writer) + { + base.SaveContent(writer); + ResXResourceWriter w = (ResXResourceWriter)writer; + foreach (KeyValuePair entry in this.metadata) { + w.AddMetadata(entry.Key, entry.Value); + } + } + + /// + /// Gets a resx resource writer for the resource file represented by this instance. + /// + /// A resx resource writer for the resource file represented by this instance. + protected override IResourceWriter GetResourceWriter() + { + return new ResXResourceWriter(this.FileName); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourceFileContentRegistry.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourceFileContentRegistry.cs new file mode 100644 index 0000000000..c167e3bcff --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourceFileContentRegistry.cs @@ -0,0 +1,120 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Provides facilities to load and cache the contents of resource files. + /// + public static class ResourceFileContentRegistry + { + /// + /// The AddIn tree path where the resource file content factories are registered. + /// + public const string ResourceFileContentFactoriesAddInTreePath = "/AddIns/ResourceToolkit/ResourceFileContentFactories"; + + static List factories; + + /// + /// Gets a list of all registered resource file content factories. + /// + public static IEnumerable Factories { + get { + if (factories == null) { + factories = AddInTree.BuildItems(ResourceFileContentFactoriesAddInTreePath, null, false); + } + return factories; + } + } + + + static Dictionary resourceFileContents = new Dictionary(); + + /// + /// Gets the resource content for the specified file. + /// + /// The name of the file to get a resource content for. + /// The resource content for the specified file. + /// The format of the specified resource file cannot be handled. + public static IResourceFileContent GetResourceFileContent(string fileName) + { + IResourceFileContent c; + if (!resourceFileContents.TryGetValue(fileName, out c)) { + c = CreateResourceFileContent(fileName); + if (c == null) { + throw new NotSupportedException("The format of the resource file '"+fileName+"' cannot be handled by any registered resource file content factory."); + } + resourceFileContents[fileName] = c; + } + return c; + } + + /// + /// Creates the resource content for the specified file. + /// + /// The name of the file to create a resource content for. + /// The resource content for the specified file, or null, if the resource file format cannot be handled. + static IResourceFileContent CreateResourceFileContent(string fileName) + { + foreach (IResourceFileContentFactory factory in Factories) { + if (factory.CanCreateContentForFile(fileName)) { + return factory.CreateContentForFile(fileName); + } + } + return null; + } + + // ******************************************************************************************************************************** + + /// + /// The AddIn tree path where the localized resource finders are registered. + /// + public const string LocalizedResourcesFindersAddInTreePath = "/AddIns/ResourceToolkit/LocalizedResourcesFinders"; + + static List localizedResourcesFinders; + + /// + /// Gets a list of all registered localized resources finders. + /// + public static IEnumerable LocalizedResourcesFinders { + get { + if (localizedResourcesFinders == null) { + localizedResourcesFinders = AddInTree.BuildItems(LocalizedResourcesFindersAddInTreePath, null, false); + } + return localizedResourcesFinders; + } + } + + /// + /// Gets localized resources that belong to the master resource file. + /// + /// The name of the master resource file. + /// A dictionary of culture names and associated resource file contents. + public static IDictionary GetLocalizedContents(string fileName) + { + Dictionary list = new Dictionary(); + foreach (ILocalizedResourcesFinder finder in LocalizedResourcesFinders) { + IDictionary l = finder.GetLocalizedContents(fileName); + if (l != null) { + foreach (KeyValuePair entry in l) { + if (!list.ContainsKey(entry.Key)) { + list.Add(entry.Key, entry.Value); + } + } + } + } + return list; + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourcesResourceFileContent.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourcesResourceFileContent.cs new file mode 100644 index 0000000000..e5d27e3043 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceFileContent/ResourcesResourceFileContent.cs @@ -0,0 +1,270 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Resources; + +using ICSharpCode.Core; + +namespace Hornung.ResourceToolkit.ResourceFileContent +{ + /// + /// Describes the content of a .resources resource file. + /// + public class ResourcesResourceFileContent : IResourceFileContent + { + + readonly string fileName; + readonly CultureInfo culture; + + DateTime lastWriteTimeUtc; + Dictionary data; + + /// + /// Gets the file name of the resource file this instance represents. + /// + public string FileName { + get { + return this.fileName; + } + } + + /// + /// Gets the culture of the resource file this instance represents. + /// + public CultureInfo Culture { + get { + return this.culture; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The file name of the resource file this instance represents. + public ResourcesResourceFileContent(string fileName) + { + this.fileName = fileName; + // Determine culture from file name + string cultureExt = Path.GetExtension(Path.GetFileNameWithoutExtension(fileName)); + if (!String.IsNullOrEmpty(cultureExt)) { + try { + this.culture = CultureInfo.GetCultureInfo(cultureExt.Substring(1)); // need to remove leading dot from cultureExt + } catch (ArgumentException) { + this.culture = CultureInfo.InvariantCulture; + } + } else { + this.culture = CultureInfo.InvariantCulture; + } + + #if DEBUG + LoggingService.Debug("ResourceToolkit: Created ResourceFileContent, file '"+fileName+"', culture name: '"+this.Culture.Name+"'"); + #endif + } + + /// + /// Synchronises the cache with the content of the actual file on disk. + /// + protected void EnsureLoaded() + { + if (this.data == null || File.GetLastWriteTimeUtc(this.FileName) != this.lastWriteTimeUtc) { + this.InitializeContent(); + this.LoadContent(); + this.lastWriteTimeUtc = File.GetLastWriteTimeUtc(this.FileName); + } + } + + // ******************************************************************************************************************************** + + /// + /// Initializes all instance fields in preparation for loading of the file content. + /// + protected virtual void InitializeContent() + { + this.data = new Dictionary(); + } + + /// + /// Loads the content of the specified into the cache. + /// + /// The to be used to read the resource content. + protected virtual void LoadContent(IResourceReader reader) + { + IDictionaryEnumerator en = reader.GetEnumerator(); + while (en.MoveNext()) { + this.data.Add((string)en.Key, en.Value); + } + } + + /// + /// Loads the content of the file into the cache. + /// + protected virtual void LoadContent() + { + using(IResourceReader reader = this.GetResourceReader()) { + if (reader != null) { + this.LoadContent(reader); + reader.Close(); + } + } + } + + /// + /// Gets a resource reader for the resource file represented by this instance. + /// + /// A resource reader for the resource file represented by this instance. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + protected virtual IResourceReader GetResourceReader() + { + return new ResourceReader(this.FileName); + } + + // ******************************************************************************************************************************** + + /// + /// Save changes done to the resource content to disk. + /// + protected void Save() + { + this.SaveContent(); + this.lastWriteTimeUtc = File.GetLastWriteTimeUtc(this.FileName); + } + + /// + /// Save changes done to the resource content to disk. + /// + protected virtual void SaveContent() + { + using(IResourceWriter writer = this.GetResourceWriter()) { + if (writer != null) { + this.SaveContent(writer); + writer.Close(); + } + } + } + + /// + /// Save changes done to the resource content to disk. + /// + /// The to be used to save the resource content. + protected virtual void SaveContent(IResourceWriter writer) + { + foreach (KeyValuePair entry in this.data) { + writer.AddResource(entry.Key, entry.Value); + } + } + + /// + /// Gets a resource writer for the resource file represented by this instance. + /// + /// A resource writer for the resource file represented by this instance. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + protected virtual IResourceWriter GetResourceWriter() + { + return new ResourceWriter(this.FileName); + } + + // ******************************************************************************************************************************** + + /// + /// Gets an iterator that can be used to iterate over all key/value pairs in this resource. + /// + public IEnumerable> Data { + get { + this.EnsureLoaded(); + return this.data; + } + } + + /// + /// Determines if the resource file this instance represents contains the specified key. + /// + public bool ContainsKey(string key) + { + this.EnsureLoaded(); + return this.data.ContainsKey(key); + } + + /// + /// Tries to get the value of the resource with the specified key. + /// + /// true, if the key exists, otherwise false. + public bool TryGetValue(string key, out object value) + { + this.EnsureLoaded(); + return this.data.TryGetValue(key, out value); + } + + /// + /// Adds a new key to the resource file. + /// + /// A key with the same name already exists. + public void Add(string key, object value) + { + this.EnsureLoaded(); + if (this.data.ContainsKey(key)) { + throw new ArgumentException("A key with the name '"+key+"' already exists.", "key"); + } + this.data.Add(key, value); + this.Save(); + } + + /// + /// Modify the value of an existing entry. + /// + /// The specified key does not exist. + public void SetValue(string key, object value) + { + this.EnsureLoaded(); + if (!this.data.ContainsKey(key)) { + throw new ArgumentException("The key '"+key+"' does not exist.", "key"); + } + this.data[key] = value; + this.Save(); + } + + /// + /// Renames a resource key. + /// + /// The old name of the resource key to rename. + /// The new name of the resource key. + /// The specified key does not exist or the new key does already exist. + public void RenameKey(string oldName, string newName) + { + this.EnsureLoaded(); + if (!this.data.ContainsKey(oldName)) { + throw new ArgumentException("The key '"+oldName+"' does not exist.", "oldName"); + } + if (this.data.ContainsKey(newName)) { + throw new ArgumentException("The key '"+newName+"' already exists.", "newName"); + } + this.data.Add(newName, this.data[oldName]); + this.data.Remove(oldName); + this.Save(); + } + + /// + /// Removes the specified resource key permanently. + /// + /// The resource key to remove. + /// The specified key does not exist. + public void RemoveKey(string key) + { + this.EnsureLoaded(); + if (!this.data.ContainsKey(key)) { + throw new ArgumentException("The key '"+key+"' does not exist.", "key"); + } + this.data.Remove(key); + this.Save(); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs new file mode 100644 index 0000000000..0c0eed19b3 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ResourceResolverService.cs @@ -0,0 +1,136 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Text; + +using ICSharpCode.Core; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; + +using Hornung.ResourceToolkit.Resolver; +using Hornung.ResourceToolkit.ResourceFileContent; + +namespace Hornung.ResourceToolkit +{ + /// + /// Provides facilities to find and resolve expressions referencing resources. + /// + public static class ResourceResolverService + { + + /// + /// The AddIn tree path where the resource resolvers are registered. + /// + public const string ResourceResolversAddInTreePath = "/AddIns/ResourceToolkit/Resolvers"; + + // ******************************************************************************************************************************** + + static List resolvers; + + /// + /// Gets a list of all registered resource resolvers. + /// + public static IEnumerable Resolvers { + get { + if (resolvers == null) { + resolvers = AddInTree.BuildItems(ResourceResolversAddInTreePath, null, false); + } + return resolvers; + } + } + + // ******************************************************************************************************************************** + + /// + /// Attempts to resolve a reference to a resource using all registered resolvers. + /// + /// The text editor for which a resource resolution attempt should be performed. + /// A that describes which resource is referenced by the expression at the caret in the specified editor, or null if all registered resolvers return null. + public static ResourceResolveResult Resolve(TextEditorControl editor) + { + ResourceResolveResult result; + foreach (IResourceResolver resolver in Resolvers) { + if ((result = resolver.Resolve(editor)) != null) { + return result; + } + } + return null; + } + + /// + /// Attempts to resolve a reference to a resource using all registered resolvers. + /// + /// The name of the file that contains the expression to be resolved. + /// The document that contains the expression to be resolved. + /// The 0-based line in the file that contains the expression to be resolved. + /// The 0-based column position of the expression to be resolved. + /// A that describes which resource is referenced by the expression at the caret in the specified editor, or null if all registered resolvers return null. + public static ResourceResolveResult Resolve(string fileName, IDocument document, int caretLine, int caretColumn) + { + ResourceResolveResult result; + foreach (IResourceResolver resolver in Resolvers) { + if ((result = resolver.Resolve(fileName, document, caretLine, caretColumn)) != null) { + return result; + } + } + return null; + } + + // ******************************************************************************************************************************** + + /// + /// Builds the formatted description string for the specified resource. + /// + public static string FormatResourceDescription(IResourceFileContent content, string key) + { + StringBuilder sb = new StringBuilder(); + + IMultiResourceFileContent mrfc; + if (key != null && (mrfc = (content as IMultiResourceFileContent)) != null) { + string file = mrfc.GetFileNameForKey(key); + if (file == null) { + file = content.FileName; + } + sb.AppendFormat(StringParser.Parse("${res:Hornung.ResourceToolkit.ToolTips.PlaceMessage}"), file); + } else { + sb.AppendFormat(StringParser.Parse("${res:Hornung.ResourceToolkit.ToolTips.PlaceMessage}"), content.FileName); + } + + sb.AppendLine(); + sb.Append(StringParser.Parse("${res:Hornung.ResourceToolkit.KeyLabel}")); + sb.Append(' '); + + if (key != null) { + + sb.AppendLine(key); + sb.AppendLine(); + sb.AppendLine(StringParser.Parse("${res:Hornung.ResourceToolkit.ValueLabel}")); + + object value; + if (content.TryGetValue(key, out value)) { + if (value is string) { + sb.Append(value); + } else { + sb.AppendFormat(StringParser.Parse("${res:Hornung.ResourceToolkit.ToolTips.TypeMessage}"), value.GetType().ToString()); + sb.Append(' '); + sb.Append(value.ToString()); + } + } else { + sb.Append(StringParser.Parse("${res:Hornung.ResourceToolkit.ToolTips.KeyNotFound}")); + } + + } else { + sb.Append(StringParser.Parse("${res:Hornung.ResourceToolkit.ToolTips.UnknownKey}")); + } + + return sb.ToString(); + } + + } +} diff --git a/src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs b/src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs new file mode 100644 index 0000000000..1aaad44e38 --- /dev/null +++ b/src/AddIns/Misc/ResourceToolkit/Project/Src/ToolTips/ResourceToolTipProvider.cs @@ -0,0 +1,48 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Drawing; +using System.Windows.Forms; + +using ICSharpCode.Core; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; +using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; + +using Hornung.ResourceToolkit.Resolver; + +namespace Hornung.ResourceToolkit.ToolTips +{ + /// + /// Provides tooltips for resources. + /// + public class ResourceToolTipProvider : ITextAreaToolTipProvider + { + + public ToolTipInfo GetToolTipInfo(TextArea textArea, ToolTipRequestEventArgs e) + { + Point logicPos = e.LogicalPosition; + IDocument doc = textArea.Document; + if (logicPos.X > doc.GetLineSegment(logicPos.Y).Length - 1) { + return null; + } + + ResourceResolveResult result = ResourceResolverService.Resolve(textArea.MotherTextEditorControl.FileName, doc, logicPos.Y, logicPos.X); + + if (result != null && result.ResourceFileContent != null) { + #if DEBUG + LoggingService.Debug("ResourceToolkit: Providing ToolTipInfo"); + #endif + return new ToolTipInfo(ResourceResolverService.FormatResourceDescription(result.ResourceFileContent, result.Key)); + } + + return null; + } + + } +} diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index de723432e0..bd4e241ebe 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -744,4 +744,4 @@ - + \ No newline at end of file diff --git a/src/Main/StartUp/Project/Resources/StringResources.resources b/src/Main/StartUp/Project/Resources/StringResources.resources index 93e8457f9ea29dadbdeac52cfcb5610e5eeafb6e..386777cb2a473f38351a47a756dd076ad750ae11 100644 GIT binary patch delta 32639 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 delta 28484 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 I>pk%Q0RKW)LjV8( diff --git a/src/SharpDevelop.sln b/src/SharpDevelop.sln index ab90db3d70..8fb099a6a8 100644 --- a/src/SharpDevelop.sln +++ b/src/SharpDevelop.sln @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 9.00 -# SharpDevelop 2.1.0.1793 +# SharpDevelop 2.1.0.1865 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AddIns", "AddIns", "{14A277EE-7DF1-4529-B639-7D1EF334C1C5}" ProjectSection(SolutionItems) = postProject EndProjectSection @@ -56,6 +56,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{CE5B42B7-6 ProjectSection(SolutionItems) = postProject EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResourceToolkit", "AddIns\Misc\ResourceToolkit\Project\ResourceToolkit.csproj", "{461606BD-E824-4D0A-8CBA-01810B1F5E02}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpDbTools", "AddIns\Misc\SharpServerTools\SharpDbTools\SharpDbTools.csproj", "{F2CC804D-5A9C-4875-A423-4FB9A5D07018}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpServerTools", "AddIns\Misc\SharpServerTools\SharpServerTools.csproj", "{E8922383-B6F5-4107-AB82-49662D98B2FE}" @@ -376,6 +378,10 @@ Global {F2CC804D-5A9C-4875-A423-4FB9A5D07018}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2CC804D-5A9C-4875-A423-4FB9A5D07018}.Release|Any CPU.Build.0 = Release|Any CPU {F2CC804D-5A9C-4875-A423-4FB9A5D07018}.Release|Any CPU.ActiveCfg = Release|Any CPU + {461606BD-E824-4D0A-8CBA-01810B1F5E02}.Debug|Any CPU.Build.0 = Debug|Any CPU + {461606BD-E824-4D0A-8CBA-01810B1F5E02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {461606BD-E824-4D0A-8CBA-01810B1F5E02}.Release|Any CPU.Build.0 = Release|Any CPU + {461606BD-E824-4D0A-8CBA-01810B1F5E02}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2} = {14A277EE-7DF1-4529-B639-7D1EF334C1C5} @@ -419,6 +425,7 @@ Global {BDDDCD01-D2FE-4EAD-9425-4B6B91922C7C} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2} {E8922383-B6F5-4107-AB82-49662D98B2FE} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2} {F2CC804D-5A9C-4875-A423-4FB9A5D07018} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2} + {461606BD-E824-4D0A-8CBA-01810B1F5E02} = {CE5B42B7-6E8C-4385-9E97-F4023FC16BF2} {000E4F64-5D0D-4EB1-B0BF-1A62ADBC6EAD} = {BDDDCD01-D2FE-4EAD-9425-4B6B91922C7C} {869951D5-A0D6-4DC6-9F1D-E6B9A12AC446} = {BDDDCD01-D2FE-4EAD-9425-4B6B91922C7C} {E6F4983F-DE41-4AEC-88E7-1FA9AFB4E6FF} = {BDDDCD01-D2FE-4EAD-9425-4B6B91922C7C}