From bbe48609abd5b437dcfc727051a48b48a2010deb Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Mon, 25 May 2009 14:18:15 +0000 Subject: [PATCH] Added support for ContextMenuStrips in the python forms designer. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4145 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/PythonBinding.csproj | 1 + .../Src/NRefactoryToPythonConverter.cs | 20 +--- .../Project/Src/PythonCodeBuilder.cs | 43 ++++++- .../Project/Src/PythonComponentWalker.cs | 11 +- .../Project/Src/PythonContextMenuComponent.cs | 30 +++++ .../Project/Src/PythonControl.cs | 23 ++-- .../Project/Src/PythonDesignerComponent.cs | 108 +++++++++++------- .../Src/PythonDesignerComponentFactory.cs | 4 +- .../Src/PythonDesignerRootComponent.cs | 72 +++--------- .../Project/Src/PythonListViewComponent.cs | 3 +- .../GenerateBackgroundWorkerTestFixture.cs | 17 +-- .../GenerateContextMenuStripTestFixture.cs | 105 +++++++++++++++++ .../Designer/GenerateEventLogTestFixture.cs | 1 - .../GenerateListViewItemTestFixture.cs | 10 +- .../GenerateMenuStripItemsTestFixture.cs | 8 -- .../GenerateNestedPanelFormTestFixture.cs | 2 +- .../Designer/GeneratePanelFormTestFixture.cs | 2 +- .../Designer/GenerateSimpleFormTestFixture.cs | 2 +- .../Test/Designer/GenerateTimerTestFixture.cs | 17 +-- .../GeneratedControlOrderingTestFixture.cs | 18 ++- ...etInstanceFromDesignerLoaderTestFixture.cs | 16 +++ .../Test/Designer/PythonCodeBuilderTests.cs | 28 +++++ .../PythonDesignerLoaderTestFixture.cs | 2 +- .../Test/PythonBinding.Tests.csproj | 2 + .../Python/PythonBinding/Test/TODO.txt | 7 +- .../Test/Utils/DerivedToolStripMenuItem.cs | 19 +++ 26 files changed, 363 insertions(+), 208 deletions(-) create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonContextMenuComponent.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateContextMenuStripTestFixture.cs create mode 100644 src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedToolStripMenuItem.cs diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj index 3d61f5ab24..6580e9b3ff 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/PythonBinding.csproj @@ -87,6 +87,7 @@ + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs index 7e870544ea..0b92a7980f 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/NRefactoryToPythonConverter.cs @@ -1476,25 +1476,7 @@ namespace ICSharpCode.PythonBinding return (assignmentExpression.Op == AssignmentOperatorType.Subtract) && (assignmentExpression.Left is MemberReferenceExpression); } - - /// - /// Creates an assign statement with the right hand side of the assignment using a binary operator. - /// - object CreateAssignmentStatementWithBinaryOperatorExpression(AssignmentExpression assignmentExpression, string binaryOperatorType) - { - // Create the left hand side of the assignment. - assignmentExpression.Left.AcceptVisitor(this, null); - - Append(" = "); - - // Create the right hand side of the assignment. - assignmentExpression.Left.AcceptVisitor(this, null); - Append(" " + binaryOperatorType + " "); - assignmentExpression.Right.AcceptVisitor(this, null); - - return null; - } - + void Append(string code) { codeBuilder.Append(code); diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeBuilder.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeBuilder.cs index ef24bb2fe6..fafaf81788 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeBuilder.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonCodeBuilder.cs @@ -6,6 +6,7 @@ // using System; +using System.ComponentModel; using System.Text; namespace ICSharpCode.PythonBinding @@ -15,6 +16,7 @@ namespace ICSharpCode.PythonBinding StringBuilder codeBuilder = new StringBuilder(); string indentString = "\t"; int indent; + bool insertedCreateComponentsContainer; public PythonCodeBuilder() { @@ -62,12 +64,38 @@ namespace ICSharpCode.PythonBinding /// public void AppendIndented(string text) { - for (int i = 0; i < indent; ++i) { - codeBuilder.Append(indentString); - } + codeBuilder.Append(GetIndentString()); codeBuilder.Append(text); } + + /// + /// Inserts a new line at the start of the code before everything else. + /// + public void InsertIndentedLine(string text) + { + text = GetIndentString() + text + "\r\n"; + codeBuilder.Insert(0, text, 1); + } + /// + /// Inserts the following line of code before all the other lines of code: + /// + /// "self._components = System.ComponentModel.Container()" + /// + /// This line will only be inserted once. Multiple calls to this method will only result in one + /// line of code being inserted. + /// + public void InsertCreateComponentsContainer() + { + if (!insertedCreateComponentsContainer) { + InsertIndentedLine("self._components = " + typeof(Container).FullName + "()"); + insertedCreateComponentsContainer = true; + } + } + + /// + /// Inserts the text with a carriage return and newline at the end. + /// public void AppendIndentedLine(string text) { AppendIndented(text + "\r\n"); @@ -93,5 +121,14 @@ namespace ICSharpCode.PythonBinding public int Length { get { return codeBuilder.Length; } } + + string GetIndentString() + { + StringBuilder currentIndentString = new StringBuilder(); + for (int i = 0; i < indent; ++i) { + currentIndentString.Append(indentString); + } + return currentIndentString.ToString(); + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs index 2d95a8f134..fb2d6ad1b0 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonComponentWalker.cs @@ -283,16 +283,7 @@ namespace ICSharpCode.PythonBinding /// object GetPropertyValueFromAssignmentRhs(MemberExpression memberExpression) { - object propertyValue = deserializer.Deserialize(memberExpression); - if (propertyValue == null) { - PythonControlFieldExpression field = PythonControlFieldExpression.Create(memberExpression); - if (field.MemberName.Length > 0) { - propertyValue = GetComponent(PythonControlFieldExpression.GetVariableName(field.MemberName)); - } else { - propertyValue = field.FullMemberName; - } - } - return propertyValue; + return deserializer.Deserialize(memberExpression); } /// diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonContextMenuComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonContextMenuComponent.cs new file mode 100644 index 0000000000..59158b931d --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonContextMenuComponent.cs @@ -0,0 +1,30 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.ComponentModel; + +namespace ICSharpCode.PythonBinding +{ + public class PythonContextMenuComponent : PythonDesignerComponent + { + public PythonContextMenuComponent(PythonDesignerComponent parent, IComponent component) + : base(parent, component) + { + } + + /// + /// Always ignore the OwnerItem property. This is set if the context menu is open and displayed in + /// the designer when the user switches to the source tab. This method works around the problem by + /// ignoring the OwnerItem property when generating the form designer code. + /// + protected override bool IgnoreProperty(PropertyDescriptor property) + { + return property.Name == "OwnerItem"; + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs index 415c6eb6ae..8d260b9315 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonControl.cs @@ -43,15 +43,19 @@ namespace ICSharpCode.PythonBinding /// public string GenerateInitializeComponentMethod(Control control) { + PythonCodeBuilder methodCodeBuilder = new PythonCodeBuilder(); + methodCodeBuilder.IndentString = indentString; + + methodCodeBuilder.AppendIndentedLine("def InitializeComponent(self):"); + codeBuilder = new PythonCodeBuilder(); codeBuilder.IndentString = indentString; - - codeBuilder.AppendIndentedLine("def InitializeComponent(self):"); codeBuilder.IncreaseIndent(); GenerateInitializeComponentMethodBodyInternal(control); - return codeBuilder.ToString(); + methodCodeBuilder.Append(codeBuilder.ToString()); + return methodCodeBuilder.ToString(); } /// @@ -73,20 +77,13 @@ namespace ICSharpCode.PythonBinding void GenerateInitializeComponentMethodBodyInternal(Control control) { PythonDesignerRootComponent rootDesignerComponent = PythonDesignerComponentFactory.CreateDesignerRootComponent(control); - if (rootDesignerComponent.HasNonVisualChildComponents()) { - rootDesignerComponent.AppendCreateComponentsContainer(codeBuilder); - rootDesignerComponent.AppendCreateNonVisualComponents(codeBuilder); - rootDesignerComponent.AppendNonVisualComponentsBeginInit(codeBuilder); - } - rootDesignerComponent.AppendCreateChildComponents(codeBuilder); + rootDesignerComponent.AppendCreateContainerComponents(codeBuilder); + rootDesignerComponent.AppendNonVisualComponentsBeginInit(codeBuilder); rootDesignerComponent.AppendChildComponentsSuspendLayout(codeBuilder); rootDesignerComponent.AppendSuspendLayout(codeBuilder); - rootDesignerComponent.AppendNonVisualComponents(codeBuilder); rootDesignerComponent.AppendComponent(codeBuilder); rootDesignerComponent.AppendChildComponentsResumeLayout(codeBuilder); - if (rootDesignerComponent.HasNonVisualChildComponents()) { - rootDesignerComponent.AppendNonVisualComponentsEndInit(codeBuilder); - } + rootDesignerComponent.AppendNonVisualComponentsEndInit(codeBuilder); rootDesignerComponent.AppendResumeLayout(codeBuilder); } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs index cbc77ab830..8a2628f236 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponent.cs @@ -213,13 +213,18 @@ namespace ICSharpCode.PythonBinding } return null; } - + /// /// Appends code that creates an instance of the component. /// public virtual void AppendCreateInstance(PythonCodeBuilder codeBuilder) { - AppendComponentCreation(codeBuilder, component); + if (HasIContainerConstructor()) { + codeBuilder.InsertCreateComponentsContainer(); + AppendCreateInstance(codeBuilder, "self._components"); + } else { + AppendComponentCreation(codeBuilder, component); + } } public void AppendCreateInstance(PythonCodeBuilder codeBuilder, string parameters) @@ -235,13 +240,34 @@ namespace ICSharpCode.PythonBinding AppendCreateChildComponents(codeBuilder, GetChildComponents()); } + /// + /// Adds all the components that have been added to the design surface container. + /// + public void AppendCreateContainerComponents(PythonCodeBuilder codeBuilder) + { + AppendCreateChildComponents(codeBuilder, GetContainerComponents()); + } + + /// + /// Gets all the components added to the design surface container excluding the + /// root component. + /// + public PythonDesignerComponent[] GetContainerComponents() + { + List components = new List(); + ComponentCollection containerComponents = Component.Site.Container.Components; + for (int i = 1; i < containerComponents.Count; ++i) { + components.Add(PythonDesignerComponentFactory.CreateDesignerComponent(this, containerComponents[i])); + } + return components.ToArray(); + } + /// /// Appends the component's properties. /// public virtual void AppendComponent(PythonCodeBuilder codeBuilder) { AppendComponentProperties(codeBuilder); - AppendChildComponentProperties(codeBuilder); } /// @@ -365,37 +391,15 @@ namespace ICSharpCode.PythonBinding { codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "(" + parameters + ")"); } - + /// /// Generates the code for the component's properties. /// public void AppendComponentProperties(PythonCodeBuilder codeBuilder) { - AppendComponentProperties(codeBuilder, true, false, true); + AppendComponentProperties(codeBuilder, true, true); } - - /// - /// Appends the properties of any component that is contained in a collection property that is - /// marked as DesignerSerializationVisibility.Content. - /// - public void AppendChildComponentProperties(PythonCodeBuilder codeBuilder) - { - foreach (PropertyDescriptor property in PythonDesignerComponent.GetSerializableContentProperties(component)) { - object propertyCollection = property.GetValue(component); - ICollection collection = propertyCollection as ICollection; - if (collection != null) { - foreach (object childObject in collection) { - IComponent childComponent = childObject as IComponent; - if (childComponent != null) { - PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(this, childComponent); - if (designerComponent.IsSited) { - designerComponent.AppendComponentProperties(codeBuilder, true, true, true); - } - } - } - } - } - } + /// /// Generates python code for an object's properties when the object is not an IComponent. /// @@ -443,6 +447,14 @@ namespace ICSharpCode.PythonBinding return typeName[0].ToString().ToLowerInvariant() + typeName.Substring(1) + count; } + /// + /// Appends an array as a parameter and its associated method call. + /// + public virtual void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor) + { + AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor, false); + } + /// /// Appends an array as a parameter and its associated method call. /// @@ -450,7 +462,7 @@ namespace ICSharpCode.PythonBinding /// Looks for the AddRange method first. If that does not exist or is hidden from the designer the /// Add method is looked for. /// - public static void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor) + 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; @@ -462,6 +474,9 @@ namespace ICSharpCode.PythonBinding } else { MethodInfo addMethod = GetAddSerializationMethod(collectionProperty); ParameterInfo[] parameters = addMethod.GetParameters(); + if (reverse) { + collectionProperty = ReverseCollection(collectionProperty); + } foreach (object item in collectionProperty) { IComponent collectionComponent = item as IComponent; if (PythonDesignerComponent.IsSitedComponent(collectionComponent)) { @@ -477,11 +492,7 @@ namespace ICSharpCode.PythonBinding /// public void AppendProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj, PropertyDescriptor propertyDescriptor) { - object propertyValue = propertyDescriptor.GetValue(obj); - if (propertyValue == null) { - return; - } - + object propertyValue = propertyDescriptor.GetValue(obj); ExtenderProvidedPropertyAttribute extender = GetExtenderAttribute(propertyDescriptor); if (extender != null) { AppendExtenderProperty(codeBuilder, propertyOwnerName, extender, propertyDescriptor, propertyValue); @@ -521,7 +532,9 @@ namespace ICSharpCode.PythonBinding public void AppendProperties(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj) { foreach (PropertyDescriptor property in GetSerializableProperties(obj)) { - AppendProperty(codeBuilder, propertyOwnerName, obj, property); + if (!IgnoreProperty(property)) { + AppendProperty(codeBuilder, propertyOwnerName, obj, property); + } } } @@ -536,7 +549,7 @@ namespace ICSharpCode.PythonBinding /// /// Generates python code for the component. /// - public void AppendComponentProperties(PythonCodeBuilder codeBuilder, bool addComponentNameToProperty, bool addChildComponentProperties, bool addComment) + public void AppendComponentProperties(PythonCodeBuilder codeBuilder, bool addComponentNameToProperty, bool addComment) { PythonCodeBuilder propertiesBuilder = new PythonCodeBuilder(codeBuilder.Indent); propertiesBuilder.IndentString = codeBuilder.IndentString; @@ -549,10 +562,6 @@ namespace ICSharpCode.PythonBinding AppendComment(codeBuilder); } codeBuilder.Append(propertiesBuilder.ToString()); - - if (addChildComponentProperties) { - AppendChildComponentProperties(codeBuilder); - } } /// @@ -611,6 +620,14 @@ namespace ICSharpCode.PythonBinding get { return component; } } + /// + /// Return true to prevent the property from being added to the generated code. + /// + protected virtual bool IgnoreProperty(PropertyDescriptor property) + { + return false; + } + static bool HasSitedComponents(PythonDesignerComponent[] components) { foreach (PythonDesignerComponent component in components) { @@ -626,7 +643,6 @@ namespace ICSharpCode.PythonBinding foreach (PythonDesignerComponent designerComponent in childComponents) { if (designerComponent.IsSited) { designerComponent.AppendCreateInstance(codeBuilder); - designerComponent.AppendCreateChildComponents(codeBuilder); } } } @@ -724,5 +740,15 @@ namespace ICSharpCode.PythonBinding } return null; } + + static ICollection ReverseCollection(ICollection collection) + { + List reversedCollection = new List(); + foreach (object item in collection) { + reversedCollection.Add(item); + } + reversedCollection.Reverse(); + return reversedCollection; + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs index 350e074b97..f580162db1 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerComponentFactory.cs @@ -31,7 +31,9 @@ namespace ICSharpCode.PythonBinding public static PythonDesignerComponent CreateDesignerComponent(PythonDesignerComponent parent, IComponent component) { if (component is ListView) { - return new PythonListViewComponent(parent,component); + return new PythonListViewComponent(parent, component); + } else if (component is ContextMenuStrip) { + return new PythonContextMenuComponent(parent, component); } return new PythonDesignerComponent(parent, component); } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs index 90b0b4859d..228e3ba1e0 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonDesignerRootComponent.cs @@ -41,37 +41,14 @@ namespace ICSharpCode.PythonBinding public override void AppendComponent(PythonCodeBuilder codeBuilder) { // Add the child components first. - foreach (PythonDesignerComponent component in GetChildComponents()) { + foreach (PythonDesignerComponent component in GetContainerComponents()) { component.AppendComponent(codeBuilder); } // Add root component - AppendComponentProperties(codeBuilder, false, false, true); + AppendComponentProperties(codeBuilder, false, true); } - - /// - /// Gets the child components in reverse order since the forms designer has them reversed. - /// - public override PythonDesignerComponent[] GetChildComponents() - { - PythonDesignerComponent[] components = base.GetChildComponents(); - Array.Reverse(components); - return components; - } - - /// - /// Returns true if non-visual components (e.g. Timer) are associated with this root component. - /// - public bool HasNonVisualChildComponents() - { - foreach (IComponent containerComponent in Component.Site.Container.Components) { - if (IsNonVisualComponent(containerComponent)) { - return true; - } - } - return false; - } - + public PythonDesignerComponent[] GetNonVisualChildComponents() { List components = new List(); @@ -83,39 +60,7 @@ namespace ICSharpCode.PythonBinding } return components.ToArray(); } - - /// - /// Appends an expression that creates an instance of the Container to hold non-visual components - /// - public void AppendCreateComponentsContainer(PythonCodeBuilder codeBuilder) - { - codeBuilder.AppendIndentedLine("self._components = " + typeof(Container).FullName + "()"); - } - - /// - /// Appends code to create all the non-visual component. - /// - public void AppendCreateNonVisualComponents(PythonCodeBuilder codeBuilder) - { - foreach (PythonDesignerComponent component in GetNonVisualChildComponents()) { - if (component.HasIContainerConstructor()) { - component.AppendCreateInstance(codeBuilder, "self._components"); - } else { - component.AppendCreateInstance(codeBuilder); - } - } - } - - /// - /// Appends code to set all the non-visual component properties. - /// - public void AppendNonVisualComponents(PythonCodeBuilder codeBuilder) - { - foreach (PythonDesignerComponent component in GetNonVisualChildComponents()) { - component.AppendComponent(codeBuilder); - } - } - + /// /// Adds BeginInit method call for any non-visual components that implement the /// System.ComponentModel.ISupportInitialize interface. @@ -142,5 +87,14 @@ namespace ICSharpCode.PythonBinding } } } + + /// + /// Reverses the ordering when adding items to the Controls collection. + /// + public override void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor) + { + bool reverse = propertyDescriptor.Name == "Controls"; + AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor, reverse); + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs index 64a9c3d9ab..751bbdc0e2 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonListViewComponent.cs @@ -48,8 +48,7 @@ namespace ICSharpCode.PythonBinding { AppendComment(codeBuilder); AppendListViewItemProperties(codeBuilder); - AppendComponentProperties(codeBuilder, true, false, false); - AppendChildComponentProperties(codeBuilder); + AppendComponentProperties(codeBuilder, true, false); } /// diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateBackgroundWorkerTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateBackgroundWorkerTestFixture.cs index 766ca7f239..3864ac5389 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateBackgroundWorkerTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateBackgroundWorkerTestFixture.cs @@ -20,7 +20,6 @@ namespace PythonBinding.Tests.Designer public class GenerateBackgroundWorkerTestFixture { string generatedPythonCode; - bool hasNonVisualChildComponents; bool hasIContainerConstructor; [TestFixtureSetUp] @@ -40,29 +39,19 @@ namespace PythonBinding.Tests.Designer propertyDescriptor = descriptors.Find("WorkerReportsProgress", false); propertyDescriptor.SetValue(worker, true); - string indentString = " "; - PythonDesignerRootComponent designerRootComponent = new PythonDesignerRootComponent(form); - hasNonVisualChildComponents = designerRootComponent.HasNonVisualChildComponents(); - PythonDesignerComponent component = new PythonDesignerComponent(worker); hasIContainerConstructor = component.HasIContainerConstructor(); - + + string indentString = " "; 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._backgroundWorker1 = System.ComponentModel.BackgroundWorker()\r\n" + " self.SuspendLayout()\r\n" + " # \r\n" + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateContextMenuStripTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateContextMenuStripTestFixture.cs new file mode 100644 index 0000000000..2d514fb56b --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateContextMenuStripTestFixture.cs @@ -0,0 +1,105 @@ +// +// +// +// +// $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 +{ + [TestFixture] + public class GenerateContextMenuStripTestFixture + { + string generatedPythonCode; + string createContextMenuStripCode; + Size menuStripSize; + PythonDesignerComponent contextMenuDesignerComponent; + + [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 timer. This checks that the components Container is only created once in the + // generated code. + Timer timer = (Timer)host.CreateComponent(typeof(Timer), "timer1"); + + // Add menu strip. + ContextMenuStrip menuStrip = (ContextMenuStrip)host.CreateComponent(typeof(ContextMenuStrip), "contextMenuStrip1"); + + // Set the context menu strip OwnerItem to simulate leaving the context menu + // open in the designer before generating the source code. We do not want the + // OwnerItem to be serialized. + menuStrip.OwnerItem = new DerivedToolStripMenuItem(); + menuStrip.RightToLeft = RightToLeft.No; + menuStripSize = menuStrip.Size; + + PythonControl pythonForm = new PythonControl(" "); + generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form); + + PythonCodeBuilder codeBuilder = new PythonCodeBuilder(); + contextMenuDesignerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(menuStrip); + contextMenuDesignerComponent.AppendCreateInstance(codeBuilder); + + createContextMenuStripCode = codeBuilder.ToString(); + } + } + + [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._contextMenuStrip1 = System.Windows.Forms.ContextMenuStrip(self._components)\r\n" + + " self.SuspendLayout()\r\n" + + " # \r\n" + + " # contextMenuStrip1\r\n" + + " # \r\n" + + " self._contextMenuStrip1.Name = \"contextMenuStrip1\"\r\n" + + " self._contextMenuStrip1.Size = " + PythonPropertyValueAssignment.ToString(menuStripSize) + "\r\n" + + " # \r\n" + + " # MainForm\r\n" + + " # \r\n" + + " self.ClientSize = System.Drawing.Size(200, 300)\r\n" + + " self.Name = \"MainForm\"\r\n" + + " self.ResumeLayout(False)\r\n" + + " self.PerformLayout()\r\n"; + + Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode); + } + + [Test] + public void CreateContextMenuStripCodeUsesIContainerConstructor() + { + string expectedCode = "self._components = System.ComponentModel.Container()\r\n" + + "self._contextMenuStrip1 = System.Windows.Forms.ContextMenuStrip(self._components)\r\n"; + Assert.AreEqual(expectedCode, createContextMenuStripCode); + } + + [Test] + public void ContextMenuDesignerComponentCreatedFromFactory() + { + Assert.IsInstanceOf(typeof(PythonContextMenuComponent), contextMenuDesignerComponent); + } + } +} diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateEventLogTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateEventLogTestFixture.cs index 2c587b3ade..fcd737ee6f 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateEventLogTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateEventLogTestFixture.cs @@ -47,7 +47,6 @@ namespace PythonBinding.Tests.Designer public void GeneratedCode() { string expectedCode = "def InitializeComponent(self):\r\n" + - " self._components = System.ComponentModel.Container()\r\n" + " self._eventLog1 = System.Diagnostics.EventLog()\r\n" + " self._eventLog1.BeginInit()\r\n" + " self.SuspendLayout()\r\n" + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs index 5629f34399..8d8a8db7bc 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateListViewItemTestFixture.cs @@ -228,15 +228,7 @@ namespace PythonBinding.Tests.Designer " self._listView1.Name = \"listView1\"\r\n" + " self._listView1.Size = System.Drawing.Size(204, 104)\r\n" + " self._listView1.TabIndex = 0\r\n" + - " self._listView1.View = System.Windows.Forms.View.Details\r\n" + - " # \r\n" + - " # columnHeader1\r\n" + - " # \r\n" + - " self._columnHeader1.Text = \"columnHeader1\"\r\n" + - " # \r\n" + - " # columnHeader2\r\n" + - " # \r\n" + - " self._columnHeader2.Text = \"columnHeader2\"\r\n"; + " self._listView1.View = System.Windows.Forms.View.Details\r\n"; Assert.AreEqual(expectedCode, listViewPropertiesCode); } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs index dd8a433bf5..f2b205bb6d 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateMenuStripItemsTestFixture.cs @@ -26,7 +26,6 @@ namespace PythonBinding.Tests.Designer Size openMenuItemSize; Size exitMenuItemSize; Size editMenuItemSize; - bool nonVisualComponents; [TestFixtureSetUp] public void SetUpFixture() @@ -77,7 +76,6 @@ namespace PythonBinding.Tests.Designer editMenuItemSize = editMenuItem.Size; PythonDesignerRootComponent rootComponent = new PythonDesignerRootComponent(form); - nonVisualComponents = rootComponent.HasNonVisualChildComponents(); PythonControl pythonForm = new PythonControl(" "); generatedPythonCode = pythonForm.GenerateInitializeComponentMethod(form); @@ -146,12 +144,6 @@ namespace PythonBinding.Tests.Designer Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode); } - - [Test] - public void NoNonVisualComponents() - { - Assert.IsFalse(nonVisualComponents); - } string SizeToString(Size size) { diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateNestedPanelFormTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateNestedPanelFormTestFixture.cs index 1bc18b359d..f8107a1c88 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateNestedPanelFormTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateNestedPanelFormTestFixture.cs @@ -107,7 +107,7 @@ namespace PythonBinding.Tests.Designer " self.ResumeLayout(False)\r\n" + " self.PerformLayout()\r\n"; - Assert.AreEqual(expectedCode, generatedPythonCode); + Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode); } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratePanelFormTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratePanelFormTestFixture.cs index e5f753ea13..50b46278da 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratePanelFormTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratePanelFormTestFixture.cs @@ -94,7 +94,7 @@ namespace PythonBinding.Tests.Designer " self.ResumeLayout(False)\r\n" + " self.PerformLayout()\r\n"; - Assert.AreEqual(expectedCode, generatedPythonCode); + Assert.AreEqual(expectedCode, generatedPythonCode, generatedPythonCode); } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs index f35270c287..a1a5c44437 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateSimpleFormTestFixture.cs @@ -44,7 +44,7 @@ namespace PythonBinding.Tests.Designer codeBuilder.IncreaseIndent(); PythonDesignerRootComponent designerRootComponent = new PythonDesignerRootComponent(form); propertyOwnerName = designerRootComponent.GetPropertyOwnerName(); - designerRootComponent.AppendComponentProperties(codeBuilder, true, false, false); + designerRootComponent.AppendComponentProperties(codeBuilder, true, false); formPropertiesCode = codeBuilder.ToString(); } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs index ab829346c9..32c196c96d 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GenerateTimerTestFixture.cs @@ -20,8 +20,8 @@ namespace PythonBinding.Tests.Designer public class GenerateTimerTestFixture { string generatedPythonCode; - bool hasNonVisualChildComponents; bool hasIContainerConstructor; + [TestFixtureSetUp] public void SetUpFixture() { @@ -38,25 +38,16 @@ namespace PythonBinding.Tests.Designer descriptors = TypeDescriptor.GetProperties(timer); namePropertyDescriptor = descriptors.Find("Interval", false); namePropertyDescriptor.SetValue(timer, 1000); - - string indentString = " "; - PythonDesignerRootComponent designerRootComponent = new PythonDesignerRootComponent(form); - hasNonVisualChildComponents = designerRootComponent.HasNonVisualChildComponents(); - + PythonDesignerComponent component = new PythonDesignerComponent(timer); hasIContainerConstructor = component.HasIContainerConstructor(); + string indentString = " "; PythonControl pythonControl = new PythonControl(indentString); generatedPythonCode = pythonControl.GenerateInitializeComponentMethod(form); } } - - [Test] - public void HasNonVisualChildComponents() - { - Assert.IsTrue(hasNonVisualChildComponents); - } - + [Test] public void GeneratedCode() { diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratedControlOrderingTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratedControlOrderingTestFixture.cs index aa08c19a96..66dea0817c 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratedControlOrderingTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GeneratedControlOrderingTestFixture.cs @@ -36,17 +36,7 @@ namespace PythonBinding.Tests.Designer PropertyDescriptorCollection descriptors = TypeDescriptor.GetProperties(form); PropertyDescriptor namePropertyDescriptor = descriptors.Find("Name", false); namePropertyDescriptor.SetValue(form, "MainForm"); - - RadioButton radioButton = (RadioButton)host.CreateComponent(typeof(RadioButton), "radioButton1"); - radioButton.Location = new Point(20, 0); - radioButton.Size = new Size(10, 10); - radioButton.Text = "radioButton1"; - radioButton.TabIndex = 1; - radioButton.UseCompatibleTextRendering = false; - form.Controls.Add(radioButton); - // Add button after radio button to simulate the forms designer - // behaviour of adding the controls in reverse order to the Controls collection. Button button = (Button)host.CreateComponent(typeof(Button), "button1"); button.Location = new Point(0, 0); button.Size = new Size(10, 10); @@ -54,6 +44,14 @@ namespace PythonBinding.Tests.Designer button.TabIndex = 0; button.UseCompatibleTextRendering = false; form.Controls.Add(button); + + RadioButton radioButton = (RadioButton)host.CreateComponent(typeof(RadioButton), "radioButton1"); + radioButton.Location = new Point(20, 0); + radioButton.Size = new Size(10, 10); + radioButton.Text = "radioButton1"; + radioButton.TabIndex = 1; + radioButton.UseCompatibleTextRendering = false; + form.Controls.Add(radioButton); string indentString = " "; PythonControl pythonForm = new PythonControl(indentString); diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetInstanceFromDesignerLoaderTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetInstanceFromDesignerLoaderTestFixture.cs index 0841692169..67c38f6eb3 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetInstanceFromDesignerLoaderTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetInstanceFromDesignerLoaderTestFixture.cs @@ -25,6 +25,8 @@ namespace PythonBinding.Tests.Designer MockDesignerLoaderHost host; ListViewItem listViewItem1; object instance; + Type type; + string typeName; [SetUp] public void Init() @@ -37,6 +39,8 @@ namespace PythonBinding.Tests.Designer using (designerSerializationManager.CreateSession()) { listViewItem1 = (ListViewItem)loader.CreateInstance(typeof(ListViewItem), new object[0], "listViewItem1", false); instance = loader.GetInstance("listViewItem1"); + typeName = typeof(Int32).FullName; + type = loader.GetType(typeName); } } @@ -46,5 +50,17 @@ namespace PythonBinding.Tests.Designer { Assert.AreEqual(listViewItem1, instance); } + + [Test] + public void GetTypeFromLoader() + { + Assert.AreEqual(typeof(Int32), type); + } + + [Test] + public void TypeNameUsed() + { + Assert.AreEqual(typeName, host.TypeResolutionService.LastTypeNameResolved); + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeBuilderTests.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeBuilderTests.cs index a602ceb816..a886d276f2 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeBuilderTests.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonCodeBuilderTests.cs @@ -100,5 +100,33 @@ namespace PythonBinding.Tests.Designer codeBuilder.AppendIndented("abc"); Assert.AreEqual("\t\tabc", codeBuilder.ToString()); } + + [Test] + public void InsertIndentedLine() + { + codeBuilder.IncreaseIndent(); + codeBuilder.AppendIndentedLine("def"); + codeBuilder.InsertIndentedLine("abc"); + Assert.AreEqual("\tabc\r\n\tdef\r\n", codeBuilder.ToString()); + } + + /// + /// Check that the "self._components = System.ComponentModel.Container()" line is generated + /// the once and before any other lines of code. + /// + [Test] + public void AppendCreateComponentsContainerTwice() + { + codeBuilder.IndentString = " "; + codeBuilder.IncreaseIndent(); + codeBuilder.AppendIndentedLine("self._listView = System.Windows.Forms.ListView()"); + codeBuilder.InsertCreateComponentsContainer(); + codeBuilder.InsertCreateComponentsContainer(); + + string expectedCode = " self._components = System.ComponentModel.Container()\r\n" + + " self._listView = System.Windows.Forms.ListView()\r\n"; + + Assert.AreEqual(expectedCode, codeBuilder.ToString()); + } } } diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs index 98a7b875bf..a47adc6c89 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/PythonDesignerLoaderTestFixture.cs @@ -142,7 +142,7 @@ namespace PythonBinding.Tests.Designer { Assert.AreEqual(designedForm, loader.RootComponent); } - + /// /// The code that the designer loader will parse. /// diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj index f0ae1e2f61..83c1bf4d75 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj @@ -170,6 +170,7 @@ + @@ -291,6 +292,7 @@ + diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt b/src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt index d07ca80315..bcb96474e9 100644 --- a/src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/TODO.txt @@ -88,7 +88,12 @@ def main(args): Handle invalid event name. Check that += operator used. -* ContextMenuStrip - designer does not generate the correct code. +* ContextMenuStrip + + If the context menu is added for the first time and left open and displayed on the form when + switching to the source code you see an OwnerItem property added to the context menu variable: + + self._contextMenuStrip1.OwnerItem = ContextMenuStrip * Look at fixing the compiled exe so it can be run from a different folder. diff --git a/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedToolStripMenuItem.cs b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedToolStripMenuItem.cs new file mode 100644 index 0000000000..f7a7bd9ab5 --- /dev/null +++ b/src/AddIns/BackendBindings/Python/PythonBinding/Test/Utils/DerivedToolStripMenuItem.cs @@ -0,0 +1,19 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows.Forms; + +namespace PythonBinding.Tests.Utils +{ + public class DerivedToolStripMenuItem : ToolStripMenuItem + { + public DerivedToolStripMenuItem() : base() + { + } + } +}