diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs index 9d4477fd3c..8161f13804 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControlFieldExpression.cs @@ -202,14 +202,38 @@ namespace ICSharpCode.PythonBinding } return null; } + + /// + /// Looks for a field in the component with the given name. + /// + public static object GetInheritedObject(string name, object component) + { + if (component != null) { + FieldInfo[] fields = component.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance); + foreach (FieldInfo field in fields) { + if (String.Equals(name, field.Name, StringComparison.InvariantCultureIgnoreCase)) { + return field.GetValue(component); + } + } + } + return null; + } /// /// Gets the object that the field expression variable refers to. /// + /// + /// This method will also check form's base class for any inherited objects that match + /// the object being referenced. + /// public object GetObject(IComponentCreator componentCreator) { if (variableName.Length > 0) { - return componentCreator.GetComponent(variableName); + object component = componentCreator.GetComponent(variableName); + if (component != null) { + return component; + } + return GetInheritedObject(variableName, componentCreator.RootComponent); } return componentCreator.RootComponent; } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs index 1eff0315d9..9e85fe4bfc 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs @@ -284,25 +284,46 @@ namespace ICSharpCode.PythonBinding } /// - /// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.InheritedReadOnly + /// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.Inherited or + /// InheritanceLevel.InheritedReadOnly /// - public static bool IsInheritedReadOnlyComponent(object component) + public static bool IsInheritedComponent(object component) { if (component != null) { - AttributeCollection attributes = TypeDescriptor.GetAttributes(component); - InheritanceAttribute attribute = (InheritanceAttribute)attributes[typeof(InheritanceAttribute)]; - if (attribute != null) { - return attribute.InheritanceLevel == InheritanceLevel.InheritedReadOnly; - } + InheritanceAttribute attribute = GetInheritanceAttribute(component); + return attribute.InheritanceLevel != InheritanceLevel.NotInherited; } return false; } + /// + /// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.Inherited or + /// InheritanceLevel.InheritedReadOnly + /// + public bool IsInherited { + get { return IsInheritedComponent(component); } + } + /// /// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.InheritedReadOnly /// public bool IsInheritedReadOnly { - get { return IsInheritedReadOnlyComponent(component); } + get { + InheritanceAttribute attribute = GetInheritanceAttribute(component); + if (attribute != null) { + return attribute.InheritanceLevel == InheritanceLevel.InheritedReadOnly; + } + return false; + } + } + + public static InheritanceAttribute GetInheritanceAttribute(object component) + { + if (component != null) { + AttributeCollection attributes = TypeDescriptor.GetAttributes(component); + return attributes[typeof(InheritanceAttribute)] as InheritanceAttribute; + } + return null; } /// @@ -495,7 +516,7 @@ namespace ICSharpCode.PythonBinding } foreach (object item in collectionProperty) { IComponent collectionComponent = item as IComponent; - if (PythonDesignerComponent.IsSitedComponent(collectionComponent) && !PythonDesignerComponent.IsInheritedReadOnlyComponent(collectionComponent)) { + if (PythonDesignerComponent.IsSitedComponent(collectionComponent) && !PythonDesignerComponent.IsInheritedComponent(collectionComponent)) { codeBuilder.AppendIndentedLine(propertyOwnerName + "." + propertyDescriptor.Name + "." + addMethod.Name + "(self._" + collectionComponent.Site.Name + ")"); } } @@ -639,9 +660,15 @@ namespace ICSharpCode.PythonBinding /// /// Gets the owner of any properties generated (e.g. "self._textBox1"). + /// For an inherited component the actual component name is used without any underscore prefix. + /// public virtual string GetPropertyOwnerName() { - return "self._" + component.Site.Name; + string componentName = component.Site.Name; + if (IsInherited) { + return "self." + componentName; + } + return "self._" + componentName; } /// @@ -741,7 +768,7 @@ namespace ICSharpCode.PythonBinding static bool HasSitedComponents(PythonDesignerComponent[] components) { foreach (PythonDesignerComponent component in components) { - if (component.IsSited) { + if (component.IsSited && !component.IsInherited) { return true; } } @@ -751,7 +778,7 @@ namespace ICSharpCode.PythonBinding void AppendCreateChildComponents(PythonCodeBuilder codeBuilder, PythonDesignerComponent[] childComponents) { foreach (PythonDesignerComponent designerComponent in childComponents) { - if (designerComponent.IsSited) { + if (designerComponent.IsSited && !designerComponent.IsInherited) { designerComponent.AppendCreateInstance(codeBuilder); } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateInheritedProtectedPanelFormTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateInheritedProtectedPanelFormTestFixture.cs new file mode 100644 index 0000000000..ff335c3189 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateInheritedProtectedPanelFormTestFixture.cs @@ -0,0 +1,109 @@ +// +// +// +// +// $Revision$ +// + +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 +{ + class ProtectedPanelBaseForm : Form + { + protected Panel panel1 = new Panel(); + Button button1 = new Button(); + + public ProtectedPanelBaseForm() + { + button1.Name = "button1"; + + panel1.Name = "panel1"; + panel1.Location = new Point(5, 10); + panel1.Size = new Size(200, 100); + panel1.Controls.Add(button1); + + Controls.Add(panel1); + } + } + + class ProtectedPanelDerivedForm : ProtectedPanelBaseForm + { + [EditorBrowsableAttribute(EditorBrowsableState.Never)] + internal Point PanelLocation { + get { return panel1.Location; } + set { panel1.Location = value; } + } + + [EditorBrowsableAttribute(EditorBrowsableState.Never)] + internal Size PanelSize { + get { return panel1.Size; } + set { panel1.Size = value; } + } + + [EditorBrowsableAttribute(EditorBrowsableState.Never)] + internal Panel GetPanel() + { + return panel1; + } + } + + /// + /// Tests that no code is generated for a protected panel control in the base class + /// that has child controls. + /// + [TestFixture] + public class GenerateInheritedProtectedPanelFormTestFixture + { + string generatedPythonCode; + + [TestFixtureSetUp] + public void SetUpFixture() + { + using (DesignSurface designSurface = new DesignSurface(typeof(ProtectedPanelDerivedForm))) { + 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"); + + // Move protected panel so we generate code for the new location. + ProtectedPanelDerivedForm derivedForm = (ProtectedPanelDerivedForm)form; + derivedForm.PanelLocation = new Point(10, 15); + + string indentString = " "; + PythonControl pythonForm = new PythonControl(indentString); + generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form); + } + } + + [Test] + public void GeneratedCode() + { + string expectedCode = "def InitializeComponent(self):\r\n" + + " self.SuspendLayout()\r\n" + + " # \r\n" + + " # panel1\r\n" + + " # \r\n" + + " self.panel1.Location = System.Drawing.Point(10, 15)\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); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadInheritedProtectedPanelFormTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadInheritedProtectedPanelFormTestFixture.cs new file mode 100644 index 0000000000..1eebc84f30 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/LoadInheritedProtectedPanelFormTestFixture.cs @@ -0,0 +1,90 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.IO; +using System.Windows.Forms; + +using ICSharpCode.PythonBinding; +using IronPython.Compiler.Ast; +using NUnit.Framework; +using PythonBinding.Tests.Utils; + +namespace PythonBinding.Tests.Designer +{ + [TestFixture] + public class LoadInheritedProtectedPanelFormTestFixture : LoadFormTestFixtureBase + { + public override string PythonCode { + get { + base.ComponentCreator.AddType("PythonBinding.Tests.Designer.ProtectedPanelDerivedForm", typeof(ProtectedPanelDerivedForm)); + + return "class MainForm(PythonBinding.Tests.Designer.ProtectedPanelDerivedForm):\r\n" + + " def InitializeComponent(self):\r\n" + + " self.SuspendLayout()\r\n" + + " # \r\n" + + " # panel1\r\n" + + " # \r\n" + + " self.panel1.Location = System.Drawing.Point(10, 15)\r\n" + + " self.panel1.Size = System.Drawing.Size(108, 120)\r\n" + + " # \r\n" + + " # form1\r\n" + + " # \r\n" + + " self.Location = System.Drawing.Point(10, 20)\r\n" + + " self.Name = \"form1\"\r\n" + + " self.Controls.Add(self._textBox1)\r\n" + + " self.ResumeLayout(False)\r\n"; + } + } + + ProtectedPanelDerivedForm DerivedForm { + get { return Form as ProtectedPanelDerivedForm; } + } + + [Test] + public void PanelLocation() + { + Assert.AreEqual(new Point(10, 15), DerivedForm.PanelLocation); + } + + [Test] + public void PanelSize() + { + Assert.AreEqual(new Size(108, 120), DerivedForm.PanelSize); + } + + [Test] + public void GetProtectedPanelObject() + { + Assert.AreEqual(DerivedForm.GetPanel(), PythonControlFieldExpression.GetInheritedObject("panel1", DerivedForm)); + } + + [Test] + public void GetProtectedPanelObjectIncorrectCase() + { + Assert.AreEqual(DerivedForm.GetPanel(), PythonControlFieldExpression.GetInheritedObject("PANEL1", DerivedForm)); + } + + [Test] + public void GetInheritedObjectPassedNull() + { + Assert.IsNull(PythonControlFieldExpression.GetInheritedObject("panel1", null)); + } + + [Test] + public void GetInheritedPanelObjectFromFieldExpression() + { + AssignmentStatement statement = PythonParserHelper.GetAssignmentStatement("self.panel1.Name = \"abc\""); + PythonControlFieldExpression field = PythonControlFieldExpression.Create(statement.Left[0] as MemberExpression); + + Assert.AreEqual(DerivedForm.GetPanel(), field.GetObject(ComponentCreator)); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj index 3ec24d2b90..c1cf54fd8d 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj @@ -197,6 +197,7 @@ + @@ -235,6 +236,7 @@ +