You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
214 lines
7.6 KiB
214 lines
7.6 KiB
// <file> |
|
// <copyright see="prj:///doc/copyright.txt"/> |
|
// <license see="prj:///doc/license.txt"/> |
|
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/> |
|
// <version>$Revision$</version> |
|
// </file> |
|
|
|
using System; |
|
using System.CodeDom; |
|
using System.CodeDom.Compiler; |
|
using System.Collections.Generic; |
|
using System.ComponentModel.Design.Serialization; |
|
using System.IO; |
|
using System.Text; |
|
using Boo.Lang.Compiler.Ast; |
|
using Boo.Lang.Parser; |
|
using ICSharpCode.Core; |
|
using ICSharpCode.FormsDesigner; |
|
using ICSharpCode.SharpDevelop; |
|
using ICSharpCode.SharpDevelop.Dom; |
|
using ICSharpCode.TextEditor; |
|
|
|
namespace Grunwald.BooBinding.Designer |
|
{ |
|
public class BooDesignerLoader : AbstractCodeDomDesignerLoader |
|
{ |
|
protected override bool IsReloadNeeded() |
|
{ |
|
return base.IsReloadNeeded() || this.Generator.ViewContent.DesignerCodeFileContent != lastTextContent; |
|
} |
|
|
|
public BooDesignerLoader(IDesignerGenerator generator) |
|
: base(generator) |
|
{ |
|
} |
|
|
|
string lastTextContent; |
|
Module parsedModule; |
|
|
|
protected override CodeCompileUnit Parse() |
|
{ |
|
LoggingService.Debug("BooDesignerLoader.Parse()"); |
|
try { |
|
CodeCompileUnit ccu = ParseForm(); |
|
LoggingService.Debug("BooDesignerLoader.Parse() finished"); |
|
// Clear the cached module after loading has finished |
|
this.parsedModule = null; |
|
return ccu; |
|
} catch (Boo.Lang.Compiler.CompilerError ex) { |
|
throw new FormsDesignerLoadException(ex.ToString(true)); |
|
} |
|
} |
|
|
|
CodeCompileUnit ParseForm() |
|
{ |
|
ParseInformation parseInfo = ParserService.ParseFile(this.Generator.ViewContent.DesignerCodeFile.FileName, this.Generator.ViewContent.DesignerCodeFileContent, false); |
|
Module module = ParseFormAsModule(); |
|
|
|
#if DEBUG |
|
Console.WriteLine(module.ToCodeString()); |
|
#endif |
|
|
|
CodeDomVisitor visitor = new CodeDomVisitor(parseInfo.MostRecentCompilationUnit.ProjectContent); |
|
module.Accept(visitor); |
|
|
|
#if DEBUG |
|
// output generated CodeDOM to the console : |
|
ICSharpCode.NRefactory.Visitors.CodeDomVerboseOutputGenerator outputGenerator = new ICSharpCode.NRefactory.Visitors.CodeDomVerboseOutputGenerator(); |
|
outputGenerator.GenerateCodeFromMember(visitor.OutputCompileUnit.Namespaces[0].Types[0], Console.Out, null); |
|
CodeDomProvider cSharpProvider = new Microsoft.CSharp.CSharpCodeProvider(); |
|
cSharpProvider.GenerateCodeFromCompileUnit(visitor.OutputCompileUnit, Console.Out, null); |
|
#endif |
|
|
|
return visitor.OutputCompileUnit; |
|
} |
|
|
|
Module ParseFormAsModule() |
|
{ |
|
// The module is cached while loading so that |
|
// determining the localization model and generating the CodeDOM |
|
// does not require the code to be parsed twice. |
|
if (this.parsedModule != null && lastTextContent == this.Generator.ViewContent.DesignerCodeFileContent) { |
|
return this.parsedModule; |
|
} |
|
|
|
lastTextContent = this.Generator.ViewContent.DesignerCodeFileContent; |
|
|
|
ParseInformation parseInfo = ParserService.ParseFile(this.Generator.ViewContent.DesignerCodeFile.FileName, this.Generator.ViewContent.DesignerCodeFileContent, false); |
|
// ensure that there are no syntax errors in the file: |
|
Module mainModule = Parse(this.Generator.ViewContent.DesignerCodeFile.FileName, lastTextContent); |
|
|
|
IClass formClass; |
|
bool isFirstClassInFile; |
|
IList<IClass> parts = NRefactoryDesignerLoader.FindFormClassParts(parseInfo, out formClass, out isFirstClassInFile); |
|
|
|
IMethod initMethod = FormsDesignerSecondaryDisplayBinding.GetInitializeComponents(formClass); |
|
|
|
if (initMethod == null) |
|
throw new FormsDesignerLoadException("The InitializeComponent method was not found. Designer cannot be loaded."); |
|
|
|
Module module = new Module(); |
|
module.Namespace = new NamespaceDeclaration(formClass.Namespace); |
|
ClassDefinition cld = new ClassDefinition(); |
|
cld.Name = formClass.Name; |
|
module.Members.Add(cld); |
|
if (formClass.BaseClass == null) |
|
throw new FormsDesignerLoadException("formClass.BaseClass returned null."); |
|
cld.BaseTypes.Add(new SimpleTypeReference(formClass.BaseClass.FullyQualifiedName)); |
|
|
|
System.Diagnostics.Debug.Assert(FileUtility.IsEqualFileName(initMethod.DeclaringType.CompilationUnit.FileName, this.Generator.ViewContent.DesignerCodeFile.FileName)); |
|
|
|
foreach (IField f in formClass.Fields) { |
|
Field field = new Field(); |
|
field.Name = f.Name; |
|
if (f.ReturnType.IsDefaultReturnType) { |
|
field.Type = new SimpleTypeReference(f.ReturnType.FullyQualifiedName); |
|
} |
|
field.Modifiers = CodeCompletion.ConvertVisitor.ConvertVisibilityBack(f.Modifiers); |
|
cld.Members.Add(field); |
|
} |
|
|
|
// Now find InitializeComponent in parsed module and put it into our new module |
|
foreach (TypeMember m in mainModule.Members) { |
|
TypeDefinition td = m as TypeDefinition; |
|
if (td == null) |
|
continue; |
|
foreach (TypeMember m2 in td.Members) { |
|
Method method = m2 as Method; |
|
if (method != null |
|
&& FormsDesignerSecondaryDisplayBinding.IsInitializeComponentsMethodName(method.Name) |
|
&& method.Parameters.Count == 0) |
|
{ |
|
cld.Members.Add(method); |
|
this.parsedModule = module; |
|
return module; |
|
} |
|
} |
|
} |
|
throw new FormsDesignerLoadException("Could not find InitializeComponent in parsed module."); |
|
} |
|
|
|
static Module Parse(string fileName, string fileContent) |
|
{ |
|
BooParsingStep step = new BooParsingStep(); |
|
|
|
StringBuilder errors = new StringBuilder(); |
|
Module module = BooParser.ParseModule(4, new CompileUnit(), fileName, |
|
new StringReader(fileContent), |
|
delegate(antlr.RecognitionException e) { |
|
errors.AppendLine(e.ToString()); |
|
}); |
|
|
|
if (errors.Length > 0) { |
|
throw new FormsDesignerLoadException("Syntax errors in " + fileName + ":\r\n" + errors.ToString()); |
|
} |
|
return module; |
|
} |
|
|
|
protected override void Write(CodeCompileUnit unit) |
|
{ |
|
LoggingService.Info("BooDesignerLoader.Write called"); |
|
try { |
|
this.Generator.MergeFormChanges(unit); |
|
} catch (Exception ex) { |
|
MessageService.ShowError(ex); |
|
} |
|
} |
|
|
|
protected override CodeDomLocalizationModel GetCurrentLocalizationModelFromDesignedFile() |
|
{ |
|
Module m = ParseFormAsModule(); |
|
FindLocalizationModelVisitor visitor = new FindLocalizationModelVisitor(); |
|
m.Accept(visitor); |
|
return visitor.Model; |
|
} |
|
|
|
sealed class FindLocalizationModelVisitor : DepthFirstVisitor |
|
{ |
|
CodeDomLocalizationModel model = CodeDomLocalizationModel.None; |
|
|
|
public CodeDomLocalizationModel Model { |
|
get { return this.model; } |
|
} |
|
|
|
public override bool EnterMethod(Method node) |
|
{ |
|
return node.Name == "InitializeComponent" || node.Name == "InitializeComponents"; |
|
} |
|
|
|
public override bool EnterBinaryExpression(BinaryExpression node) |
|
{ |
|
return this.model != CodeDomLocalizationModel.PropertyReflection && node.Operator == BinaryOperatorType.Assign; |
|
} |
|
|
|
public override bool EnterMethodInvocationExpression(MethodInvocationExpression node) |
|
{ |
|
if (this.model == CodeDomLocalizationModel.PropertyReflection) return false; |
|
|
|
MemberReferenceExpression member = node.Target as MemberReferenceExpression; |
|
if (member != null) { |
|
ReferenceExpression refex = member.Target as ReferenceExpression; |
|
if (refex != null && refex.Name.Equals("resources", StringComparison.InvariantCulture)) { |
|
if (member.Name.Equals("ApplyResources", StringComparison.InvariantCulture)) { |
|
this.model = CodeDomLocalizationModel.PropertyReflection; |
|
} else if (member.Name.Equals("GetString", StringComparison.InvariantCulture)) { |
|
this.model = CodeDomLocalizationModel.PropertyAssignment; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
} |
|
} |
|
}
|
|
|