Browse Source

The Python forms designer (currently disabled) now has limited support for designing very basic forms.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3738 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 17 years ago
parent
commit
e8fcd7c020
  1. 2
      src/AddIns/BackendBindings/Python/PyWalker/MainForm.cs
  2. 77
      src/AddIns/BackendBindings/Python/PyWalker/ResolveWalker.cs
  3. 4
      src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj
  4. 28
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/IComponentCreator.cs
  5. 125
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs
  6. 38
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerGenerator.cs
  7. 33
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerLoader.cs
  8. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonForm.cs
  9. 33
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormVisitor.cs
  10. 196
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormWalker.cs
  11. 21
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormWalkerException.cs
  12. 11
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormsDesignerDisplayBinding.cs
  13. 33
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonParser.cs
  14. 40
      src/AddIns/BackendBindings/Python/PythonBinding/Test/AddInFileTestFixture.cs
  15. 3
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs
  16. 8
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratorMergeFindsInitializeComponentsTestFixture.cs
  17. 62
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadFormTestFixtureBase.cs
  18. 67
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadSimpleFormTestFixture.cs
  19. 92
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadTextBoxTestFixture.cs
  20. 42
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/MergeFormTestFixture.cs
  21. 70
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/MissingInitializeComponentMethodTestFixture.cs
  22. 87
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/NoNewLineAfterInitializeComponentTestFixture.cs
  23. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderProviderTestFixture.cs
  24. 4
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs
  25. 73
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/TextBoxNotAddedToFormTestFixture.cs
  26. 85
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/TextEditorIndentPassedToGeneratorTestFixture.cs
  27. 46
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/UnknownTypeTestFixture.cs
  28. 4
      src/AddIns/BackendBindings/Python/PythonBinding/Test/FormsDesignerDisplayBindingTestFixture.cs
  29. 68
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/IronPythonParserTestFixture.cs
  30. 9
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
  31. 54
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/AddedComponent.cs
  32. 69
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CreatedInstance.cs
  33. 8
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedPythonDesignerGenerator.cs

2
src/AddIns/BackendBindings/Python/PyWalker/MainForm.cs

@ -48,7 +48,7 @@ namespace PyWalker @@ -48,7 +48,7 @@ namespace PyWalker
PythonAst ast = parser.ParseFile(false);
if (sink.Errors.Count == 0) {
ResolveWalker walker = new ResolveWalker(this);
walker.Walk(ast);
ast.Walk(walker);
} else {
walkerOutputTextBox.Text += "\r\n";
foreach (PythonCompilerError error in sink.Errors) {

77
src/AddIns/BackendBindings/Python/PyWalker/ResolveWalker.cs

@ -31,49 +31,43 @@ namespace PyWalker @@ -31,49 +31,43 @@ namespace PyWalker
public override bool Walk(AndExpression node)
{
writer.WriteLine("And");
return true;
return base.Walk(node);
}
public override bool Walk(AssertStatement node)
{
writer.WriteLine("Assert");
return true;
return base.Walk(node);
}
//public override bool Walk(AugAssignStatement node)
//{
// writer.WriteLine("AugAssert");
// return true;
//}
public override bool Walk(Arg node)
{
writer.WriteLine("Arg: " + node.Name.ToString());
return true;
return base.Walk(node);
}
// public override bool Walk(AssignStatement node)
// {
// writer.WriteLine("Assign");
// return true;
// }
public override bool Walk(AssignmentStatement node)
{
writer.WriteLine("AssignmentStatement");
return base.Walk(node);
}
public override bool Walk(BackQuoteExpression node)
{
writer.WriteLine("BackQuote");
return true;
return base.Walk(node);
}
public override bool Walk(BinaryExpression node)
{
writer.WriteLine("Binary");
return true;
return base.Walk(node);
}
public override bool Walk(BreakStatement node)
{
writer.WriteLine("Breaks");
return true;
return base.Walk(node);
}
public override bool Walk(ClassDefinition node)
@ -83,121 +77,109 @@ namespace PyWalker @@ -83,121 +77,109 @@ namespace PyWalker
} else {
writer.WriteLine("Class: " + node.Name.ToString());
}
return true;
return base.Walk(node);
}
public override bool Walk(ConditionalExpression node)
{
writer.WriteLine("ConditionalExpression");
return true;
return base.Walk(node);
}
public override bool Walk(ConstantExpression node)
{
writer.WriteLine("ConstantExpression");
return true;
return base.Walk(node);
}
public override bool Walk(ContinueStatement node)
{
writer.WriteLine("Continue");
return true;
return base.Walk(node);
}
public override bool Walk(PrintStatement node)
{
writer.WriteLine("PrintStatement");
return true;
return base.Walk(node);
}
public override bool Walk(FunctionDefinition node)
{
writer.WriteLine("FunctionDefinition");
return true;
return base.Walk(node);
}
public override bool Walk(CallExpression node)
{
writer.WriteLine("Call");
return true;
return base.Walk(node);
}
public override bool Walk(DictionaryExpression node)
{
writer.WriteLine("Dict");
return true;
return base.Walk(node);
}
public override bool Walk(DottedName node)
{
writer.WriteLine("DottedName");
return true;
return base.Walk(node);
}
public override bool Walk(ExpressionStatement node)
{
writer.WriteLine("Expr");
return true;
return base.Walk(node);
}
// public override bool Walk(FieldExpression node)
// {
// writer.WriteLine("Field: " + node.Name.ToString());
// return true;
// }
public override bool Walk(GlobalStatement node)
{
writer.WriteLine("Global");
return true;
return base.Walk(node);
}
public override bool Walk(NameExpression node)
{
writer.WriteLine("Name: " + node.Name);
return true;
return base.Walk(node);
}
public override bool Walk(FromImportStatement node)
{
writer.WriteLine("FromImport: " + node.Root.MakeString());
return true;
return base.Walk(node);
}
public override bool Walk(ImportStatement node)
{
writer.WriteLine("Import: " + GetImports(node.Names));
return true;
return base.Walk(node);
}
public override bool Walk(UnaryExpression node)
{
writer.WriteLine("Unary");
return true;
return base.Walk(node);
}
public override bool Walk(SuiteStatement node)
{
writer.WriteLine("Suite");
return true;
return base.Walk(node);
}
// public override bool Walk(GlobalSuite node)
// {
// writer.WriteLine("GlobalSuite");
// return true;
// }
public override bool Walk(ErrorExpression node)
{
writer.WriteLine("Error");
return true;
return base.Walk(node);
}
public override bool Walk(IfStatement node)
{
writer.WriteLine("If");
return true;
return base.Walk(node);
}
string GetImports(IList<DottedName> names)
@ -222,6 +204,5 @@ namespace PyWalker @@ -222,6 +204,5 @@ namespace PyWalker
}
return s.ToString();
}
}
}

4
src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj

@ -86,13 +86,15 @@ @@ -86,13 +86,15 @@
<Compile Include="Src\PythonConsoleCompletionDataProvider.cs" />
<Compile Include="Src\PythonConsoleHost.cs" />
<Compile Include="Src\PythonConsolePad.cs" />
<Compile Include="Src\PythonControlFieldExpression.cs" />
<Compile Include="Src\PythonDesignerGenerator.cs" />
<Compile Include="Src\PythonDesignerLoader.cs" />
<Compile Include="Src\PythonDesignerLoaderProvider.cs" />
<Compile Include="Src\PythonExpressionFinder.cs" />
<Compile Include="Src\PythonForm.cs" />
<Compile Include="Src\PythonFormsDesignerDisplayBinding.cs" />
<Compile Include="Src\PythonFormVisitor.cs" />
<Compile Include="Src\PythonFormWalker.cs" />
<Compile Include="Src\PythonFormWalkerException.cs" />
<Compile Include="Src\PythonLanguageBinding.cs" />
<Compile Include="Src\PythonOptionsPanel.cs" />
<Compile Include="Src\PythonOutputStream.cs" />

28
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/IComponentCreator.cs

@ -6,13 +6,19 @@ @@ -6,13 +6,19 @@
// </file>
using System;
using System.Collections;
using System.ComponentModel;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Interface that creates an IComponent given a type. Used by the PythonFormVisitor
/// class so it can be wired up to a IDesignerHost
/// Interface that can:
///
/// 1) Create an IComponent given a type.
/// 2) Create a new object given its type name.
///
/// Used by the PythonFormVisitor class so it can be wired up to an
/// IDesignerHost and an IDesignerSerializationManager.
/// </summary>
public interface IComponentCreator
{
@ -22,5 +28,23 @@ namespace ICSharpCode.PythonBinding @@ -22,5 +28,23 @@ namespace ICSharpCode.PythonBinding
/// <param name="componentClass">The type of the component to be created.</param>
/// <param name="name">The component name.</param>
IComponent CreateComponent(Type componentClass, string name);
/// <summary>
/// Adds a component to the component creator.
/// </summary>
void Add(IComponent component, string name);
/// <summary>
/// Creates a new instance of the object given its type.
/// </summary>
/// <param name="arguments">Arguments passed to the type's constructor.</param>
/// <param name="name">Name of the object.</param>
/// <param name="addToContainer">If set to true then the is added to the design container.</param>
object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer);
/// <summary>
/// Gets the type given its name.
/// </summary>
Type GetType(string typeName);
}
}

125
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using IronPython.Compiler.Ast;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Represents a member field expression in a Control or Form:
///
/// self._textBox1
/// self._textBox1.Name
/// </summary>
public class PythonControlFieldExpression
{
string memberName = String.Empty;
string fullMemberName = String.Empty;
PythonControlFieldExpression(string memberName, string fullMemberName)
{
this.memberName = memberName;
this.fullMemberName = fullMemberName;
}
public string MemberName {
get { return memberName; }
}
public string FullMemberName {
get { return fullMemberName; }
}
/// <summary>
/// Creates a PythonControlField from a member expression:
///
/// self._textBox1
/// self._textBox1.Name
/// </summary>
public static PythonControlFieldExpression Create(MemberExpression expression)
{
string memberName = expression.Name.ToString();
string fullMemberName = PythonControlFieldExpression.GetMemberName(expression);
return new PythonControlFieldExpression(memberName, fullMemberName);
}
/// <summary>
/// Gets the variable name from an expression of the form:
///
/// self._textBox1.Name
///
/// Returns "textBox1"
/// </summary>
public static string GetVariableNameFromSelfReference(string name)
{
int startIndex = name.IndexOf('.');
if (startIndex > 0) {
name = name.Substring(startIndex + 1);
int endIndex = name.IndexOf('.');
if (endIndex > 0) {
return GetVariableName(name.Substring(0, endIndex));
}
return String.Empty;
}
return name;
}
/// <summary>
/// Gets the variable name of the control being added.
/// </summary>
public static string GetControlNameBeingAdded(CallExpression node)
{
//if (node.Args.Length > 0) {
Arg arg = node.Args[0];
MemberExpression memberExpression = arg.Expression as MemberExpression;
return GetVariableName(memberExpression.Name.ToString());
//}
//return null;
}
/// <summary>
/// Removes the underscore from the variable name.
/// </summary>
public static string GetVariableName(string name)
{
if (!String.IsNullOrEmpty(name)) {
if (name.Length > 1) {
if (name[0] == '_') {
return name.Substring(1);
}
}
}
return name;
}
/// <summary>
/// Gets the fully qualified name being referenced in the MemberExpression.
/// </summary>
public static string GetMemberName(MemberExpression expression)
{
StringBuilder typeName = new StringBuilder();
while (expression != null) {
typeName.Insert(0, expression.Name);
typeName.Insert(0, ".");
NameExpression nameExpression = expression.Target as NameExpression;
expression = expression.Target as MemberExpression;
if (expression == null) {
if (nameExpression != null) {
typeName.Insert(0, nameExpression.Name);
}
}
}
return typeName.ToString();
}
}
}

38
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerGenerator.cs

@ -17,6 +17,7 @@ using System.Windows.Forms; @@ -17,6 +17,7 @@ using System.Windows.Forms;
using ICSharpCode.FormsDesigner;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
@ -39,9 +40,11 @@ namespace ICSharpCode.PythonBinding @@ -39,9 +40,11 @@ namespace ICSharpCode.PythonBinding
public class PythonDesignerGenerator : IPythonDesignerGenerator
{
FormsDesignerViewContent viewContent;
ITextEditorProperties textEditorProperties;
public PythonDesignerGenerator()
public PythonDesignerGenerator(ITextEditorProperties textEditorProperties)
{
this.textEditorProperties = textEditorProperties;
}
/// <summary>
@ -76,7 +79,7 @@ namespace ICSharpCode.PythonBinding @@ -76,7 +79,7 @@ namespace ICSharpCode.PythonBinding
public void MergeRootComponentChanges(IComponent component)
{
ParseInformation parseInfo = ParseFile(this.ViewContent.DesignerCodeFile.FileName, this.ViewContent.DesignerCodeFileContent);
Merge(component, ViewContent.DesignerCodeFileDocument, parseInfo.BestCompilationUnit);
Merge(component, ViewContent.DesignerCodeFileDocument, parseInfo.BestCompilationUnit, textEditorProperties);
}
/// <summary>
@ -85,21 +88,21 @@ namespace ICSharpCode.PythonBinding @@ -85,21 +88,21 @@ namespace ICSharpCode.PythonBinding
/// <param name="component">The root component in the designer host.</param>
/// <param name="document">The document that the generated code will be merged into.</param>
/// <param name="parseInfo">The current compilation unit for the <paramref name="document"/>.</param>
public static void Merge(IComponent component, IDocument document, ICompilationUnit compilationUnit)
public static void Merge(IComponent component, IDocument document, ICompilationUnit compilationUnit, ITextEditorProperties textEditorProperties)
{
// Get the document's initialize components method.
IMethod method = GetInitializeComponents(compilationUnit);
// Generate the python source code.
PythonForm pythonForm = new PythonForm("\t");
PythonForm pythonForm = new PythonForm(NRefactoryToPythonConverter.GetIndentString(textEditorProperties));
int indent = method.Region.BeginColumn;
string methodBody = pythonForm.GenerateInitializeComponentMethodBody(component as Form, indent);
Console.WriteLine("GeneratedCode: " + methodBody);
// Merge the code.
DomRegion methodRegion = GetBodyRegionInDocument(method);
int startOffset = document.PositionToOffset(new TextLocation(methodRegion.BeginColumn - 1, methodRegion.BeginLine - 1));
int endOffset = document.PositionToOffset(new TextLocation(methodRegion.EndColumn - 1, methodRegion.EndLine - 1));
int startOffset = GetStartOffset(document, methodRegion);
int endOffset = GetEndOffset(document, methodRegion);
document.Replace(startOffset, endOffset - startOffset, methodBody);
}
@ -232,5 +235,26 @@ namespace ICSharpCode.PythonBinding @@ -232,5 +235,26 @@ namespace ICSharpCode.PythonBinding
{
return unit.Classes[0];
}
/// <summary>
/// Gets the start offset of the region.
/// </summary>
static int GetStartOffset(IDocument document, DomRegion region)
{
return document.PositionToOffset(new TextLocation(region.BeginColumn - 1, region.BeginLine - 1));
}
/// <summary>
/// Gets the end offset of the region.
/// </summary>
static int GetEndOffset(IDocument document, DomRegion region)
{
TextLocation endLocation = new TextLocation(region.EndColumn - 1, region.EndLine - 1);
if (endLocation.Line >= document.TotalNumberOfLines) {
// At end of document.
return document.TextLength;
}
return document.PositionToOffset(endLocation);
}
}
}

33
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerLoader.cs

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
using System;
using System.CodeDom;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Security.Permissions;
@ -26,7 +27,8 @@ namespace ICSharpCode.PythonBinding @@ -26,7 +27,8 @@ namespace ICSharpCode.PythonBinding
public class PythonDesignerLoader : BasicDesignerLoader, IComponentCreator
{
IPythonDesignerGenerator generator;
IDesignerSerializationManager serializationManager;
public PythonDesignerLoader(IPythonDesignerGenerator generator)
{
if (generator == null) {
@ -52,6 +54,30 @@ namespace ICSharpCode.PythonBinding @@ -52,6 +54,30 @@ namespace ICSharpCode.PythonBinding
return base.LoaderHost.CreateComponent(componentClass, name);
}
/// <summary>
/// Adds a component.
/// </summary>
public void Add(IComponent component, string name)
{
base.LoaderHost.Container.Add(component, name);
}
/// <summary>
/// Creates a new instance of the specified type.
/// </summary>
public object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer)
{
return serializationManager.CreateInstance(type, arguments, name, addToContainer);
}
/// <summary>
/// Gets the type given its name.
/// </summary>
public Type GetType(string typeName)
{
return serializationManager.GetType(typeName);
}
/// <summary>
/// Passes the designer host's root component to the generator so it can update the
/// source code with changes made at design time.
@ -64,8 +90,9 @@ namespace ICSharpCode.PythonBinding @@ -64,8 +90,9 @@ namespace ICSharpCode.PythonBinding
protected override void PerformLoad(IDesignerSerializationManager serializationManager)
{
// Create designer root object.
PythonFormVisitor visitor = new PythonFormVisitor();
visitor.CreateForm("abc", this);
this.serializationManager = serializationManager;
PythonFormWalker visitor = new PythonFormWalker(this);
visitor.CreateForm(generator.ViewContent.DesignerCodeFileContent);
}
}
}

1
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonForm.cs

@ -65,6 +65,7 @@ namespace ICSharpCode.PythonBinding @@ -65,6 +65,7 @@ namespace ICSharpCode.PythonBinding
AppendControl(form);
AppendIndentedLine("self.ResumeLayout(False)");
AppendIndentedLine("self.PerformLayout()");
}
void AppendControl(Control control)

33
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormVisitor.cs

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Description of PythonFormVisitor.
/// </summary>
public class PythonFormVisitor
{
public PythonFormVisitor()
{
}
/// <summary>
/// Creates a form from python code.
/// </summary>
public Form CreateForm(string pythonCode, IComponentCreator componentCreator)
{
Form form = (Form)componentCreator.CreateComponent(typeof(Form), "MainForm");
form.Name = "MainForm";
return form;
}
}
}

196
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormWalker.cs

@ -0,0 +1,196 @@ @@ -0,0 +1,196 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using IronPython.Compiler.Ast;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Visits the code's Python AST and creates a Windows Form.
/// </summary>
public class PythonFormWalker : PythonWalker
{
Form form;
PythonControlFieldExpression fieldExpression;
IComponentCreator componentCreator;
bool walkingAssignment;
Dictionary<string, object> createdObjects = new Dictionary<string, object>();
public PythonFormWalker(IComponentCreator componentCreator)
{
this.componentCreator = componentCreator;
}
/// <summary>
/// Creates a form from python code.
/// </summary>
public Form CreateForm(string pythonCode)
{
PythonParser parser = new PythonParser();
PythonAst ast = parser.CreateAst(@"Form.py", pythonCode);
ast.Walk(this);
// Did we find the InitializeComponent method?
if (form == null) {
throw new PythonFormWalkerException("Unable to find InitializeComponents method.");
}
return form;
}
public override bool Walk(ClassDefinition node)
{
if (node.Body != null) {
node.Body.Walk(this);
}
return false;
}
public override bool Walk(FunctionDefinition node)
{
if (IsInitializeComponentMethod(node)) {
form = (Form)componentCreator.CreateComponent(typeof(Form), "MainForm");
node.Body.Walk(this);
}
return false;
}
public override bool Walk(AssignmentStatement node)
{
if (node.Left.Count > 0) {
MemberExpression memberExpression = node.Left[0] as MemberExpression;
if (memberExpression != null) {
fieldExpression = PythonControlFieldExpression.Create(memberExpression);
walkingAssignment = true;
node.Right.Walk(this);
walkingAssignment = false;
}
}
return false;
}
public override bool Walk(ConstantExpression node)
{
Control control = GetCurrentControl();
SetPropertyValue(control, fieldExpression.MemberName, node.Value);
return false;
}
Control GetCurrentControl()
{
string variableName = PythonControlFieldExpression.GetVariableNameFromSelfReference(fieldExpression.FullMemberName);
if (variableName.Length > 0) {
return GetControl(variableName);
}
return form;
}
public override bool Walk(CallExpression node)
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
string name = PythonControlFieldExpression.GetMemberName(memberExpression);
if (walkingAssignment) {
Type type = GetType(name);
List<object> args = GetArguments(node);
object instance = componentCreator.CreateInstance(type, args, fieldExpression.MemberName, false);
if (!SetPropertyValue(form, fieldExpression.MemberName, instance)) {
AddComponent(fieldExpression.MemberName, instance);
}
} else if (name == "self.Controls.Add") {
string controlName = PythonControlFieldExpression.GetControlNameBeingAdded(node);
form.Controls.Add(GetControl(controlName));
}
}
return false;
}
/// <summary>
/// Gets the arguments passed to the call expression.
/// </summary>
static List<object> GetArguments(CallExpression expression)
{
List<object> args = new List<object>();
foreach (Arg a in expression.Args) {
ConstantExpression constantExpression = a.Expression as ConstantExpression;
if (constantExpression != null) {
args.Add(constantExpression.Value);
}
}
return args;
}
static bool IsInitializeComponentMethod(FunctionDefinition node)
{
string name = node.Name.ToString().ToLowerInvariant();
return name == "initializecomponent" || name == "initializecomponents";
}
/// <summary>
/// Sets the value of a form's property.
/// </summary>
bool SetPropertyValue(Control control, string name, object @value)
{
PropertyInfo propertyInfo = control.GetType().GetProperty(name);
if (propertyInfo != null) {
propertyInfo.SetValue(control, @value, null);
return true;
}
return false;
}
Type GetType(string typeName)
{
Type type = componentCreator.GetType(typeName);
if (type == null) {
throw new PythonFormWalkerException(String.Format("Could not find type '{0}'.", typeName));
}
return type;
}
/// <summary>
/// Looks for the control with the specified name in the objects that have been
/// created whilst processing the InitializeComponent method.
/// </summary>
Control GetControl(string name)
{
object o = null;
if (createdObjects.TryGetValue(name, out o)) {
return o as Control;
}
return null;
}
/// <summary>
/// Adds a component to the list of created objects.
/// </summary>
void AddComponent(string name, object component)
{
string variableName = PythonControlFieldExpression.GetVariableName(name);
componentCreator.Add(component as IComponent, variableName);
createdObjects.Add(variableName, component);
}
static string GetFirstArgumentAsString(CallExpression node)
{
List<object> args = GetArguments(node);
if (args.Count > 0) {
return args[0] as String;
}
return null;
}
}
}

21
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormWalkerException.cs

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
namespace ICSharpCode.PythonBinding
{
/// <summary>
/// Exception thrown by the PythonFormWalker class.
/// </summary>
public class PythonFormWalkerException : Exception
{
public PythonFormWalkerException(string message) : base(message)
{
}
}
}

11
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormsDesignerDisplayBinding.cs

@ -7,12 +7,14 @@ @@ -7,12 +7,14 @@
using System;
using System.IO;
using ICSharpCode.FormsDesigner;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace ICSharpCode.PythonBinding
{
@ -44,8 +46,13 @@ namespace ICSharpCode.PythonBinding @@ -44,8 +46,13 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
public IViewContent[] CreateSecondaryViewContent(IViewContent viewContent)
{
return CreateSecondaryViewContent(viewContent, SharpDevelopTextEditorProperties.Instance);
}
public IViewContent[] CreateSecondaryViewContent(IViewContent viewContent, ITextEditorProperties textEditorProperties)
{
foreach (IViewContent existingView in viewContent.SecondaryViewContents) {
if (existingView.GetType() == typeof(FormsDesignerViewContent)) {
@ -54,7 +61,7 @@ namespace ICSharpCode.PythonBinding @@ -54,7 +61,7 @@ namespace ICSharpCode.PythonBinding
}
IDesignerLoaderProvider loader = new PythonDesignerLoaderProvider();
IDesignerGenerator generator = new PythonDesignerGenerator();
IDesignerGenerator generator = new PythonDesignerGenerator(textEditorProperties);
return new IViewContent[] { new FormsDesignerViewContent(viewContent, loader, generator) };
}

33
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonParser.cs

@ -75,30 +75,35 @@ namespace ICSharpCode.PythonBinding @@ -75,30 +75,35 @@ namespace ICSharpCode.PythonBinding
return false;
}
/// <summary>
/// Parses a python file and creates a PythonAst.
/// </summary>
public PythonAst CreateAst(string fileName, string fileContent)
{
if (scriptEngine == null) {
scriptEngine = IronPython.Hosting.Python.CreateEngine();
}
PythonCompilerSink sink = new PythonCompilerSink();
SourceUnit source = DefaultContext.DefaultPythonContext.CreateFileUnit(fileName, fileContent);
CompilerContext context = new CompilerContext(source, new PythonCompilerOptions(), sink);
using (Parser parser = Parser.CreateParser(context, new PythonOptions())) {
return parser.ParseFile(false);
}
}
/// <summary>
/// Parses the python code and returns an ICompilationUnit.
/// </summary>
public ICompilationUnit Parse(IProjectContent projectContent, string fileName, string fileContent)
{
if (fileContent != null) {
// try {
if (scriptEngine == null) {
scriptEngine = IronPython.Hosting.Python.CreateEngine();
}
PythonCompilerSink sink = new PythonCompilerSink();
SourceUnit source = DefaultContext.DefaultPythonContext.CreateFileUnit(fileName, fileContent);
CompilerContext context = new CompilerContext(source, new PythonCompilerOptions(), sink);
Parser parser = Parser.CreateParser(context, new PythonOptions());
PythonAst ast = parser.ParseFile(false);
PythonAst ast = CreateAst(fileName, fileContent);
PythonAstWalker walker = new PythonAstWalker(projectContent, fileName);
walker.Walk(ast);
return walker.CompilationUnit;
// } catch (PythonSyntaxErrorException) {
// Ignore parsing errors
// }
}
DefaultCompilationUnit compilationUnit = new DefaultCompilationUnit(projectContent);
compilationUnit.FileName = fileName;
return compilationUnit;

40
src/AddIns/BackendBindings/Python/PythonBinding/Test/AddInFileTestFixture.cs

@ -45,6 +45,8 @@ namespace PythonBinding.Tests @@ -45,6 +45,8 @@ namespace PythonBinding.Tests
Runtime formsDesignerRuntime;
Codon displayBindingCodon;
Codon convertCodeCodon;
Codon pythonFileIconCodon;
Codon pythonProjectIconCodon;
[TestFixtureSetUp]
public void SetupFixture()
@ -72,6 +74,8 @@ namespace PythonBinding.Tests @@ -72,6 +74,8 @@ namespace PythonBinding.Tests
compilingOptionsCodon = GetCodon("/SharpDevelop/BackendBindings/ProjectOptions/Python", "CompilingOptions");
debugOptionsCodon = GetCodon("/SharpDevelop/BackendBindings/ProjectOptions/Python", "DebugOptions");
convertCodeCodon = GetCodon("/SharpDevelop/Workbench/MainMenu/Tools/ConvertCode", "ConvertToPython");
pythonFileIconCodon = GetCodon("/Workspace/Icons", "PythonFileIcon");
pythonProjectIconCodon = GetCodon("/Workspace/Icons", "PythonProjectIcon");
// Get the PythonBinding runtime.
foreach (Runtime runtime in addin.Runtimes) {
@ -610,7 +614,43 @@ namespace PythonBinding.Tests @@ -610,7 +614,43 @@ namespace PythonBinding.Tests
Assert.AreEqual(".cs", csharpCondition["activeextension"]);
Assert.AreEqual(".vb", vbnetCondition["activeextension"]);
}
[Test]
public void PythonFileIconCodonExists()
{
Assert.IsNotNull(pythonFileIconCodon);
}
[Test]
public void PythonFileIconCodonExtensions()
{
Assert.AreEqual(".py", pythonFileIconCodon["extensions"]);
}
[Test]
public void PythonFileIconCodonResource()
{
Assert.AreEqual("Python.ProjectBrowser.File", pythonFileIconCodon["resource"]);
}
[Test]
public void PythonProjectIconCodonExists()
{
Assert.IsNotNull(pythonProjectIconCodon);
}
[Test]
public void PythonProjectIconCodonLanguage()
{
Assert.AreEqual("Python", pythonProjectIconCodon["language"]);
}
[Test]
public void PythonProjectIconCodonResource()
{
Assert.AreEqual("Python.ProjectBrowser.Project", pythonProjectIconCodon["resource"]);
}
/// <summary>
/// Gets the codon with the specified extension path and name.
/// </summary>

3
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs

@ -42,7 +42,8 @@ namespace PythonBinding.Tests.Designer @@ -42,7 +42,8 @@ namespace PythonBinding.Tests.Designer
" # \r\n" +
" self.ClientSize = System.Drawing.Size(284, 264)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.ResumeLayout(False)\r\n";
" self.ResumeLayout(False)\r\n" +
" self.PerformLayout()\r\n";
Assert.AreEqual(expectedCode, generatedPythonCode);
}

8
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratorMergeFindsInitializeComponentsTestFixture.cs

@ -35,6 +35,7 @@ namespace PythonBinding.Tests.Designer @@ -35,6 +35,7 @@ namespace PythonBinding.Tests.Designer
[TestFixtureSetUp]
public void SetUpFixture()
{
MockTextEditorProperties textEditorProperties = new MockTextEditorProperties();
generator = new DerivedPythonDesignerGenerator();
mockViewContent = new MockTextEditorViewContent();
viewContent = new FormsDesignerViewContent(mockViewContent, new MockOpenedFile("Test.py"));
@ -95,7 +96,9 @@ namespace PythonBinding.Tests.Designer @@ -95,7 +96,9 @@ namespace PythonBinding.Tests.Designer
"\t\t# \r\n" +
"\t\tself.ClientSize = System.Drawing.Size(499, 309)\r\n" +
"\t\tself.Name = \"MainForm\"\r\n" +
"\t\tself.ResumeLayout(False)\r\n";
"\t\tself.ResumeLayout(False)\r\n" +
"\t\tself.PerformLayout()\r\n";
Assert.AreEqual(expectedText, viewContent.DesignerCodeFileContent);
}
@ -123,7 +126,8 @@ namespace PythonBinding.Tests.Designer @@ -123,7 +126,8 @@ namespace PythonBinding.Tests.Designer
"\t\tself.SuspendLayout()\r\n" +
"\t\tself.ClientSize = System.Drawing.Size(499, 309)\r\n" +
"\t\tself.Name = 'MainForm'\r\n" +
"\t\tself.ResumeLayout(False)\r\n";
"\t\tself.ResumeLayout(False)\r\n" +
"\t\tself.PerformLayout()\r\n";
}
}
}

62
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadFormTestFixtureBase.cs

@ -6,9 +6,13 @@ @@ -6,9 +6,13 @@
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using PythonBinding.Tests.Utils;
@ -20,6 +24,9 @@ namespace PythonBinding.Tests.Designer @@ -20,6 +24,9 @@ namespace PythonBinding.Tests.Designer
public class LoadFormTestFixtureBase : IComponentCreator
{
List <CreatedComponent> createdComponents = new List<CreatedComponent>();
List <CreatedInstance> createdInstances = new List<CreatedInstance>();
List <AddedComponent> addedComponents = new List<AddedComponent>();
List<string> typeNames = new List<string>();
public LoadFormTestFixtureBase()
{
@ -31,12 +38,65 @@ namespace PythonBinding.Tests.Designer @@ -31,12 +38,65 @@ namespace PythonBinding.Tests.Designer
createdComponents.Add(c);
object instance = componentClass.Assembly.CreateInstance(componentClass.FullName);
Control control = instance as Control;
return (IComponent)instance;
}
public void Add(IComponent component, string name)
{
AddedComponent addedComponent = new AddedComponent(component, name);
addedComponents.Add(addedComponent);
}
public object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer)
{
CreatedInstance createdInstance = new CreatedInstance(type, arguments, name, addToContainer);
createdInstances.Add(createdInstance);
object[] argumentsArray = new object[arguments.Count];
arguments.CopyTo(argumentsArray, 0);
object o = type.Assembly.CreateInstance(type.FullName, true, BindingFlags.CreateInstance, null, argumentsArray, null, new object[0]);
createdInstance.Object = o;
return o;
}
public Type GetType(string typeName)
{
typeNames.Add(typeName);
// Lookup type in System.Windows.Forms assembly.
Type type = typeof(Form).Assembly.GetType(typeName);
if (type == null) {
// Lookup type System.Drawing assembly.
type = typeof(Size).Assembly.GetType(typeName);
}
return type;
}
protected List<CreatedComponent> CreatedComponents {
get { return createdComponents; }
}
protected List<AddedComponent> AddedComponents {
get { return addedComponents; }
}
protected List<CreatedInstance> CreatedInstances {
get { return createdInstances; }
}
protected List<string> TypeNames {
get { return typeNames; }
}
protected CreatedInstance GetCreatedInstance(Type type)
{
foreach (CreatedInstance instance in createdInstances) {
if (instance.InstanceType == type) {
return instance;
}
}
return null;
}
}
}

67
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadSimpleFormTestFixture.cs

@ -6,9 +6,11 @@ @@ -6,9 +6,11 @@
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
@ -18,26 +20,35 @@ namespace PythonBinding.Tests.Designer @@ -18,26 +20,35 @@ namespace PythonBinding.Tests.Designer
[TestFixture]
public class LoadSimpleFormTestFixture : LoadFormTestFixtureBase
{
string pythonCode = "def InitializeComponent(self):\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # MainForm\r\n" +
" # \r\n" +
" self.ClientSize = System.Drawing.Size(284, 264)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.ResumeLayout(False)\r\n";
string pythonCode = "class MainForm(System.Windows.Forms.Form):\r\n" +
" def InitializeComponent(self):\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # MainForm\r\n" +
" # \r\n" +
" self.ClientSize = System.Drawing.Size(300, 400)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.ResumeLayout(False)\r\n";
Form form;
CreatedComponent formComponent;
string typeName;
CreatedInstance instance;
[TestFixtureSetUp]
public void SetUpFixture()
{
PythonFormVisitor visitor = new PythonFormVisitor();
form = visitor.CreateForm(pythonCode, this);
PythonFormWalker walker = new PythonFormWalker(this);
form = walker.CreateForm(pythonCode);
if (CreatedComponents.Count > 0) {
formComponent = CreatedComponents[0];
}
if (TypeNames.Count > 0) {
typeName = TypeNames[0];
}
if (CreatedInstances.Count > 0) {
instance = CreatedInstances[0];
}
}
[TestFixtureTearDown]
@ -74,6 +85,42 @@ namespace PythonBinding.Tests.Designer @@ -74,6 +85,42 @@ namespace PythonBinding.Tests.Designer
public void ComponentType()
{
Assert.AreEqual("System.Windows.Forms.Form", formComponent.TypeName);
}
[Test]
public void FormClientSize()
{
Size size = new Size(300, 400);
Assert.AreEqual(size, form.ClientSize);
}
/// <summary>
/// The System.Drawing.Size type name should have been looked up by the PythonFormWalker when
/// parsing the InitializeComponent method.
/// </summary>
[Test]
public void TypeNameLookedUp()
{
Assert.AreEqual("System.Drawing.Size", typeName);
}
[Test]
public void OneObjectCreated()
{
Assert.AreEqual(1, CreatedInstances.Count);
}
[Test]
public void InstanceType()
{
List<object> args = new List<object>();
int width = 300;
int height = 400;
args.Add(width);
args.Add(height);
CreatedInstance expectedInstance = new CreatedInstance(typeof(Size), args, "ClientSize", false);
Assert.AreEqual(expectedInstance, instance);
}
}
}

92
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadTextBoxTestFixture.cs

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
[TestFixture]
public class LoadTextBoxTestFixture : LoadFormTestFixtureBase
{
string pythonCode = "class MainForm(System.Windows.Forms.Form):\r\n" +
" def InitializeComponent(self):\r\n" +
" self._textBox1 = System.Windows.Forms.TextBox()\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # textBox1\r\n" +
" # \r\n" +
" self._textBox1.Name = \"textBoxName\"\r\n" +
" # \r\n" +
" # form1\r\n" +
" # \r\n" +
" self.Name = \"form1\"\r\n" +
" self.Controls.Add(self._textBox1)\r\n" +
" self.ResumeLayout(False)\r\n";
Form form;
TextBox textBox;
[TestFixtureSetUp]
public void SetUpFixture()
{
PythonFormWalker walker = new PythonFormWalker(this);
form = walker.CreateForm(pythonCode);
if (form.Controls.Count > 0) {
textBox = form.Controls[0] as TextBox;
}
}
[TestFixtureTearDown]
public void TearDownFixture()
{
form.Dispose();
}
[Test]
public void TextBoxInstanceCreated()
{
CreatedInstance instance = new CreatedInstance(typeof(TextBox), new List<object>(), "_textBox1", false);
Assert.Contains(instance, CreatedInstances);
}
[Test]
public void AddedComponentsContainsTextBox()
{
CreatedInstance instance = GetCreatedInstance(typeof(TextBox));
AddedComponent component = new AddedComponent(instance.Object as IComponent, "textBox1");
Assert.Contains(component, AddedComponents);
}
[Test]
public void TextBoxAddedToForm()
{
Assert.IsNotNull(textBox);
}
[Test]
public void TextBoxObjectMatchesObjectAddedToComponentCreator()
{
CreatedInstance instance = GetCreatedInstance(typeof(TextBox));
Assert.AreSame(textBox, instance.Object as TextBox);
}
[Test]
public void TextBoxName()
{
Assert.AreEqual("textBoxName", textBox.Name);
}
}
}

42
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/MergeFormTestFixture.cs

@ -7,7 +7,10 @@ @@ -7,7 +7,10 @@
using System;
using System.CodeDom;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TextEditor;
@ -22,7 +25,6 @@ namespace PythonBinding.Tests.Designer @@ -22,7 +25,6 @@ namespace PythonBinding.Tests.Designer
/// can merge the changes into the text editor.
/// </summary>
[TestFixture]
[Ignore("Not ported")]
public class MergeFormTestFixture
{
IDocument document;
@ -30,25 +32,26 @@ namespace PythonBinding.Tests.Designer @@ -30,25 +32,26 @@ namespace PythonBinding.Tests.Designer
[TestFixtureSetUp]
public void SetUpFixture()
{
// using (TextEditorControl textEditor = new TextEditorControl()) {
// document = textEditor.Document;
// textEditor.Text = GetTextEditorCode();
//
// PythonParser parser = new PythonParser();
// ICompilationUnit textEditorCompileUnit = parser.Parse(new DefaultProjectContent(), @"test.py", document.TextContent);
//
// PythonProvider provider = new PythonProvider();
// CodeCompileUnit unit = provider.Parse(new StringReader(GetGeneratedCode()));
// GeneratedInitializeComponentMethod initComponentMethod = GeneratedInitializeComponentMethod.GetGeneratedInitializeComponentMethod(unit);
// initComponentMethod.Merge(document, textEditorCompileUnit);
// }
using (TextEditorControl textEditor = new TextEditorControl()) {
document = textEditor.Document;
textEditor.Text = GetTextEditorCode();
PythonParser parser = new PythonParser();
ICompilationUnit compilationUnit = parser.Parse(new DefaultProjectContent(), @"test.py", document.TextContent);
using (Form form = new Form()) {
form.Name = "MainForm";
form.ClientSize = new Size(499, 309);
PythonDesignerGenerator.Merge(form, document, compilationUnit, new MockTextEditorProperties());
}
}
}
[Test]
public void MergedDocumentText()
{
string expectedText = GetTextEditorCode().Replace(GetTextEditorInitializeComponentMethod(), GetGeneratedInitializeComponentMethod());
Assert.AreEqual(expectedText, document.TextContent);
}
@ -67,14 +70,13 @@ namespace PythonBinding.Tests.Designer @@ -67,14 +70,13 @@ namespace PythonBinding.Tests.Designer
{
return "\tdef InitializeComponent(self):\r\n" +
"\t\tself.SuspendLayout()\r\n" +
"\t\t#\r\n" +
"\t\t# \r\n" +
"\t\t# MainForm\r\n" +
"\t\t#\r\n" +
"\t\tself.AutoScaleDimensions = System.Drawing.SizeF(6, 13)\r\n" +
"\t\tself.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font\r\n" +
"\t\t# \r\n" +
"\t\tself.ClientSize = System.Drawing.Size(499, 309)\r\n" +
"\t\tself.Name = 'MainForm'\r\n" +
"\t\tself.ResumeLayout(False)\r\n";
"\t\tself.Name = \"MainForm\"\r\n" +
"\t\tself.ResumeLayout(False)\r\n" +
"\t\tself.PerformLayout()\r\n";
}
string GetTextEditorCode()

70
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/MissingInitializeComponentMethodTestFixture.cs

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using IronPython.Compiler.Ast;
using Microsoft.Scripting;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests that the PythonFormVisitor throws an exception if no InitializeComponent or
/// InitializeComponent method can be found.
/// </summary>
[TestFixture]
public class MissingInitializeComponentMethodTestFixture : LoadFormTestFixtureBase
{
string pythonCode = "from System.Windows.Forms import Form\r\n" +
"\r\n" +
"class MainForm(System.Windows.Forms.Form):\r\n" +
" def __init__(self):\r\n" +
" self.MissingMethod()\r\n" +
"\r\n" +
" def MissingMethod(self):\r\n" +
" pass\r\n";
[Test]
[ExpectedException(typeof(PythonFormWalkerException))]
public void PythonFormWalkerExceptionThrown()
{
PythonFormWalker walker = new PythonFormWalker(this);
walker.CreateForm(pythonCode);
Assert.Fail("Exception should have been thrown before this.");
}
/// <summary>
/// Check that the PythonFormWalker does not try to walk the class body if it is null.
/// </summary>
[Test]
public void ClassWithNoBody()
{
ClassDefinition classDef = new ClassDefinition(new SymbolId(10), null, null);
PythonFormWalker walker = new PythonFormWalker(this);
walker.Walk(classDef);
}
/// <summary>
/// Make sure we do not get an ArgumentOutOfRangeException when walking the
/// AssignmentStatement.
/// </summary>
[Test]
public void NoLeftHandSideExpressionsInAssignment()
{
List<Expression> lhs = new List<Expression>();
AssignmentStatement assign = new AssignmentStatement(lhs.ToArray(), null);
PythonFormWalker walker = new PythonFormWalker(this);
walker.Walk(assign);
}
}
}

87
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/NoNewLineAfterInitializeComponentTestFixture.cs

@ -0,0 +1,87 @@ @@ -0,0 +1,87 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.CodeDom;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests the code can be generated if there is no new line after the InitializeComponent method.
/// </summary>
[TestFixture]
public class NoNewLineAfterInitializeComponentMethodTestFixture
{
IDocument document;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (TextEditorControl textEditor = new TextEditorControl()) {
document = textEditor.Document;
textEditor.Text = GetTextEditorCode();
PythonParser parser = new PythonParser();
ICompilationUnit compilationUnit = parser.Parse(new DefaultProjectContent(), @"test.py", document.TextContent);
using (Form form = new Form()) {
form.Name = "MainForm";
form.ClientSize = new Size(499, 309);
PythonDesignerGenerator.Merge(form, document, compilationUnit, new MockTextEditorProperties());
}
}
}
[Test]
public void GeneratedCode()
{
string expectedCode = "from System.Windows.Forms import Form\r\n" +
"\r\n" +
"class MainForm(Form):\r\n" +
"\tdef __init__(self):\r\n" +
"\t\tself.InitializeComponent()\r\n" +
"\t\r\n" +
"\tdef InitializeComponent(self):\r\n" +
"\t\tself.SuspendLayout()\r\n" +
"\t\t# \r\n" +
"\t\t# MainForm\r\n" +
"\t\t# \r\n" +
"\t\tself.ClientSize = System.Drawing.Size(499, 309)\r\n" +
"\t\tself.Name = \"MainForm\"\r\n" +
"\t\tself.ResumeLayout(False)\r\n" +
"\t\tself.PerformLayout()\r\n";
Assert.AreEqual(expectedCode, document.TextContent);
}
/// <summary>
/// No new line after the pass statement for InitializeComponent method.
/// </summary>
string GetTextEditorCode()
{
return "from System.Windows.Forms import Form\r\n" +
"\r\n" +
"class MainForm(Form):\r\n" +
"\tdef __init__(self):\r\n" +
"\t\tself.InitializeComponent()\r\n" +
"\t\r\n" +
"\tdef InitializeComponent(self):\r\n" +
"\t\tpass";
}
}
}

2
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderProviderTestFixture.cs

@ -25,7 +25,7 @@ namespace PythonBinding.Tests.Designer @@ -25,7 +25,7 @@ namespace PythonBinding.Tests.Designer
public void SetUpFixture()
{
provider = new PythonDesignerLoaderProvider();
generator = new PythonDesignerGenerator();
generator = new PythonDesignerGenerator(null);
}
[Test]

4
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs

@ -132,9 +132,9 @@ namespace PythonBinding.Tests.Designer @@ -132,9 +132,9 @@ namespace PythonBinding.Tests.Designer
"\r\n" +
"class MainForm(Form):\r\n" +
"\tdef __init__(self):\r\n" +
"\t\tself.InitializeComponent()\r\n" +
"\t\tself.InitializeComponents()\r\n" +
"\t\r\n" +
"\tdef InitializeComponent(self):\r\n" +
"\tdef InitializeComponents(self):\r\n" +
"\t\tself.Name = 'MainForm'\r\n";
}
}

73
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/TextBoxNotAddedToFormTestFixture.cs

@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// When a text box is not added to the form's Control collection in InitializeComponent then:
///
/// 1) Text box should not be added to the form's Control collection when the form is created.
/// 2) Text box should be registered with the designer via the IComponentCreator.Add method.
/// 3) Text box should be created via the IComponentCreator.CreateInstance method.
/// </summary>
[TestFixture]
public class TextBoxNotAddedToFormTestFixture : LoadFormTestFixtureBase
{
string pythonCode = "class MainForm(System.Windows.Forms.Form):\r\n" +
" def InitializeComponent(self):\r\n" +
" self._textBox1 = System.Windows.Forms.TextBox()\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # textBox1\r\n" +
" # \r\n" +
" self._textBox1.Name = \"textBox1\"\r\n" +
" # \r\n" +
" # form1\r\n" +
" # \r\n" +
" self.ResumeLayout(False)\r\n";
Form form;
[TestFixtureSetUp]
public void SetUpFixture()
{
PythonFormWalker walker = new PythonFormWalker(this);
form = walker.CreateForm(pythonCode);
}
[TestFixtureTearDown]
public void TearDownFixture()
{
form.Dispose();
}
[Test]
public void AddedComponentsContainsTextBox()
{
CreatedInstance instance = GetCreatedInstance(typeof(TextBox));
AddedComponent c = new AddedComponent(instance.Object as IComponent, "textBox1");
Assert.Contains(c, AddedComponents);
}
[Test]
public void TextBoxIsNotAddedToForm()
{
Assert.AreEqual(0, form.Controls.Count);
}
}
}

85
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/TextEditorIndentPassedToGeneratorTestFixture.cs

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.CodeDom;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.FormsDesigner;
using ICSharpCode.PythonBinding;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests that the indent information in the ITextEditorProperties is passed to the generator.
/// </summary>
[TestFixture]
public class TextEditorIndentPassedToGeneratorTestFixture
{
IDocument document;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (FormsDesignerViewContent viewContent = new FormsDesignerViewContent(null, new MockOpenedFile("Test.py"))) {
viewContent.DesignerCodeFileContent = "class MainForm(Form):\r\n" +
" def __init__(self):\r\n" +
" self.InitializeComponent()\r\n" +
"\r\n" +
" def InitializeComponent(self):\r\n" +
" pass\r\n";
document = viewContent.DesignerCodeFileDocument;
ParseInformation parseInfo = new ParseInformation();
PythonParser parser = new PythonParser();
ICompilationUnit compilationUnit = parser.Parse(new DefaultProjectContent(), @"test.py", document.TextContent);
parseInfo.SetCompilationUnit(compilationUnit);
using (Form form = new Form()) {
form.Name = "MainForm";
MockTextEditorProperties textEditorProperties = new MockTextEditorProperties();
textEditorProperties.ConvertTabsToSpaces = true;
textEditorProperties.IndentationSize = 1;
DerivedPythonDesignerGenerator generator = new DerivedPythonDesignerGenerator(textEditorProperties);
generator.ParseInfoToReturnFromParseFileMethod = parseInfo;
generator.Attach(viewContent);
generator.MergeRootComponentChanges(form);
}
}
}
[Test]
public void GeneratedCode()
{
string expectedCode = "class MainForm(Form):\r\n" +
" def __init__(self):\r\n" +
" self.InitializeComponent()\r\n" +
"\r\n" +
" def InitializeComponent(self):\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # MainForm\r\n" +
" # \r\n" +
" self.ClientSize = System.Drawing.Size(284, 264)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.ResumeLayout(False)\r\n" +
" self.PerformLayout()\r\n";
Assert.AreEqual(expectedCode, document.TextContent);
}
}
}

46
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/UnknownTypeTestFixture.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using IronPython.Compiler.Ast;
using Microsoft.Scripting;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests that the PythonFormWalker throws a PythonFormWalkerException if a unknown type is used in the
/// form.
/// </summary>
[TestFixture]
public class UnknownTypeTestFixture : LoadFormTestFixtureBase
{
string pythonCode = "from System.Windows.Forms import Form\r\n" +
"\r\n" +
"class MainForm(System.Windows.Forms.Form):\r\n" +
" def __init__(self):\r\n" +
" self.InitializeComponent()\r\n" +
"\r\n" +
" def InitializeComponent(self):\r\n" +
" self.ClientSize = Unknown.Type(10)\r\n";
[Test]
[ExpectedException(typeof(PythonFormWalkerException))]
public void PythonFormWalkerExceptionThrown()
{
PythonFormWalker walker = new PythonFormWalker(this);
walker.CreateForm(pythonCode);
Assert.Fail("Exception should have been thrown before this.");
}
}
}

4
src/AddIns/BackendBindings/Python/PythonBinding/Test/FormsDesignerDisplayBindingTestFixture.cs

@ -120,7 +120,7 @@ namespace PythonBinding.Tests @@ -120,7 +120,7 @@ namespace PythonBinding.Tests
public void CreatesPythonFormsDesigner()
{
MockTextEditorViewContent view = new MockTextEditorViewContent();
IViewContent[] views = displayBinding.CreateSecondaryViewContent(view);
IViewContent[] views = displayBinding.CreateSecondaryViewContent(view, new MockTextEditorProperties());
Assert.AreEqual(1, views.Length);
Assert.IsTrue(views[0] is FormsDesignerViewContent);
views[0].Dispose();
@ -133,7 +133,7 @@ namespace PythonBinding.Tests @@ -133,7 +133,7 @@ namespace PythonBinding.Tests
IViewContent[] views = null;
using (FormsDesignerViewContent formsDesigner = new FormsDesignerViewContent(view, new MockOpenedFile("test.py"))) {
view.SecondaryViewContents.Add(formsDesigner);
views = displayBinding.CreateSecondaryViewContent(view);
views = displayBinding.CreateSecondaryViewContent(view, new MockTextEditorProperties());
}
Assert.AreEqual(0, views.Length);
}

68
src/AddIns/BackendBindings/Python/PythonBinding/Test/Parsing/IronPythonParserTestFixture.cs

@ -1,68 +0,0 @@ @@ -1,68 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using Microsoft.Scripting.Runtime;
using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.IO;
using IronPython;
using IronPython.Compiler;
using IronPython.Compiler.Ast;
using IronPython.Runtime;
using NUnit.Framework;
namespace PythonBinding.Tests.Parsing
{
/// <summary>
/// Tests the IronPython's parser.
/// </summary>
[TestFixture]
public class IronPythonParserTestFixture
{
/// <summary>
/// Cannot create PrintStatement for code com.
/// </summary>
// [Test]s
// public void Test()
// {
// string pythonScript = "print 'Hello'";
// PythonProvider provider = new PythonProvider();
// CodeCompileUnit unit = provider.Parse(new StringReader(pythonScript));
// }
[Test]
public void Test2()
{
// string pythonScript = "print 'Hello'";
// CompilerContext context = new CompilerContext();
// Parser parser = Parser.FromString(null, context, pythonScript);
// Statement statement = parser.ParseFileInput();
}
[Test]
public void Test3()
{
// string pythonScript = "Console.WriteLine";
// CompilerContext context = new CompilerContext();
// Parser parser = Parser.FromString(null, context, pythonScript);
// Statement statement = parser.ParseFileInput();
// ResolveVisitor visitor = new ResolveVisitor();
// statement.Walk(visitor);
// Console.WriteLine(statement.GetType().FullName);
}
}
public class ResolveVisitor : PythonWalker
{
public override bool Walk(NameExpression node)
{
System.Console.WriteLine("NameExpression: " + node.Name);
return true;
}
}
}

9
src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

@ -151,13 +151,19 @@ @@ -151,13 +151,19 @@
<Compile Include="Designer\IsFullyQualifiedBaseClassFormDesignableTestFixture.cs" />
<Compile Include="Designer\LoadFormTestFixtureBase.cs" />
<Compile Include="Designer\LoadSimpleFormTestFixture.cs" />
<Compile Include="Designer\LoadTextBoxTestFixture.cs" />
<Compile Include="Designer\MergeFormTestFixture.cs" />
<Compile Include="Designer\MissingInitializeComponentMethodTestFixture.cs" />
<Compile Include="Designer\NoNewLineAfterInitializeComponentTestFixture.cs" />
<Compile Include="Designer\OneCompatibleMethodTestFixture.cs" />
<Compile Include="Designer\PythonGeneratorTestFixture.cs" />
<Compile Include="Designer\IsFormDesignableTestFixture.cs" />
<Compile Include="Designer\NullGeneratorPassedToLoader.cs" />
<Compile Include="Designer\PythonDesignerLoaderProviderTestFixture.cs" />
<Compile Include="Designer\PythonDesignerLoaderTestFixture.cs" />
<Compile Include="Designer\TextBoxNotAddedToFormTestFixture.cs" />
<Compile Include="Designer\TextEditorIndentPassedToGeneratorTestFixture.cs" />
<Compile Include="Designer\UnknownTypeTestFixture.cs" />
<Compile Include="Expressions\FindImportExpressionTestFixture.cs" />
<Compile Include="Expressions\FindSystemConsoleExpressionTestFixture.cs" />
<Compile Include="Expressions\RemoveLastPartTests.cs" />
@ -168,7 +174,6 @@ @@ -168,7 +174,6 @@
<Compile Include="ImportCompletionTestFixture.cs" />
<Compile Include="LanguageBindingTestFixture.cs" />
<Compile Include="Parsing\ClassWithBaseClassTestFixture.cs" />
<Compile Include="Parsing\IronPythonParserTestFixture.cs" />
<Compile Include="Parsing\MethodWithParametersTestFixture.cs" />
<Compile Include="Parsing\MissingLastParameterFromMethodTestFixture.cs" />
<Compile Include="Parsing\ParseClassWithCtorTestFixture.cs" />
@ -198,9 +203,11 @@ @@ -198,9 +203,11 @@
<Compile Include="Resolver\ResolveUnknownNamespaceTestFixture.cs" />
<Compile Include="RunPythonCommandTestFixture.cs" />
<Compile Include="StopPythonCommandTestFixture.cs" />
<Compile Include="Utils\AddedComponent.cs" />
<Compile Include="Utils\BrowseButtonInfo.cs" />
<Compile Include="Utils\BrowseFolderButtonInfo.cs" />
<Compile Include="Utils\CreatedComponent.cs" />
<Compile Include="Utils\CreatedInstance.cs" />
<Compile Include="Utils\DerivedAddInOptions.cs" />
<Compile Include="Utils\DerivedApplicationSettingsPanel.cs" />
<Compile Include="Utils\DerivedCompilingOptionsPanel.cs" />

54
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/AddedComponent.cs

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.ComponentModel;
namespace PythonBinding.Tests.Utils
{
/// <summary>
/// Component passed to the IComponentCreator.Add method.
/// </summary>
public class AddedComponent
{
public AddedComponent(IComponent component, string name)
{
Component = component;
Name = name;
}
public string Name { get; set; }
public IComponent Component { get; set; }
public override bool Equals(object obj)
{
AddedComponent rhs = obj as AddedComponent;
if (rhs != null) {
return Name == rhs.Name && Component == rhs.Component;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return Component.GetHashCode() ^ Name.GetHashCode();
}
public override string ToString()
{
return "AddedComponent [Component=" + GetComponentTypeName() + "Name=" + Name + "]";
}
string GetComponentTypeName()
{
if (Component != null) {
return Component.GetType().Name;
}
return "<null>";
}
}
}

69
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CreatedInstance.cs

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Text;
namespace PythonBinding.Tests.Utils
{
/// <summary>
/// Helper class that stores the parameters passed when the IComponentCreator.CreateInstance method is called.
/// </summary>
public class CreatedInstance
{
public CreatedInstance(Type type, ICollection arguments, string name, bool addToContainer)
{
InstanceType = type;
Arguments = arguments;
Name = name;
AddToContainer = addToContainer;
}
public Type InstanceType { get; set; }
public ICollection Arguments { get; set; }
public string Name { get; set; }
public bool AddToContainer { get; set; }
public object Object { get; set; }
public override bool Equals(object obj)
{
CreatedInstance rhs = obj as CreatedInstance;
if (rhs != null) {
return ToString() == rhs.ToString();
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return InstanceType.GetHashCode();
}
public override string ToString()
{
return "CreatedInstance [Type=" + InstanceType + ", Name=" + Name + ArgsToString() + "]";
}
string ArgsToString()
{
StringBuilder s = new StringBuilder();
s.Append("[Args=");
bool firstArg = true;
foreach (object o in Arguments) {
if (!firstArg) {
s.Append(", ");
}
s.Append(o);
firstArg = false;
}
s.Append("]");
return s.ToString();
}
}
}

8
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedPythonDesignerGenerator.cs

@ -17,6 +17,7 @@ using ICSharpCode.PythonBinding; @@ -17,6 +17,7 @@ using ICSharpCode.PythonBinding;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.TextEditor;
using ICSharpCode.TextEditor.Document;
namespace PythonBinding.Tests.Utils
{
@ -29,8 +30,13 @@ namespace PythonBinding.Tests.Utils @@ -29,8 +30,13 @@ namespace PythonBinding.Tests.Utils
string fileNamePassedToParseFile;
string textContentPassedToParseFile;
ParseInformation parseInfoToReturnFromParseFile;
public DerivedPythonDesignerGenerator() : this(new MockTextEditorProperties())
{
}
public DerivedPythonDesignerGenerator()
public DerivedPythonDesignerGenerator(ITextEditorProperties textEditorProperties)
: base(textEditorProperties)
{
}

Loading…
Cancel
Save