Browse Source

Python forms designer now loading/generating forms with nested properties (e.g. Button.FlatAppearance)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4544 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 16 years ago
parent
commit
ba5384dfbd
  1. 38
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs
  2. 39
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs
  3. 18
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs
  4. 85
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateButtonFlatAppearanceTestFixture.cs
  5. 71
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadButtonFlatAppearanceTestFixture.cs
  6. 55
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonControlFieldExpressionTests.cs
  7. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

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

@ -107,20 +107,7 @@ namespace ICSharpCode.PythonBinding @@ -107,20 +107,7 @@ namespace ICSharpCode.PythonBinding
NameExpression lhsNameExpression = node.Left[0] as NameExpression;
if (lhsMemberExpression != null) {
fieldExpression = PythonControlFieldExpression.Create(lhsMemberExpression);
MemberExpression rhsMemberExpression = node.Right as MemberExpression;
if (rhsMemberExpression != null) {
object propertyValue = GetPropertyValueFromAssignmentRhs(rhsMemberExpression);
SetPropertyValue(fieldExpression, propertyValue);
} else {
walkingAssignment = true;
BinaryExpression binaryExpression = node.Right as BinaryExpression;
if (binaryExpression != null) {
WalkAssignment(binaryExpression);
} else {
node.Right.Walk(this);
}
walkingAssignment = false;
}
WalkMemberExpressionAssignmentRhs(node.Right);
} else if (lhsNameExpression != null) {
CallExpression callExpression = node.Right as CallExpression;
if (callExpression != null) {
@ -202,6 +189,27 @@ namespace ICSharpCode.PythonBinding @@ -202,6 +189,27 @@ namespace ICSharpCode.PythonBinding
object value = deserializer.Deserialize(binaryExpression);
SetPropertyValue(fieldExpression.MemberName, value);
}
/// <summary>
/// Walks the right hand side of an assignment to a member expression.
/// </summary>
void WalkMemberExpressionAssignmentRhs(Expression rhs)
{
MemberExpression rhsMemberExpression = rhs as MemberExpression;
if (rhsMemberExpression != null) {
object propertyValue = GetPropertyValueFromAssignmentRhs(rhsMemberExpression);
SetPropertyValue(fieldExpression, propertyValue);
} else {
walkingAssignment = true;
BinaryExpression binaryExpression = rhs as BinaryExpression;
if (binaryExpression != null) {
WalkAssignment(binaryExpression);
} else {
rhs.Walk(this);
}
walkingAssignment = false;
}
}
static bool IsInitializeComponentMethod(FunctionDefinition node)
{
@ -216,7 +224,7 @@ namespace ICSharpCode.PythonBinding @@ -216,7 +224,7 @@ namespace ICSharpCode.PythonBinding
bool SetPropertyValue(PythonControlFieldExpression fieldExpression, object propertyValue)
{
if (fieldExpression.IsSelfReference) {
return SetPropertyValue(fieldExpression.MemberName, propertyValue);
return SetPropertyValue(fieldExpression.GetObject(GetCurrentComponent()), fieldExpression.MemberName, propertyValue);
}
return SetPropertyValue(componentCreator.GetInstance(fieldExpression.VariableName), fieldExpression.MemberName, propertyValue);
}

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

@ -176,6 +176,26 @@ namespace ICSharpCode.PythonBinding @@ -176,6 +176,26 @@ namespace ICSharpCode.PythonBinding
}
return names.ToArray();
}
/// <summary>
/// Returns the object that the property is defined on. This method may just return the object
/// passed to it if the property is defined on that object.
/// </summary>
/// <remarks>The object parameter must be equivalent to the object referred to
/// by the variable name in this PythonControlFieldExpression
/// (e.g. button1 in self._button1.FlatAppearance.BorderSize).</remarks>
public object GetObject(object component)
{
string[] members = fullMemberName.Split('.');
int startIndex = GetMembersStartIndex(members);
object currentComponent = component;
for (int i = startIndex; i < members.Length - 1; ++i) {
PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties(currentComponent).Find(members[i], true);
currentComponent = propertyDescriptor.GetValue(currentComponent);
}
return currentComponent;
}
/// <summary>
/// Gets the member object that matches the field member.
@ -197,11 +217,7 @@ namespace ICSharpCode.PythonBinding @@ -197,11 +217,7 @@ namespace ICSharpCode.PythonBinding
if (obj != null) {
string[] memberNames = fullMemberName.Split('.');
int startIndex = 2;
if (!ContainsSelfReference(memberNames)) {
// No self to skip over when searching for member.
startIndex = 1;
}
int startIndex = GetMembersStartIndex(memberNames);
return GetMember(obj, memberNames, startIndex, memberNames.Length - 1);
}
return null;
@ -297,5 +313,18 @@ namespace ICSharpCode.PythonBinding @@ -297,5 +313,18 @@ namespace ICSharpCode.PythonBinding
}
return false;
}
/// <summary>
/// Returns the index into the members array where the members actually start.
/// The "self" and variable name are skipped.
/// </summary>
int GetMembersStartIndex(string[] members)
{
if (ContainsSelfReference(members)) {
// Skip self over when searching for member.
return 2;
}
return 1;
}
}
}

18
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs

@ -502,7 +502,7 @@ namespace ICSharpCode.PythonBinding @@ -502,7 +502,7 @@ namespace ICSharpCode.PythonBinding
}
} else {
// DesignerSerializationVisibility.Content
AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, obj, propertyDescriptor);
AppendPropertyContents(codeBuilder, propertyOwnerName, obj, propertyDescriptor);
}
}
@ -802,6 +802,20 @@ namespace ICSharpCode.PythonBinding @@ -802,6 +802,20 @@ namespace ICSharpCode.PythonBinding
}
reversedCollection.Reverse();
return reversedCollection;
}
}
/// <summary>
/// Appends a property that needs its contents serialized.
/// </summary>
void AppendPropertyContents(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor)
{
object propertyValue = propertyDescriptor.GetValue(propertyOwner);
if (propertyValue is ICollection) {
AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor);
} else {
propertyOwnerName += "." + propertyDescriptor.Name;
AppendProperties(codeBuilder, propertyOwnerName, propertyValue);
}
}
}
}

85
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateButtonFlatAppearanceTestFixture.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.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
[TestFixture]
public class GenerateButtonFlatAppearanceTestFixture
{
string generatedPythonCode;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (DesignSurface designSurface = new DesignSurface(typeof(Form))) {
IDesignerHost host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
IEventBindingService eventBindingService = new MockEventBindingService(host);
Form form = (Form)host.RootComponent;
form.ClientSize = new Size(200, 300);
Button button = (Button)host.CreateComponent(typeof(Button), "button1");
button.Location = new Point(0, 0);
button.Size = new Size(10, 10);
button.Text = "button1";
button.UseCompatibleTextRendering = false;
button.FlatAppearance.BorderSize = 2;
button.FlatAppearance.BorderColor = Color.Red;
button.FlatAppearance.MouseOverBackColor = Color.Yellow;
form.Controls.Add(button);
PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(form);
PropertyDescriptor namePropertyDescriptor = descriptors.Find("Name", false);
namePropertyDescriptor.SetValue(form, "MainForm");
PythonControl pythonForm = new PythonControl(" ");
generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form);
}
}
[Test]
public void GeneratedCode()
{
string expectedCode = "def InitializeComponent(self):\r\n" +
" self._button1 = System.Windows.Forms.Button()\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # button1\r\n" +
" # \r\n" +
" self._button1.FlatAppearance.BorderColor = System.Drawing.Color.Red\r\n" +
" self._button1.FlatAppearance.BorderSize = 2\r\n" +
" self._button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Yellow\r\n" +
" self._button1.Location = System.Drawing.Point(0, 0)\r\n" +
" self._button1.Name = \"button1\"\r\n" +
" self._button1.Size = System.Drawing.Size(10, 10)\r\n" +
" self._button1.TabIndex = 0\r\n" +
" self._button1.Text = \"button1\"\r\n" +
" # \r\n" +
" # MainForm\r\n" +
" # \r\n" +
" self.ClientSize = System.Drawing.Size(200, 300)\r\n" +
" self.Controls.Add(self._button1)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.ResumeLayout(False)\r\n" +
" self.PerformLayout()\r\n";
Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode);
}
}
}

71
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadButtonFlatAppearanceTestFixture.cs

@ -0,0 +1,71 @@ @@ -0,0 +1,71 @@
// <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.ComponentModel.Design;
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 LoadButtonFlatAppearanceTestFixture : LoadFormTestFixtureBase
{
public override string PythonCode {
get {
return "class TestForm(System.Windows.Forms.Form):\r\n" +
" def InitializeComponent(self):\r\n" +
" self._button1 = System.Windows.Forms.Button()\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # button1\r\n" +
" # \r\n" +
" self._button1.FlatAppearance.BorderColor = System.Drawing.Color.Red\r\n" +
" self._button1.FlatAppearance.BorderSize = 2\r\n" +
" self._button1.FlatAppearance.MouseDownBackColor = System.Drawing.Color.Blue\r\n" +
" self._button1.FlatAppearance.MouseOverBackColor = System.Drawing.Color.Yellow\r\n" +
" self._button1.Location = System.Drawing.Point(0, 0)\r\n" +
" self._button1.Name = \"button1\"\r\n" +
" self._button1.Size = System.Drawing.Size(10, 10)\r\n" +
" self._button1.TabIndex = 0\r\n" +
" self._button1.Text = \"button1\"\r\n" +
" # \r\n" +
" # MainForm\r\n" +
" # \r\n" +
" self.AcceptButton = self._button1\r\n" +
" self.ClientSize = System.Drawing.Size(200, 300)\r\n" +
" self.Name = \"MainForm\"\r\n" +
" self.Controls.Add(self._button1)\r\n" +
" self.ResumeLayout(False)\r\n";
}
}
public Button Button
{
get { return Form.Controls[0] as Button; }
}
[Test]
public void ButtonFlatAppearanceBorderSize()
{
Assert.AreEqual(2, Button.FlatAppearance.BorderSize);
}
[Test]
public void ButtonFlatAppearanceBorderColor()
{
Assert.AreEqual(Color.Red, Button.FlatAppearance.BorderColor);
}
}
}

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

@ -204,6 +204,61 @@ namespace PythonBinding.Tests.Designer @@ -204,6 +204,61 @@ namespace PythonBinding.Tests.Designer
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.IsTrue(field.IsSelfReference);
}
[Test]
public void GetButtonObjectForSelfReference()
{
using (Button button = new Button()) {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("self._button1.Size = System.Drawing.Size(10, 10)");
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.AreEqual(button, field.GetObject(button));
}
}
[Test]
public void GetButtonObject()
{
using (Button button = new Button()) {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("_button1.Size = System.Drawing.Size(10, 10)");
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.AreEqual(button, field.GetObject(button));
}
}
[Test]
public void GetButtonFlatAppearanceObjectForSelfReference()
{
using (Button button = new Button()) {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("self._button1.FlatAppearance.BorderSize = 3");
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.AreEqual(button.FlatAppearance, field.GetObject(button));
}
}
[Test]
public void GetButtonFlatAppearanceObject()
{
using (Button button = new Button()) {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("_button1.FlatAppearance.BorderSize = 3");
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.AreEqual(button.FlatAppearance, field.GetObject(button));
}
}
[Test]
public void GetInvalidTwoLevelDeepButtonPropertyDescriptorForSelfReference()
{
using (Button button = new Button()) {
AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("self._button1.InvalidProperty.BorderSize = 3");
PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression);
Assert.IsNull(field.GetObject(button));
}
}
void AssertAreEqual(PythonControlFieldExpression field, string variableName, string memberName, string methodName, string fullMemberName)
{

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

@ -180,6 +180,7 @@ @@ -180,6 +180,7 @@
<Compile Include="Designer\GenerateAutoScaleModeFormTestFixture.cs" />
<Compile Include="Designer\GenerateAutoScrollFormTestFixture.cs" />
<Compile Include="Designer\GenerateBackgroundWorkerTestFixture.cs" />
<Compile Include="Designer\GenerateButtonFlatAppearanceTestFixture.cs" />
<Compile Include="Designer\GenerateComboBoxItemsTestFixture.cs" />
<Compile Include="Designer\GenerateContextMenuStripTestFixture.cs" />
<Compile Include="Designer\GenerateCursorFormTestFixture.cs" />
@ -223,6 +224,7 @@ @@ -223,6 +224,7 @@
<Compile Include="Designer\LoadAcceptButtonFormTestFixture.cs" />
<Compile Include="Designer\LoadAccessibleRoleTestFixture.cs" />
<Compile Include="Designer\LoadAnchorStylesFormTestFixture.cs" />
<Compile Include="Designer\LoadButtonFlatAppearanceTestFixture.cs" />
<Compile Include="Designer\LoadColorFromArgbTestFixture.cs" />
<Compile Include="Designer\LoadControlEventHandlerTestFixture.cs" />
<Compile Include="Designer\LoadCursorTestFixture.cs" />

Loading…
Cancel
Save