diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs index a2c85c2172..98fe34e549 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs @@ -24,6 +24,8 @@ namespace ICSharpCode.PythonBinding /// public class PythonDesignerComponent { + delegate void AppendCollectionContent(PythonCodeBuilder codeBuilder, object item, int count); + IComponent component; static readonly Attribute[] notDesignOnlyFilter = new Attribute[] { DesignOnlyAttribute.No }; static readonly DesignerSerializationVisibility[] notHiddenDesignerVisibility = new DesignerSerializationVisibility[] { DesignerSerializationVisibility.Content, DesignerSerializationVisibility.Visible }; @@ -208,19 +210,14 @@ namespace ICSharpCode.PythonBinding /// public virtual void AppendCreateInstance(PythonCodeBuilder codeBuilder) { + string parameters = String.Empty; if (HasIContainerConstructor()) { codeBuilder.InsertCreateComponentsContainer(); - AppendCreateInstance(codeBuilder, "self._components"); - } else { - AppendComponentCreation(codeBuilder, component); - } - } - - public void AppendCreateInstance(PythonCodeBuilder codeBuilder, string parameters) - { + parameters = "self._components"; + } AppendComponentCreation(codeBuilder, component, parameters); } - + /// /// Appends the code to create the child components. /// @@ -420,12 +417,15 @@ namespace ICSharpCode.PythonBinding { AppendComponentCreation(codeBuilder, component, String.Empty); } - + /// /// Appends the code to create the specified IComponent /// public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component, string parameters) { + if (ShouldAppendCollectionContent) { + AppendForEachCollectionContent(codeBuilder, component, AppendCollectionContentCreation); + } codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "(" + parameters + ")"); } @@ -471,6 +471,24 @@ namespace ICSharpCode.PythonBinding } } + /// + /// Looks for any collections that have objects that should be created as local variables + /// in the InitializeComponent method. + /// + public void AppendCollectionContentCreation(PythonCodeBuilder codeBuilder, object item, int count) + { + AppendCreateInstance(codeBuilder, item, count, new object[0]); + } + + /// + /// Looks for any collections that have objects that will have been added as local variables + /// and appends their property values. + /// + public void AppendCollectionContentProperties(PythonCodeBuilder codeBuilder, object item, int count) + { + AppendProperties(codeBuilder, GetVariableName(item, count), item); + } + /// /// Gets the variable name for the specified type. /// @@ -501,7 +519,6 @@ namespace ICSharpCode.PythonBinding /// public static void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor, bool reverse) { - IComponent component = propertyOwner as IComponent; ICollection collectionProperty = propertyDescriptor.GetValue(propertyOwner) as ICollection; if (collectionProperty != null) { MethodInfo addRangeMethod = GetAddRangeSerializationMethod(collectionProperty); @@ -529,7 +546,7 @@ namespace ICSharpCode.PythonBinding /// public void AppendProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj, PropertyDescriptor propertyDescriptor) { - object propertyValue = propertyDescriptor.GetValue(obj); + object propertyValue = propertyDescriptor.GetValue(obj); ExtenderProvidedPropertyAttribute extender = GetExtenderAttribute(propertyDescriptor); if (extender != null) { AppendExtenderProperty(codeBuilder, propertyOwnerName, extender, propertyDescriptor, propertyValue); @@ -601,6 +618,10 @@ namespace ICSharpCode.PythonBinding /// public void AppendProperties(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj) { + if (ShouldAppendCollectionContent) { + AppendForEachCollectionContent(codeBuilder, obj, AppendCollectionContentProperties); + } + foreach (PropertyDescriptor property in GetSerializableProperties(obj)) { if (!IgnoreProperty(property)) { AppendProperty(codeBuilder, propertyOwnerName, obj, property); @@ -781,6 +802,10 @@ namespace ICSharpCode.PythonBinding return false; } + protected virtual bool ShouldAppendCollectionContent { + get { return true; } + } + static bool HasSitedComponents(PythonDesignerComponent[] components) { foreach (PythonDesignerComponent component in components) { @@ -899,5 +924,27 @@ namespace ICSharpCode.PythonBinding } return false; } + + /// + /// Calls the AppendCollectionContent method for every item in all collections that need their content + /// serialized. + /// + void AppendForEachCollectionContent(PythonCodeBuilder codeBuilder, object component, AppendCollectionContent appendCollectionContent) + { + foreach (PropertyDescriptor propertyDescriptor in GetSerializableContentProperties(component)) { + ICollection collection = propertyDescriptor.GetValue(component) as ICollection; + if (collection != null) { + int count = 1; + foreach (object item in collection) { + if (item is IComponent) { + // Ignore. + } else { + appendCollectionContent(codeBuilder, item, count); + } + ++count; + } + } + } + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs index 02de20489b..7741cc31c9 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs @@ -58,6 +58,10 @@ namespace ICSharpCode.PythonBinding AppendListViewGroupProperties(codeBuilder); AppendComponentProperties(codeBuilder, true, false); } + + protected override bool ShouldAppendCollectionContent { + get { return false; } + } /// /// Gets the parameters to the ListViewItem constructor. diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs index 3d73cddac0..ee109bd7c3 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTableLayoutPanelComponent.cs @@ -30,6 +30,10 @@ namespace ICSharpCode.PythonBinding base.AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor); } } + + protected override bool ShouldAppendCollectionContent { + get { return false; } + } bool IsStylesProperty(string name) { diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs index 389e17a0e1..dd441ea589 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonTreeViewComponent.cs @@ -51,6 +51,10 @@ namespace ICSharpCode.PythonBinding AppendComponentProperties(codeBuilder, true, false); } + protected override bool ShouldAppendCollectionContent { + get { return false; } + } + void AppendCreateInstance(PythonCodeBuilder codeBuilder, List nodes) { object[] parameters = new object[0]; diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs new file mode 100644 index 0000000000..1eb07615d2 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateCustomCollectionItemsTestFixture.cs @@ -0,0 +1,89 @@ +// +// +// +// +// $Revision$ +// + +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 +{ + /// + /// Tests that a custom collection class generates the correct code. + /// The collection class should be a property of a custom component or user control + /// and it should be marked with DesignerSerializationVisibility.Content. + /// + [TestFixture] + public class GenerateCustomCollectionItemsTestFixture + { + 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); + + PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(form); + PropertyDescriptor namePropertyDescriptor = descriptors.Find("Name", false); + namePropertyDescriptor.SetValue(form, "MainForm"); + + // Add custom control + CustomUserControl userControl = (CustomUserControl)host.CreateComponent(typeof(CustomUserControl), "userControl1"); + userControl.Location = new Point(0, 0); + userControl.ClientSize = new Size(200, 100); + userControl.FooItems.Add(new FooItem("aa")); + userControl.FooItems.Add(new FooItem("bb")); + form.Controls.Add(userControl); + + PythonControl pythonForm = new PythonControl(" "); + generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form); + } + } + + [Test] + public void GeneratedCode() + { + string expectedCode = "def InitializeComponent(self):\r\n" + + " fooItem1 = PythonBinding.Tests.Utils.FooItem()\r\n" + + " fooItem2 = PythonBinding.Tests.Utils.FooItem()\r\n" + + " self._userControl1 = PythonBinding.Tests.Utils.CustomUserControl()\r\n" + + " self.SuspendLayout()\r\n" + + " # \r\n" + + " # userControl1\r\n" + + " # \r\n" + + " fooItem1.Text = \"aa\"\r\n" + + " fooItem2.Text = \"bb\"\r\n" + + " self._userControl1.FooItems.AddRange(System.Array[PythonBinding.Tests.Utils.FooItem](\r\n" + + " [fooItem1,\r\n" + + " fooItem2]))\r\n" + + " self._userControl1.Location = System.Drawing.Point(0, 0)\r\n" + + " self._userControl1.Name = \"userControl1\"\r\n" + + " self._userControl1.Size = System.Drawing.Size(200, 100)\r\n" + + " self._userControl1.TabIndex = 0\r\n" + + " # \r\n" + + " # MainForm\r\n" + + " # \r\n" + + " self.ClientSize = System.Drawing.Size(200, 300)\r\n" + + " self.Controls.Add(self._userControl1)\r\n" + + " self.Name = \"MainForm\"\r\n" + + " self.ResumeLayout(False)\r\n" + + " self.PerformLayout()\r\n"; + + Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj index d5a3c836ba..51bc41b782 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj @@ -189,6 +189,7 @@ + @@ -327,6 +328,7 @@ + @@ -337,6 +339,7 @@ + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs new file mode 100644 index 0000000000..d50f32e673 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/CustomUserControl.cs @@ -0,0 +1,27 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace PythonBinding.Tests.Utils +{ + public class CustomUserControl : UserControl + { + FooItemCollection fooItems = new FooItemCollection(); + + public CustomUserControl() + { + } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public FooItemCollection FooItems { + get { return fooItems; } + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs new file mode 100644 index 0000000000..40ad8cc321 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/FooItemCollection.cs @@ -0,0 +1,46 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + +namespace PythonBinding.Tests.Utils +{ + public class FooItem + { + string text = String.Empty; + + public FooItem() + { + } + + public FooItem(string text) + { + this.text = text; + } + + public string Text { + get { return text; } + set { text = value; } + } + } + + public class FooItemCollection : Collection + { + public FooItemCollection() + { + } + + public void AddRange(FooItem[] items) + { + foreach (FooItem item in items) { + Add(item); + } + } + } +}