Browse Source

Removed control specific code from generated code when adding an array of controls to a property in the python forms designer.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@3987 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Matt Ward 17 years ago
parent
commit
82e54905b9
  1. 197
      src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonForm.cs
  2. 95
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/FindAddRangeMethodTests.cs
  3. 46
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetSerializableContentPropertiesTestFixture.cs
  4. 2
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/IgnoreDesignTimePropertiesTestFixture.cs
  5. 77
      src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/IsSitedComponentTests.cs
  6. 3
      src/AddIns/BackendBindings/Python/PythonBinding/Test/PythonBinding.Tests.csproj

197
src/AddIns/BackendBindings/Python/PythonBinding/Project/Src/PythonForm.cs

@ -29,7 +29,9 @@ namespace ICSharpCode.PythonBinding @@ -29,7 +29,9 @@ namespace ICSharpCode.PythonBinding
string indentString = String.Empty;
int indent;
IEventBindingService eventBindingService;
Attribute[] notDesignOnlyFilter = new Attribute[] { DesignOnlyAttribute.No };
static readonly Attribute[] notDesignOnlyFilter = new Attribute[] { DesignOnlyAttribute.No };
static readonly DesignerSerializationVisibility[] notHiddenDesignerVisibility = new DesignerSerializationVisibility[] { DesignerSerializationVisibility.Content, DesignerSerializationVisibility.Visible };
static readonly DesignerSerializationVisibility[] contentDesignerVisibility = new DesignerSerializationVisibility[] { DesignerSerializationVisibility.Content };
/// <summary>
/// Used so the EventBindingService.GetEventProperty method can be called to get the property descriptor
@ -115,11 +117,28 @@ namespace ICSharpCode.PythonBinding @@ -115,11 +117,28 @@ namespace ICSharpCode.PythonBinding
/// <summary>
/// Gets a list of properties that should be serialized for the specified form.
/// </summary>
public PropertyDescriptorCollection GetSerializableProperties(object obj)
public static PropertyDescriptorCollection GetSerializableProperties(object obj)
{
return GetSerializableProperties(obj, notHiddenDesignerVisibility);
}
/// <summary>
/// Gets a list of properties that should have their content serialized for the specified form.
/// </summary>
public static PropertyDescriptorCollection GetSerializableContentProperties(object obj)
{
return GetSerializableProperties(obj, contentDesignerVisibility);
}
/// <summary>
/// Gets the serializable properties with the specified designer serialization visibility.
/// </summary>
public static PropertyDescriptorCollection GetSerializableProperties(object obj, DesignerSerializationVisibility[] visibility)
{
List<DesignerSerializationVisibility> requiredVisibility = new List<DesignerSerializationVisibility>(visibility);
List<PropertyDescriptor> properties = new List<PropertyDescriptor>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(obj, notDesignOnlyFilter).Sort()) {
if (property.SerializationVisibility != DesignerSerializationVisibility.Hidden) {
if (requiredVisibility.Contains(property.SerializationVisibility)) {
if (property.ShouldSerializeValue(obj)) {
properties.Add(property);
}
@ -127,6 +146,76 @@ namespace ICSharpCode.PythonBinding @@ -127,6 +146,76 @@ namespace ICSharpCode.PythonBinding
}
return new PropertyDescriptorCollection(properties.ToArray());
}
/// <summary>
/// Determines whether the object is an IComponent and has a non-null ISite.
/// </summary>
public static bool IsSitedComponent(object obj)
{
IComponent component = obj as IComponent;
if (component != null) {
return component.Site != null;
}
return false;
}
/// <summary>
/// Gets the AddRange method on the object that is not hidden from the designer.
/// </summary>
public static MethodInfo GetAddRangeSerializationMethod(object obj)
{
foreach (MethodInfo methodInfo in obj.GetType().GetMethods()) {
if (methodInfo.Name == "AddRange") {
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 1) {
if (parameters[0].ParameterType.IsArray) {
if (!IsHiddenFromDesignerSerializer(methodInfo)) {
return methodInfo;
}
}
}
}
}
return null;
}
/// <summary>
/// Gets the Add serialization method that is not hidden from the designer.
/// </summary>
public static MethodInfo GetAddSerializationMethod(object obj)
{
foreach (MethodInfo methodInfo in obj.GetType().GetMethods()) {
if (methodInfo.Name == "Add") {
return methodInfo;
}
}
return null;
}
/// <summary>
/// Gets the type used in the array for the first parameter to the method.
/// </summary>
public static Type GetArrayParameterType(MethodInfo methodInfo)
{
if (methodInfo != null) {
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length > 0) {
Type arrayType = parameters[0].ParameterType;
return arrayType.GetElementType();
}
}
return null;
}
public static bool IsHiddenFromDesignerSerializer(MethodInfo methodInfo)
{
foreach (DesignerSerializationVisibilityAttribute attribute in methodInfo.GetCustomAttributes(typeof(DesignerSerializationVisibilityAttribute), true)) {
if (attribute.Visibility == DesignerSerializationVisibility.Hidden) {
return true;
}
}
return false;
}
void GenerateInitializeComponentMethodBodyInternal(Form form)
{
@ -189,35 +278,17 @@ namespace ICSharpCode.PythonBinding @@ -189,35 +278,17 @@ namespace ICSharpCode.PythonBinding
return;
}
string propertyName = GetPropertyName(propertyOwnerName, propertyDescriptor.Name);
if (propertyDescriptor.SerializationVisibility == DesignerSerializationVisibility.Visible) {
string propertyName = GetPropertyName(propertyOwnerName, propertyDescriptor.Name);
Control control = propertyValue as Control;
if (control != null) {
AppendIndentedLine(propertyName + " = self._" + control.Name);
} else {
AppendIndentedLine(propertyName + " = " + PythonPropertyValueAssignment.ToString(propertyValue));
}
} else {
// Content.
if (propertyDescriptor.Name == "Controls") {
Control parentControl = obj as Control;
foreach (Control childControl in parentControl.Controls) {
if (IsSitedComponent(childControl)) {
AppendIndentedLine(GetPropertyName(propertyOwnerName, "Controls") + ".Add(self._" + childControl.Name + ")");
}
}
} else {
MenuStrip menuStrip = obj as MenuStrip;
ComboBox comboBox = obj as ComboBox;
ToolStripMenuItem menuItem = obj as ToolStripMenuItem;
if (menuStrip != null && propertyDescriptor.Name == "Items") {
AppendMenuStripItems(menuStrip);
} else if (comboBox != null && propertyDescriptor.Name == "Items") {
AppendSystemArray(comboBox.Name, "Items.AddRange", typeof(Object).FullName, comboBox.Items);
} else if (menuItem != null && propertyDescriptor.Name == "DropDownItems") {
AppendToolStripMenuItemDropDownItems(menuItem.Name, GetSitedToolStripItems(menuItem.DropDownItems));
}
}
} else {
// DesignerSerializationVisibility.Content
AppendMethodCallWithArrayParameter(propertyOwnerName, obj, propertyDescriptor);
}
}
@ -373,11 +444,6 @@ namespace ICSharpCode.PythonBinding @@ -373,11 +444,6 @@ namespace ICSharpCode.PythonBinding
}
}
static bool IsSitedComponent(IComponent component)
{
return component.Site != null;
}
bool HasSitedChildComponents(Control control)
{
MenuStrip menuStrip = control as MenuStrip;
@ -406,21 +472,13 @@ namespace ICSharpCode.PythonBinding @@ -406,21 +472,13 @@ namespace ICSharpCode.PythonBinding
return false;
}
/// <summary>
/// Adds ToolStripItems that are stored on the MenuStrip.
/// </summary>
void AppendMenuStripItems(MenuStrip menuStrip)
{
List<ToolStripItem> items = GetSitedToolStripItems(menuStrip.Items);
AppendMenuStripItemsAddRange(menuStrip.Name, items);
}
void AppendSystemArray(string componentName, string methodName, string typeName, IList components)
void AppendSystemArray(string componentName, string methodName, string typeName, ICollection components)
{
if (components.Count > 0) {
AppendIndentedLine("self._" + componentName + "." + methodName + "(System.Array[" + typeName + "](");
IncreaseIndent();
for (int i = 0; i < components.Count; ++i) {
int i = 0;
foreach (object component in components) {
if (i == 0) {
AppendIndented("[");
} else {
@ -428,12 +486,12 @@ namespace ICSharpCode.PythonBinding @@ -428,12 +486,12 @@ namespace ICSharpCode.PythonBinding
AppendLine();
AppendIndented(String.Empty);
}
object component = components[i];
if (component is IComponent) {
Append("self._" + ((IComponent)component).Site.Name);
} else {
Append(PythonPropertyValueAssignment.ToString(component));
}
++i;
}
Append("]))");
AppendLine();
@ -441,11 +499,6 @@ namespace ICSharpCode.PythonBinding @@ -441,11 +499,6 @@ namespace ICSharpCode.PythonBinding
}
}
void AppendMenuStripItemsAddRange(string menuStripName, List<ToolStripItem> items)
{
AppendSystemArray(menuStripName, "Items.AddRange", typeof(ToolStripItem).FullName, items);
}
List<ToolStripItem> GetSitedToolStripItems(ToolStripItemCollection items)
{
List<ToolStripItem> sitedItems = new List<ToolStripItem>();
@ -478,11 +531,6 @@ namespace ICSharpCode.PythonBinding @@ -478,11 +531,6 @@ namespace ICSharpCode.PythonBinding
}
}
void AppendToolStripMenuItemDropDownItems(string menuItemName, List<ToolStripItem> items)
{
AppendSystemArray(menuItemName, "DropDownItems.AddRange", typeof(ToolStripItem).FullName, items);
}
void AppendProperties(string propertyOwnerName, object obj)
{
foreach (PropertyDescriptor property in GetSerializableProperties(obj)) {
@ -506,5 +554,50 @@ namespace ICSharpCode.PythonBinding @@ -506,5 +554,50 @@ namespace ICSharpCode.PythonBinding
}
}
}
/// <summary>
/// Returns the sited components in the collection. If an object in the collection is not
/// an IComponent then this is added to the collection.
/// </summary>
ICollection GetSitedComponentsAndNonComponents(ICollection components)
{
List<object> sitedComponents = new List<object>();
foreach (object obj in components) {
IComponent component = obj as IComponent;
if (component == null || IsSitedComponent(component)) {
sitedComponents.Add(obj);
}
}
return sitedComponents.ToArray();
}
/// <summary>
/// Appends an array as a parameter and its associated method call.
/// </summary>
/// <remarks>
/// Looks for the AddRange method first. If that does not exist or is hidden from the designer the
/// Add method is looked for.
/// </remarks>
void AppendMethodCallWithArrayParameter(string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor)
{
IComponent component = propertyOwner as IComponent;
ICollection collectionProperty = propertyDescriptor.GetValue(propertyOwner) as ICollection;
if (collectionProperty != null) {
MethodInfo addRangeMethod = GetAddRangeSerializationMethod(collectionProperty);
if (addRangeMethod != null) {
Type arrayElementType = GetArrayParameterType(addRangeMethod);
AppendSystemArray(component.Site.Name, propertyDescriptor.Name + "." + addRangeMethod.Name, arrayElementType.FullName, GetSitedComponentsAndNonComponents(collectionProperty));
} else {
MethodInfo addMethod = GetAddSerializationMethod(collectionProperty);
ParameterInfo[] parameters = addMethod.GetParameters();
foreach (object item in collectionProperty) {
IComponent collectionComponent = item as IComponent;
if (IsSitedComponent(collectionComponent)) {
AppendIndentedLine(GetPropertyName(propertyOwnerName, propertyDescriptor.Name) + "." + addMethod.Name + "(self._" + collectionComponent.Site.Name + ")");
}
}
}
}
}
}
}

95
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/FindAddRangeMethodTests.cs

@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
// <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.Reflection;
using System.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Tests that the AddRange or Add method that takes an array of items can be determined.
/// </summary>
[TestFixture]
public class FindAddRangeMethodTests
{
[Test]
public void MenuStripItemsAddRangeMethod()
{
using (MenuStrip menuStrip = new MenuStrip()) {
MethodInfo expectedMethodInfo = FindMethod(menuStrip.Items, "AddRange", typeof(ToolStripItem[]));
Assert.IsNotNull(expectedMethodInfo);
Assert.AreSame(expectedMethodInfo, PythonForm.GetAddRangeSerializationMethod(menuStrip.Items));
}
}
[Test]
public void GetArrayParameterType()
{
using (MenuStrip menuStrip = new MenuStrip()) {
MethodInfo methodInfo = FindMethod(menuStrip.Items, "AddRange", typeof(ToolStripItem[]));
Assert.AreEqual(typeof(ToolStripItem), PythonForm.GetArrayParameterType(methodInfo));
}
}
[Test]
public void GetArrayParameterTypeFromMethodWithNoParameters()
{
MethodInfo methodInfo = typeof(String).GetMethod("Clone");
Assert.IsNull(PythonForm.GetArrayParameterType(methodInfo));
}
[Test]
public void GetArrayParameterTypeWithNullMethodInfo()
{
Assert.IsNull(PythonForm.GetArrayParameterType(null));
}
/// <summary>
/// Form.Controls.AddRange() method should not be returned since it is marked with
/// DesignerSerializationVisibility.Hidden.
/// </summary>
[Test]
public void FormControlsAddRangeMethodNotFound()
{
using (Form form = new Form()) {
Assert.IsNull(PythonForm.GetAddRangeSerializationMethod(form.Controls));
}
}
[Test]
public void FormControlsAddMethod()
{
using (Form form = new Form()) {
MethodInfo expectedMethodInfo = FindMethod(form.Controls, "Add", typeof(Control));
Assert.IsNotNull(expectedMethodInfo);
Assert.AreSame(expectedMethodInfo, PythonForm.GetAddSerializationMethod(form.Controls));
}
}
static MethodInfo FindMethod(object obj, string methodName, Type parameterType)
{
foreach (MethodInfo methodInfo in obj.GetType().GetMethods()) {
if (methodInfo.Name == methodName) {
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length == 1) {
ParameterInfo param = parameters[0];
if (param.ParameterType == parameterType) {
return methodInfo;
}
}
}
}
return null;
}
}
}

46
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/GetSerializableContentPropertiesTestFixture.cs

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
// <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.Windows.Forms;
using ICSharpCode.PythonBinding;
using NUnit.Framework;
namespace PythonBinding.Tests.Designer
{
/// <summary>
/// Gets properties that are marked as DesignerSerializationVisibility.Content
/// </summary>
[TestFixture]
public class GetSerializableContentPropertiesTestFixture
{
PropertyDescriptorCollection properties;
[TestFixtureSetUp]
public void SetUpFixture()
{
using (Form form = new Form()) {
// Modify Form.Text so it is identified as needing serialization.
form.Text = "abc";
properties = PythonForm.GetSerializableContentProperties(form);
}
}
[Test]
public void FormControlsPropertyReturned()
{
Assert.IsNotNull(properties.Find("Controls", false), "Property not found: Controls");
}
[Test]
public void FormTextPropertyIsNotReturned()
{
Assert.IsNull(properties.Find("Text", false), "Property should not be found: Text");
}
}
}

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

@ -56,7 +56,7 @@ namespace PythonBinding.Tests.Designer @@ -56,7 +56,7 @@ namespace PythonBinding.Tests.Designer
PythonForm pythonForm = new PythonForm(" ");
generatedCode = pythonForm.GenerateInitializeComponentMethod(form);
propertyDescriptors = pythonForm.GetSerializableProperties(form);
propertyDescriptors = PythonForm.GetSerializableProperties(form);
}
}

77
src/AddIns/BackendBindings/Python/PythonBinding/Test/Designer/IsSitedComponentTests.cs

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
// <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 ICSharpCode.PythonBinding;
using NUnit.Framework;
using PythonBinding.Tests.Utils;
namespace PythonBinding.Tests.Designer
{
[TestFixture]
public class IsSitedComponentTests : ISite
{
[Test]
public void NullComponent()
{
Assert.IsFalse(PythonForm.IsSitedComponent(null));
}
[Test]
public void ComponentNotSited()
{
Assert.IsFalse(PythonForm.IsSitedComponent(new Component()));
}
[Test]
public void SitedComponent()
{
Component component = new Component();
component.Site = this;
Assert.IsTrue(PythonForm.IsSitedComponent(component));
}
[Test]
public void NonComponent()
{
Assert.IsFalse(PythonForm.IsSitedComponent(String.Empty));
}
public IComponent Component {
get {
throw new NotImplementedException();
}
}
public IContainer Container {
get {
throw new NotImplementedException();
}
}
public bool DesignMode {
get {
throw new NotImplementedException();
}
}
public string Name {
get {
throw new NotImplementedException();
}
set {
throw new NotImplementedException();
}
}
public object GetService(Type serviceType)
{
throw new NotImplementedException();
}
}
}

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

@ -152,6 +152,7 @@ @@ -152,6 +152,7 @@
<Compile Include="Designer\DeserializeStringArrayTestFixture.cs" />
<Compile Include="Designer\DeserializeToolStripItemArrayTestFixture.cs" />
<Compile Include="Designer\EnabledSetUsingPropertyDescriptorTestFixture.cs" />
<Compile Include="Designer\FindAddRangeMethodTests.cs" />
<Compile Include="Designer\FindInitializeComponentMethodTestFixture.cs" />
<Compile Include="Designer\GenerateAcceptButtonFormTestFixture.cs" />
<Compile Include="Designer\GenerateAccessibleRoleFormTestFixture.cs" />
@ -175,10 +176,12 @@ @@ -175,10 +176,12 @@
<Compile Include="Designer\GenerateTextBoxFormTestFixture.cs" />
<Compile Include="Designer\GeneratorMergeFindsInitializeComponentsTestFixture.cs" />
<Compile Include="Designer\GetComponentFromDesignerLoaderTestFixture.cs" />
<Compile Include="Designer\GetSerializableContentPropertiesTestFixture.cs" />
<Compile Include="Designer\IgnoreDesignTimePropertiesTestFixture.cs" />
<Compile Include="Designer\InsertNewEventHandlerTestFixture.cs" />
<Compile Include="Designer\InsertSecondEventHandlerTestFixture.cs" />
<Compile Include="Designer\IsFullyQualifiedBaseClassFormDesignableTestFixture.cs" />
<Compile Include="Designer\IsSitedComponentTests.cs" />
<Compile Include="Designer\LoadAcceptButtonFormTestFixture.cs" />
<Compile Include="Designer\LoadAccessibleRoleTestFixture.cs" />
<Compile Include="Designer\LoadAnchorStylesFormTestFixture.cs" />

Loading…
Cancel
Save