Browse Source

Added basic support for non-visual components in the python forms designer.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4047 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 17 years ago
parent
commit
99f9c096bc
  1. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeDeserializer.cs
  2. 39
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs
  3. 7
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs
  4. 51
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs
  5. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs
  6. 58
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs
  7. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs
  8. 5
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/DeserializeComponentAssignmentTestFixture.cs
  9. 6
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs
  10. 14
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs
  11. 79
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs
  12. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadTextBoxTestFixture.cs
  13. 66
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadTimerTestFixture.cs
  14. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj
  15. 6
      src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt
  16. 9
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockComponentCreator.cs

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

@ -124,7 +124,7 @@ namespace ICSharpCode.PythonBinding @@ -124,7 +124,7 @@ namespace ICSharpCode.PythonBinding
}
}
}
return componentCreator.GetComponent(PythonControlFieldExpression.GetVariableName(field.MemberName));
return componentCreator.GetInstance(PythonControlFieldExpression.GetVariableName(field.MemberName));
}
Type GetType(PythonControlFieldExpression field)

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

@ -195,12 +195,25 @@ namespace ICSharpCode.PythonBinding @@ -195,12 +195,25 @@ namespace ICSharpCode.PythonBinding
return SetPropertyValue(GetCurrentComponent(), name, propertyValue);
}
/// <summary>
/// Returns true if the current component has a property with the specified name.
/// </summary>
bool HasPropertyValue(string name)
{
return GetPropertyDescriptor(GetCurrentComponent(), name) != null;
}
PropertyDescriptor GetPropertyDescriptor(object component, string name)
{
return TypeDescriptor.GetProperties(component).Find(name, true);
}
/// <summary>
/// Sets the value of a property on the component.
/// </summary>
bool SetPropertyValue(object component, string name, object propertyValue)
{
PropertyDescriptor property = TypeDescriptor.GetProperties(component).Find(name, true);
PropertyDescriptor property = GetPropertyDescriptor(component, name);
if (property != null) {
propertyValue = ConvertPropertyValue(property, propertyValue);
property.SetValue(component, propertyValue);
@ -232,10 +245,13 @@ namespace ICSharpCode.PythonBinding @@ -232,10 +245,13 @@ namespace ICSharpCode.PythonBinding
/// <summary>
/// Adds a component to the list of created objects.
/// </summary>
void AddComponent(string name, object component)
void AddComponent(string name, object obj)
{
string variableName = PythonControlFieldExpression.GetVariableName(name);
componentCreator.Add(component as IComponent, variableName);
IComponent component = obj as IComponent;
if (component != null) {
string variableName = PythonControlFieldExpression.GetVariableName(name);
componentCreator.Add(component, variableName);
}
}
/// <summary>
@ -289,7 +305,8 @@ namespace ICSharpCode.PythonBinding @@ -289,7 +305,8 @@ namespace ICSharpCode.PythonBinding
{
MemberExpression memberExpression = node.Target as MemberExpression;
if (memberExpression != null) {
object instance = CreateInstance(null, node);
string name = GetInstanceName(fieldExpression);
object instance = CreateInstance(name, node);
if (instance != null) {
if (!SetPropertyValue(fieldExpression.MemberName, instance)) {
AddComponent(fieldExpression.MemberName, instance);
@ -305,6 +322,18 @@ namespace ICSharpCode.PythonBinding @@ -305,6 +322,18 @@ namespace ICSharpCode.PythonBinding
}
}
/// <summary>
/// Gets the name of the instance. If the name matches a property of the current component being created
/// then this method returns null.
/// </summary>
string GetInstanceName(PythonControlFieldExpression fieldExpression)
{
if (!HasPropertyValue(fieldExpression.MemberName)) {
return PythonControlFieldExpression.GetVariableName(fieldExpression.MemberName);
}
return null;
}
/// <summary>
/// Walks a method call. Typical method calls are:
///

7
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs

@ -72,10 +72,15 @@ namespace ICSharpCode.PythonBinding @@ -72,10 +72,15 @@ namespace ICSharpCode.PythonBinding
void GenerateInitializeComponentMethodBodyInternal(Control control)
{
PythonDesignerComponent rootDesignerComponent = PythonDesignerComponentFactory.CreateDesignerRootComponent(control);
PythonDesignerRootComponent rootDesignerComponent = PythonDesignerComponentFactory.CreateDesignerRootComponent(control);
if (rootDesignerComponent.HasNonVisualChildComponents()) {
rootDesignerComponent.AppendCreateComponentsContainer(codeBuilder);
rootDesignerComponent.AppendCreateNonVisualComponents(codeBuilder);
}
rootDesignerComponent.AppendCreateChildComponents(codeBuilder);
rootDesignerComponent.AppendChildComponentsSuspendLayout(codeBuilder);
rootDesignerComponent.AppendSuspendLayout(codeBuilder);
rootDesignerComponent.AppendNonVisualComponents(codeBuilder);
rootDesignerComponent.AppendComponent(codeBuilder);
rootDesignerComponent.AppendChildComponentsResumeLayout(codeBuilder);
rootDesignerComponent.AppendResumeLayout(codeBuilder);

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

@ -122,7 +122,34 @@ namespace ICSharpCode.PythonBinding @@ -122,7 +122,34 @@ namespace ICSharpCode.PythonBinding
}
}
return false;
}
}
/// <summary>
/// Returns true if the component has the DesignTimeVisible attribute set to false.
/// </summary>
public static bool IsHiddenFromDesigner(IComponent component)
{
foreach (DesignTimeVisibleAttribute attribute in component.GetType().GetCustomAttributes(typeof(DesignTimeVisibleAttribute), true)) {
return !attribute.Visible;
}
return false;
}
/// <summary>
/// A component is non-visual if it is not a control and is not hidden from the designer.
/// </summary>
public static bool IsNonVisualComponent(IComponent component)
{
Control control = component as Control;
return (control == null) && !IsHiddenFromDesigner(component);
}
/// <summary>
/// Returns true if this component is non-visual.
/// </summary>
public bool IsNonVisual {
get { return IsNonVisualComponent(component); }
}
/// <summary>
/// Gets the AddRange method on the object that is not hidden from the designer.
@ -188,6 +215,11 @@ namespace ICSharpCode.PythonBinding @@ -188,6 +215,11 @@ namespace ICSharpCode.PythonBinding
AppendComponentCreation(codeBuilder, component);
}
public void AppendCreateInstance(PythonCodeBuilder codeBuilder, string parameters)
{
AppendComponentCreation(codeBuilder, component, parameters);
}
/// <summary>
/// Appends the code to create the child components.
/// </summary>
@ -294,12 +326,11 @@ namespace ICSharpCode.PythonBinding @@ -294,12 +326,11 @@ namespace ICSharpCode.PythonBinding
designerComponent.AppendChildComponentsMethodCalls(codeBuilder, methods);
}
}
/// <summary>
/// Appends the code to create the specified object.
/// </summary>
public void AppendObjectCreation(PythonCodeBuilder codeBuilder, object obj, int count, object[] parameters)
public void AppendCreateInstance(PythonCodeBuilder codeBuilder, object obj, int count, object[] parameters)
{
if (obj is String) {
// Do nothing.
@ -330,9 +361,17 @@ namespace ICSharpCode.PythonBinding @@ -330,9 +361,17 @@ namespace ICSharpCode.PythonBinding
/// </summary>
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component)
{
codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "()");
AppendComponentCreation(codeBuilder, component, String.Empty);
}
/// <summary>
/// Appends the code to create the specified IComponent
/// </summary>
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component, string parameters)
{
codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "(" + parameters + ")");
}
/// <summary>
/// Generates the code for the component's properties.
/// </summary>

2
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.PythonBinding @@ -28,7 +28,7 @@ namespace ICSharpCode.PythonBinding
return new PythonDesignerComponent(component);
}
public static PythonDesignerComponent CreateDesignerRootComponent(IComponent component)
public static PythonDesignerRootComponent CreateDesignerRootComponent(IComponent component)
{
return new PythonDesignerRootComponent(component);
}

58
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs

@ -6,7 +6,9 @@ @@ -6,7 +6,9 @@
// </file>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
namespace ICSharpCode.PythonBinding
{
@ -54,6 +56,60 @@ namespace ICSharpCode.PythonBinding @@ -54,6 +56,60 @@ namespace ICSharpCode.PythonBinding
PythonDesignerComponent[] components = base.GetChildComponents();
Array.Reverse(components);
return components;
}
}
/// <summary>
/// Returns true if non-visual components (e.g. Timer) are associated with this root component.
/// </summary>
public bool HasNonVisualChildComponents()
{
foreach (IComponent containerComponent in Component.Site.Container.Components) {
if (IsNonVisualComponent(containerComponent)) {
return true;
}
}
return false;
}
public PythonDesignerComponent[] GetNonVisualChildComponents()
{
List<PythonDesignerComponent> components = new List<PythonDesignerComponent>();
foreach (IComponent containerComponent in Component.Site.Container.Components) {
PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(containerComponent);
if (designerComponent.IsNonVisual) {
components.Add(designerComponent);
}
}
return components.ToArray();
}
/// <summary>
/// Appends an expression that creates an instance of the Container to hold non-visual components
/// </summary>
public void AppendCreateComponentsContainer(PythonCodeBuilder codeBuilder)
{
codeBuilder.AppendIndentedLine("self._components = " + typeof(Container).FullName + "()");
}
/// <summary>
/// Appends code to create all the non-visual component.
/// </summary>
public void AppendCreateNonVisualComponents(PythonCodeBuilder codeBuilder)
{
foreach (PythonDesignerComponent component in GetNonVisualChildComponents()) {
component.AppendCreateInstance(codeBuilder, "self._components");
}
}
/// <summary>
/// Appends code to set all the non-visual component properties.
/// </summary>
/// <param name="codeBuilder"></param>
public void AppendNonVisualComponents(PythonCodeBuilder codeBuilder)
{
foreach (PythonDesignerComponent component in GetNonVisualChildComponents()) {
component.AppendComponent(codeBuilder);
}
}
}
}

2
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.PythonBinding @@ -28,7 +28,7 @@ namespace ICSharpCode.PythonBinding
// Append list view item creation first.
int count = 1;
foreach (ListViewItem item in GetListViewItems(Component)) {
AppendObjectCreation(codeBuilder, item, count, GetConstructorParameters(item));
AppendCreateInstance(codeBuilder, item, count, GetConstructorParameters(item));
++count;
}

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

@ -27,10 +27,7 @@ namespace PythonBinding.Tests.Designer @@ -27,10 +27,7 @@ namespace PythonBinding.Tests.Designer
public override string GetPythonCode()
{
button = new Button();
button.Name = "button1";
base.componentCreator.Add(button, "button1");
button = (Button)base.componentCreator.CreateInstance(typeof(Button), new object[0], "button1", false);
return "self.AcceptButton = self._button1";
}

6
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs

@ -249,5 +249,11 @@ namespace PythonBinding.Tests.Designer @@ -249,5 +249,11 @@ namespace PythonBinding.Tests.Designer
Assert.AreEqual(expectedCode, createListViewChildComponentsCode);
}
[Test]
public void ColumnHeaderIsHiddenFromDesigner()
{
Assert.IsTrue(PythonDesignerComponent.IsHiddenFromDesigner(columnHeader1));
}
}
}

14
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs

@ -26,6 +26,7 @@ namespace PythonBinding.Tests.Designer @@ -26,6 +26,7 @@ namespace PythonBinding.Tests.Designer
Size openMenuItemSize;
Size exitMenuItemSize;
Size editMenuItemSize;
bool nonVisualComponents;
[TestFixtureSetUp]
public void SetUpFixture()
@ -75,6 +76,9 @@ namespace PythonBinding.Tests.Designer @@ -75,6 +76,9 @@ namespace PythonBinding.Tests.Designer
exitMenuItemSize = exitMenuItem.Size;
editMenuItemSize = editMenuItem.Size;
PythonDesignerRootComponent rootComponent = new PythonDesignerRootComponent(form);
nonVisualComponents = rootComponent.HasNonVisualChildComponents();
PythonControl pythonForm = new PythonControl(" ");
generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form);
}
@ -142,10 +146,16 @@ namespace PythonBinding.Tests.Designer @@ -142,10 +146,16 @@ namespace PythonBinding.Tests.Designer
Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode);
}
[Test]
public void NoNonVisualComponents()
{
Assert.IsFalse(nonVisualComponents);
}
string SizeToString(Size size)
{
return PythonPropertyValueAssignment.ToString(size);
}
}
}
}

79
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
// <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 NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
[TestFixture]
public class GenerateTimerTestFixture
{
string generatedPythonCode;
bool hasNonVisualChildComponents;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (DesignSurface designSurface = new DesignSurface(typeof(Form))) {
IDesignerHost host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost));
Form form = (Form)host.RootComponent;
form.ClientSize = new Size(284, 264);
PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(form);
PropertyDescriptor namePropertyDescriptor = descriptors.Find("Name", false);
namePropertyDescriptor.SetValue(form, "MainForm");
Timer timer = (Timer)host.CreateComponent(typeof(Timer), "timer1");
descriptors = TypeDescriptor.GetProperties(timer);
namePropertyDescriptor = descriptors.Find("Interval", false);
namePropertyDescriptor.SetValue(timer, 1000);
string indentString = " ";
PythonDesignerRootComponent designerRootComponent = new PythonDesignerRootComponent(form);
hasNonVisualChildComponents = designerRootComponent.HasNonVisualChildComponents();
PythonControl pythonControl = new PythonControl(indentString);
generatedPythonCode = pythonControl.GenerateInitializeComponentMethod(form);
}
}
[Test]
public void HasNonVisualChildComponents()
{
Assert.IsTrue(hasNonVisualChildComponents);
}
[Test]
public void GeneratedCode()
{
string expectedCode = "def InitializeComponent(self):\r\n" +
" self._components = System.ComponentModel.Container()\r\n" +
" self._timer1 = System.Windows.Forms.Timer(self._components)\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # timer1\r\n" +
" # \r\n" +
" self._timer1.Interval = 1000\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, generatedPythonCode, generatedPythonCode);
}
}
}

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

@ -58,7 +58,7 @@ namespace PythonBinding.Tests.Designer @@ -58,7 +58,7 @@ namespace PythonBinding.Tests.Designer
[Test]
public void TextBoxInstanceCreated()
{
CreatedInstance instance = new CreatedInstance(typeof(TextBox), new List<object>(), null, false);
CreatedInstance instance = new CreatedInstance(typeof(TextBox), new List<object>(), "textBox1", false);
Assert.Contains(instance, ComponentCreator.CreatedInstances);
}

66
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadTimerTestFixture.cs

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
// <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 NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
[TestFixture]
public class LoadTimerTestFixture : LoadFormTestFixtureBase
{
public override string PythonCode {
get {
return "class MainForm(System.Windows.Forms.Form):\r\n" +
" def InitializeComponent(self):\r\n" +
" self._components = System.ComponentModel.Container()\r\n" +
" self._timer1 = System.Windows.Forms.Timer(self._components)\r\n" +
" self.SuspendLayout()\r\n" +
" # \r\n" +
" # timer1\r\n" +
" # \r\n" +
" self._timer1.Interval = 1000\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";
}
}
public CreatedInstance TimerInstance {
get { return ComponentCreator.CreatedInstances[1]; }
}
[Test]
public void ThreeInstancesCreated()
{
Assert.AreEqual(3, ComponentCreator.CreatedInstances.Count);
}
[Test]
public void ComponentName()
{
Assert.AreEqual("timer1", TimerInstance.Name);
}
[Test]
public void ComponentType()
{
Assert.AreEqual("System.Windows.Forms.Timer", TimerInstance.InstanceType.FullName);
}
}
}

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

@ -182,6 +182,7 @@ @@ -182,6 +182,7 @@
<Compile Include="Designer\GenerateRightToLeftFormTestFixture.cs" />
<Compile Include="Designer\GenerateSimpleFormTestFixture.cs" />
<Compile Include="Designer\GenerateTextBoxFormTestFixture.cs" />
<Compile Include="Designer\GenerateTimerTestFixture.cs" />
<Compile Include="Designer\GeneratorMergeFindsInitializeComponentsTestFixture.cs" />
<Compile Include="Designer\GetComponentFromDesignerLoaderTestFixture.cs" />
<Compile Include="Designer\GetInstanceFromDesignerLoaderTestFixture.cs" />
@ -208,6 +209,7 @@ @@ -208,6 +209,7 @@
<Compile Include="Designer\LoadSimpleUserControlTestFixture.cs" />
<Compile Include="Designer\LoadTextBoxOnPanelTestFixture.cs" />
<Compile Include="Designer\LoadTextBoxTestFixture.cs" />
<Compile Include="Designer\LoadTimerTestFixture.cs" />
<Compile Include="Designer\MergeFormTestFixture.cs" />
<Compile Include="Designer\MissingInitializeComponentMethodTestFixture.cs" />
<Compile Include="Designer\NoNewLineAfterInitializeComponentTestFixture.cs" />

6
src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt

@ -94,4 +94,8 @@ def main(args): @@ -94,4 +94,8 @@ def main(args):
See http://lists.ironpython.com/pipermail/users-ironpython.com/2009-April/009993.html
* Support for ListViewSubItems - Font, Colors.
* Support for ListViewSubItems - Font, Colors.
* Timer - Honour the GenerateMember setting.
* Look at creating code for non-visual components in the same order as Visual Studio.

9
src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/MockComponentCreator.cs

@ -42,6 +42,10 @@ namespace PythonBinding.Tests.Utils @@ -42,6 +42,10 @@ namespace PythonBinding.Tests.Utils
public void Add(IComponent component, string name)
{
if (component == null) {
throw new ArgumentNullException("component");
}
AddedComponent addedComponent = new AddedComponent(component, name);
addedComponents.Add(addedComponent);
}
@ -81,12 +85,15 @@ namespace PythonBinding.Tests.Utils @@ -81,12 +85,15 @@ namespace PythonBinding.Tests.Utils
// Lookup type in System.Windows.Forms assembly.
Type type = typeof(Form).Assembly.GetType(typeName);
if (type == null) {
// Lookup type System.Drawing assembly.
// Lookup type in System.Drawing assembly.
type = typeof(Size).Assembly.GetType(typeName);
}
if (type == null) {
type = typeof(String).Assembly.GetType(typeName);
}
if (type == null) {
type = typeof(Component).Assembly.GetType(typeName);
}
return type;
}

Loading…
Cancel
Save