Browse Source

Controls.Add method is now invoked rather than being hard coded in the python forms designer code.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3983 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 16 years ago
parent
commit
ea89a0c643
  1. 6
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeDeserializer.cs
  2. 77
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs
  3. 105
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonFormWalker.cs
  4. 43
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/DeserializeComponentAssignmentTestFixture.cs
  5. 7
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeDeserializerTests.cs
  6. 61
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonControlFieldExpressionTests.cs
  7. 1
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

6
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeDeserializer.cs

@ -63,8 +63,10 @@ namespace ICSharpCode.PythonBinding @@ -63,8 +63,10 @@ namespace ICSharpCode.PythonBinding
return Deserialize(callExpression);
} else if (binaryExpression != null) {
return Deserialize(binaryExpression);
} else if (memberExpression != null) {
return Deserialize(memberExpression);
}
return Deserialize(memberExpression);
return null;
}
/// <summary>
@ -119,7 +121,7 @@ namespace ICSharpCode.PythonBinding @@ -119,7 +121,7 @@ namespace ICSharpCode.PythonBinding
}
}
}
return null;
return componentCreator.GetComponent(PythonControlFieldExpression.GetVariableName(field.MemberName));
}
Type GetType(PythonControlFieldExpression field)

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

@ -124,45 +124,7 @@ namespace ICSharpCode.PythonBinding @@ -124,45 +124,7 @@ namespace ICSharpCode.PythonBinding
}
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>
/// Gets the variable name of the parent control adding child controls. An expression of the form:
///
/// self._panel1.Controls.Add
///
/// would return "panel1".
/// </summary>
/// <returns>Null if the expression is not one of the following forms:
/// self.{0}.Controls.Add
/// self.Controls.Add
/// </returns>
public static string GetParentControlNameAddingChildControls(string code)
{
int endIndex = code.IndexOf(".Controls.Add", StringComparison.InvariantCultureIgnoreCase);
if (endIndex > 0) {
string controlName = code.Substring(0, endIndex);
int startIndex = controlName.LastIndexOf('.');
if (startIndex > 0) {
return GetVariableName(controlName.Substring(startIndex + 1));
}
return String.Empty;
}
return null;
}
/// <summary>
/// Removes the underscore from the variable name.
/// </summary>
@ -208,6 +170,14 @@ namespace ICSharpCode.PythonBinding @@ -208,6 +170,14 @@ namespace ICSharpCode.PythonBinding
/// <summary>
/// Gets the member object that matches the field member.
///
/// For a field:
///
/// self._menuStrip.Items.AddRange()
///
/// This method returns:
///
/// Items
/// </summary>
public object GetMember(IComponentCreator componentCreator)
{
@ -216,9 +186,36 @@ namespace ICSharpCode.PythonBinding @@ -216,9 +186,36 @@ namespace ICSharpCode.PythonBinding
return null;
}
Type type = obj.GetType();
string[] memberNames = fullMemberName.Split('.');
for (int i = 2; i < memberNames.Length; ++i) {
return GetMember(obj, memberNames, 2, memberNames.Length - 1);
}
/// <summary>
/// Gets the member object that matches the field member.
/// </summary>
/// <remarks>
/// The member names array should contain all items including self, for example:
///
/// self
/// Controls
/// </remarks>
public static object GetMember(object obj, CallExpression expression)
{
string[] memberNames = GetMemberNames(expression.Target as MemberExpression);
return GetMember(obj, memberNames, 1, memberNames.Length - 2);
}
/// <summary>
/// Gets the member that matches the last item in the memberNames array.
/// </summary>
/// <param name="obj"></param>
/// <param name="memberNames"></param>
/// <param name="startIndex">The point at which to start looking in the memberNames.</param>
/// <param name="endIndex">The last memberNames item to look at.</param>
static object GetMember(object obj, string[] memberNames, int startIndex, int endIndex)
{
Type type = obj.GetType();
for (int i = startIndex; i <= endIndex; ++i) {
string name = memberNames[i];
BindingFlags propertyBindingFlags = BindingFlags.Public | BindingFlags.GetField | BindingFlags.Static | BindingFlags.Instance;
PropertyInfo property = type.GetProperty(name, propertyBindingFlags);

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

@ -104,39 +104,10 @@ namespace ICSharpCode.PythonBinding @@ -104,39 +104,10 @@ namespace ICSharpCode.PythonBinding
public override bool Walk(CallExpression node)
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
string name = PythonControlFieldExpression.GetMemberName(memberExpression);
if (walkingAssignment) {
Type type = componentCreator.GetType(name);
if (type != null) {
List<object> args = deserializer.GetArguments(node);
object instance = componentCreator.CreateInstance(type, args, null, false);
if (!SetPropertyValue(fieldExpression.MemberName, instance)) {
AddComponent(fieldExpression.MemberName, instance);
}
} else {
object obj = deserializer.Deserialize(node);
if (obj != null) {
SetPropertyValue(form, fieldExpression.MemberName, obj);
} else {
throw new PythonFormWalkerException(String.Format("Could not find type '{0}'.", name));
}
}
} else {
// Add child controls if expression is of the form self.controlName.Controls.Add.
string parentControlName = PythonControlFieldExpression.GetParentControlNameAddingChildControls(name);
if (parentControlName != null) {
AddChildControl(parentControlName, node);
} else {
PythonControlFieldExpression field = PythonControlFieldExpression.Create(node);
object member = field.GetMember(componentCreator);
if (member != null) {
object parameter = deserializer.Deserialize(node.Args[0].Expression);
member.GetType().InvokeMember(field.MethodName, BindingFlags.InvokeMethod, Type.DefaultBinder, member, new object[] {parameter});
}
}
}
if (walkingAssignment) {
WalkAssignmentRhs(node);
} else {
WalkMethodCall(node);
}
return false;
}
@ -249,16 +220,6 @@ namespace ICSharpCode.PythonBinding @@ -249,16 +220,6 @@ namespace ICSharpCode.PythonBinding
return form;
}
void AddChildControl(string parentControlName, CallExpression node)
{
string childControlName = PythonControlFieldExpression.GetControlNameBeingAdded(node);
Control parentControl = form;
if (parentControlName.Length > 0) {
parentControl = GetControl(parentControlName);
}
parentControl.Controls.Add(GetControl(childControlName));
}
/// <summary>
/// Gets the property value from the member expression. The member expression is taken from the
/// right hand side of an assignment.
@ -276,5 +237,63 @@ namespace ICSharpCode.PythonBinding @@ -276,5 +237,63 @@ namespace ICSharpCode.PythonBinding
}
return propertyValue;
}
/// <summary>
/// Walks the right hand side of an assignment where the assignment expression is a call expression.
/// Typically the call expression will be a constructor call.
///
/// Constructor call: System.Windows.Forms.Form()
/// </summary>
void WalkAssignmentRhs(CallExpression node)
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
string name = PythonControlFieldExpression.GetMemberName(memberExpression);
Type type = componentCreator.GetType(name);
if (type != null) {
List<object> args = deserializer.GetArguments(node);
object instance = componentCreator.CreateInstance(type, args, null, false);
if (!SetPropertyValue(fieldExpression.MemberName, instance)) {
AddComponent(fieldExpression.MemberName, instance);
}
} else {
object obj = deserializer.Deserialize(node);
if (obj != null) {
SetPropertyValue(form, fieldExpression.MemberName, obj);
} else {
throw new PythonFormWalkerException(String.Format("Could not find type '{0}'.", name));
}
}
}
}
/// <summary>
/// Walks a method call. Typical method calls are:
///
/// self._menuItem1.Items.AddRange(...)
///
/// This method will execute the method call.
/// </summary>
void WalkMethodCall(CallExpression node)
{
if (node.Args.Length == 0) {
// Ignore method calls with no parameters.
return;
}
// Try to get the object being called. Try the form first then
// look for other controls.
object member = PythonControlFieldExpression.GetMember(form, node);
PythonControlFieldExpression field = PythonControlFieldExpression.Create(node);
if (member == null) {
member = field.GetMember(componentCreator);
}
// Execute the method on the object.
if (member != null) {
object parameter = deserializer.Deserialize(node.Args[0].Expression);
member.GetType().InvokeMember(field.MethodName, BindingFlags.InvokeMethod, Type.DefaultBinder, member, new object[] {parameter});
}
}
}
}

43
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/DeserializeComponentAssignmentTestFixture.cs

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
// <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;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using IronPython.Compiler.Ast;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests that the string "self._menuItem1" is converted to the matching component.
/// </summary>
[TestFixture]
public class DeserializeComponentAssignmentTestFixture : DeserializeAssignmentTestFixtureBase
{
Button button;
public override string GetPythonCode()
{
button = new Button();
button.Name = "button1";
base.componentCreator.Add(button, "button1");
return "self.AcceptButton = self._button1";
}
[Test]
public void DeserializedObjectIsButton()
{
Assert.AreSame(button, deserializedObject);
}
}
}

7
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeDeserializerTests.cs

@ -93,6 +93,13 @@ namespace PythonBinding.Tests.Designer @@ -93,6 +93,13 @@ namespace PythonBinding.Tests.Designer
Assert.AreEqual(expectedStyles, DeserializeRhsAssignment(pythonCode));
}
[Test]
public void DeserializeNameExpression()
{
string pythonCode = "self.Items = self";
Assert.IsNull(DeserializeRhsAssignment(pythonCode));
}
/// <summary>
/// Deserializes the right hand side of the assignment.
/// </summary>

61
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonControlFieldExpressionTests.cs

@ -29,34 +29,6 @@ namespace PythonBinding.Tests.Designer @@ -29,34 +29,6 @@ namespace PythonBinding.Tests.Designer
Assert.AreEqual("a", PythonControlFieldExpression.GetPrefix("a"));
}
[Test]
public void ParentControlNameAddingChildControls()
{
string code = "self._panel1.Controls.Add";
Assert.AreEqual("panel1", PythonControlFieldExpression.GetParentControlNameAddingChildControls(code));
}
[Test]
public void EmptyControlNameAddingChildControls()
{
string code = "self.Controls.Add";
Assert.AreEqual(String.Empty, PythonControlFieldExpression.GetParentControlNameAddingChildControls(code));
}
[Test]
public void CaseInsensitiveCheckForControlsAddStatement()
{
string code = "self._panel1.controls.add";
Assert.AreEqual("panel1", PythonControlFieldExpression.GetParentControlNameAddingChildControls(code));
}
[Test]
public void CodeDoesNotIncludeControlsAddStatement()
{
string code = "self._panel1.SuspendLayout";
Assert.IsNull(PythonControlFieldExpression.GetParentControlNameAddingChildControls(code));
}
[Test]
public void GetVariableName()
{
@ -108,21 +80,22 @@ namespace PythonBinding.Tests.Designer @@ -108,21 +80,22 @@ namespace PythonBinding.Tests.Designer
}
[Test]
public void GetControlNameBeingAdded()
public void MethodName()
{
string code = "self.Controls.Add(self._menuItem1)";
string code = "self.menuItem.Items.Add(self._fileMenuItem)";
CallExpression expression = PythonParserHelper.GetCallExpression(code);
Assert.AreEqual("menuItem1", PythonControlFieldExpression.GetControlNameBeingAdded(expression));
PythonControlFieldExpression field = PythonControlFieldExpression.Create(expression);
AssertAreEqual(field, "menuItem", "Items", "Add", "self.menuItem.Items");
}
[Test]
public void MethodName()
public void MethodNameWithNoVariableName()
{
string code = "self.menuItem.Items.Add(self._fileMenuItem)";
string code = "self.Items.Add(self._fileMenuItem)";
CallExpression expression = PythonParserHelper.GetCallExpression(code);
PythonControlFieldExpression field = PythonControlFieldExpression.Create(expression);
AssertAreEqual(field, "menuItem", "Items", "Add", "self.menuItem.Items");
}
AssertAreEqual(field, String.Empty, "Items", "Add", "self.Items");
}
[Test]
public void GetMemberNames()
@ -146,7 +119,7 @@ namespace PythonBinding.Tests.Designer @@ -146,7 +119,7 @@ namespace PythonBinding.Tests.Designer
using (MenuStrip menuStrip = new MenuStrip()) {
MockComponentCreator creator = new MockComponentCreator();
creator.Add(menuStrip, "menuStrip1");
Assert.AreEqual(menuStrip.Items, field.GetMember(creator));
Assert.AreSame(menuStrip.Items, field.GetMember(creator));
}
}
@ -163,7 +136,21 @@ namespace PythonBinding.Tests.Designer @@ -163,7 +136,21 @@ namespace PythonBinding.Tests.Designer
creator.Add(menuStrip, "unknown");
Assert.IsNull(field.GetMember(creator));
}
}
}
[Test]
public void GetObjectInMethodCallFromSpecifiedObject()
{
string pythonCode = "self.Controls.AddRange(System.Array[System.Windows.Forms.ToolStripItem](\r\n" +
" [self._fileToolStripMenuItem,\r\n" +
" self._editToolStripMenuItem]))";
CallExpression callExpression = PythonParserHelper.GetCallExpression(pythonCode);
using (Form form = new Form()) {
Assert.AreSame(form.Controls, PythonControlFieldExpression.GetMember(form, callExpression));
}
}
void AssertAreEqual(PythonControlFieldExpression field, string variableName, string memberName, string methodName, string fullMemberName)
{

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

@ -148,6 +148,7 @@ @@ -148,6 +148,7 @@
<Compile Include="Designer\CursorTypeResolutionTestFixture.cs" />
<Compile Include="Designer\DeserializeAssignmentTestFixtureBase.cs" />
<Compile Include="Designer\DeserializeColorFromArgbTestFixture.cs" />
<Compile Include="Designer\DeserializeComponentAssignmentTestFixture.cs" />
<Compile Include="Designer\DeserializeStringArrayTestFixture.cs" />
<Compile Include="Designer\DeserializeToolStripItemArrayTestFixture.cs" />
<Compile Include="Designer\EnabledSetUsingPropertyDescriptorTestFixture.cs" />

Loading…
Cancel
Save