Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/3.0@4044 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
20 changed files with 1280 additions and 586 deletions
@ -0,0 +1,81 @@ |
|||||||
|
// <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.Text; |
||||||
|
|
||||||
|
namespace ICSharpCode.PythonBinding |
||||||
|
{ |
||||||
|
public class PythonCodeBuilder |
||||||
|
{ |
||||||
|
StringBuilder codeBuilder = new StringBuilder(); |
||||||
|
string indentString = "\t"; |
||||||
|
int indent; |
||||||
|
|
||||||
|
public PythonCodeBuilder() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the string used for indenting.
|
||||||
|
/// </summary>
|
||||||
|
public string IndentString { |
||||||
|
get { return indentString; } |
||||||
|
set { indentString = value; } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the code.
|
||||||
|
/// </summary>
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
return codeBuilder.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends text at the end of the current code.
|
||||||
|
/// </summary>
|
||||||
|
public void Append(string text) |
||||||
|
{ |
||||||
|
codeBuilder.Append(text); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends carriage return and line feed to the existing text.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendLine() |
||||||
|
{ |
||||||
|
Append("\r\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the text indented.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendIndented(string text) |
||||||
|
{ |
||||||
|
for (int i = 0; i < indent; ++i) { |
||||||
|
codeBuilder.Append(indentString); |
||||||
|
} |
||||||
|
codeBuilder.Append(text); |
||||||
|
} |
||||||
|
|
||||||
|
public void AppendIndentedLine(string text) |
||||||
|
{ |
||||||
|
AppendIndented(text + "\r\n"); |
||||||
|
} |
||||||
|
|
||||||
|
public void IncreaseIndent() |
||||||
|
{ |
||||||
|
indent++; |
||||||
|
} |
||||||
|
|
||||||
|
public void DecreaseIndent() |
||||||
|
{ |
||||||
|
indent--; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,590 @@ |
|||||||
|
// <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; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.ComponentModel; |
||||||
|
using System.ComponentModel.Design; |
||||||
|
using System.Drawing; |
||||||
|
using System.Reflection; |
||||||
|
using System.Windows.Forms; |
||||||
|
|
||||||
|
namespace ICSharpCode.PythonBinding |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents an IComponent in the designer.
|
||||||
|
/// </summary>
|
||||||
|
public class PythonDesignerComponent |
||||||
|
{ |
||||||
|
IComponent component; |
||||||
|
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 }; |
||||||
|
IEventBindingService eventBindingService; |
||||||
|
|
||||||
|
protected static readonly string[] suspendLayoutMethods = new string[] {"SuspendLayout()"}; |
||||||
|
protected static readonly string[] resumeLayoutMethods = new string[] {"ResumeLayout(False)", "PerformLayout()"}; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used so the EventBindingService.GetEventProperty method can be called to get the property descriptor
|
||||||
|
/// for an event.
|
||||||
|
/// </summary>
|
||||||
|
class PythonEventBindingService : EventBindingService |
||||||
|
{ |
||||||
|
public PythonEventBindingService() |
||||||
|
: base(new ServiceContainer()) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
protected override string CreateUniqueMethodName(IComponent component, EventDescriptor e) |
||||||
|
{ |
||||||
|
return String.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
protected override ICollection GetCompatibleMethods(EventDescriptor e) |
||||||
|
{ |
||||||
|
return new ArrayList(); |
||||||
|
} |
||||||
|
|
||||||
|
protected override bool ShowCode() |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
protected override bool ShowCode(int lineNumber) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
protected override bool ShowCode(IComponent component, EventDescriptor e, string methodName) |
||||||
|
{ |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public PythonDesignerComponent(IComponent component) |
||||||
|
: this(component, new PythonEventBindingService()) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
PythonDesignerComponent(IComponent component, IEventBindingService eventBindingService) |
||||||
|
{ |
||||||
|
this.component = component; |
||||||
|
this.eventBindingService = eventBindingService; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of properties that should be serialized for the specified form.
|
||||||
|
/// </summary>
|
||||||
|
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 (requiredVisibility.Contains(property.SerializationVisibility)) { |
||||||
|
if (property.ShouldSerializeValue(obj)) { |
||||||
|
properties.Add(property); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return new PropertyDescriptorCollection(properties.ToArray()); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks whether the method is marked with the DesignerSerializationVisibility.Hidden attribute.
|
||||||
|
/// </summary>
|
||||||
|
public static bool IsHiddenFromDesignerSerializer(MethodInfo methodInfo) |
||||||
|
{ |
||||||
|
foreach (DesignerSerializationVisibilityAttribute attribute in methodInfo.GetCustomAttributes(typeof(DesignerSerializationVisibilityAttribute), true)) { |
||||||
|
if (attribute.Visibility == DesignerSerializationVisibility.Hidden) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends code that creates an instance of the component.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AppendCreateInstance(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendComponentCreation(codeBuilder, component); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the code to create the child components.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendCreateChildComponents(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendCreateChildComponents(codeBuilder, GetChildComponents()); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the component's properties.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AppendComponent(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendComment(codeBuilder); |
||||||
|
AppendComponentProperties(codeBuilder); |
||||||
|
AppendChildComponentProperties(codeBuilder); |
||||||
|
} |
||||||
|
|
||||||
|
/// <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>
|
||||||
|
/// Determines whether this designer component is sited.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSited { |
||||||
|
get { return IsSitedComponent(component); } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the child objects that need to be stored in the generated designer code on the specified object.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// For a MenuStrip the child components include the MenuStrip.Items.
|
||||||
|
/// For a Control the child components include the Control.Controls.
|
||||||
|
/// </remarks>
|
||||||
|
public object[] GetChildComponents() |
||||||
|
{ |
||||||
|
List<object> childComponents = new List<object>(); |
||||||
|
foreach (PropertyDescriptor property in GetSerializableContentProperties(component)) { |
||||||
|
ICollection collection = property.GetValue(component) as ICollection; |
||||||
|
if (collection != null) { |
||||||
|
foreach (object childObject in collection) { |
||||||
|
IComponent childComponent = childObject as IComponent; |
||||||
|
if (IsSitedComponent(childComponent)) { |
||||||
|
childComponents.Add(childObject); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return childComponents.ToArray(); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends SuspendLayout method call if the component has any sited child components.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AppendSuspendLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
if (HasSitedChildComponents()) { |
||||||
|
AppendMethodCalls(codeBuilder, suspendLayoutMethods); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the ResumeLayout and PerformLayout method calls if the component has any sited
|
||||||
|
/// child components.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void AppendResumeLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
if (HasSitedChildComponents()) { |
||||||
|
AppendMethodCalls(codeBuilder, resumeLayoutMethods); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void AppendChildComponentsSuspendLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendChildComponentsMethodCalls(codeBuilder, suspendLayoutMethods); |
||||||
|
} |
||||||
|
|
||||||
|
public void AppendChildComponentsResumeLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendChildComponentsMethodCalls(codeBuilder, resumeLayoutMethods); |
||||||
|
} |
||||||
|
|
||||||
|
void AppendChildComponentsMethodCalls(PythonCodeBuilder codeBuilder, string[] methods) |
||||||
|
{ |
||||||
|
foreach (IComponent component in GetChildComponents()) { |
||||||
|
PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(component); |
||||||
|
if (designerComponent.component is Control) { |
||||||
|
if (designerComponent.HasSitedChildComponents()) { |
||||||
|
designerComponent.AppendMethodCalls(codeBuilder, methods); |
||||||
|
} |
||||||
|
} |
||||||
|
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) |
||||||
|
{ |
||||||
|
if (obj is String) { |
||||||
|
// Do nothing.
|
||||||
|
} else { |
||||||
|
codeBuilder.AppendIndented(GetVariableName(obj, count) + " = " + obj.GetType().FullName); |
||||||
|
|
||||||
|
codeBuilder.Append("("); |
||||||
|
for (int i = 0; i < parameters.Length; ++i) { |
||||||
|
if (i > 0) { |
||||||
|
codeBuilder.Append(", "); |
||||||
|
} |
||||||
|
codeBuilder.Append(PythonPropertyValueAssignment.ToString(parameters[i])); |
||||||
|
} |
||||||
|
codeBuilder.Append(")"); |
||||||
|
codeBuilder.AppendLine(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the code to create the specified IComponent
|
||||||
|
/// </summary>
|
||||||
|
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component) |
||||||
|
{ |
||||||
|
codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "()"); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates the code for the component's properties.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendComponentProperties(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendComponentProperties(codeBuilder, true, false, false); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the properties of any component that is contained in a collection property that is
|
||||||
|
/// marked as DesignerSerializationVisibility.Content.
|
||||||
|
/// </summary>
|
||||||
|
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(childComponent); |
||||||
|
if (designerComponent.IsSited) { |
||||||
|
designerComponent.AppendComponentProperties(codeBuilder, true, true, true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
/// <summary>
|
||||||
|
/// Generates python code for an object's properties when the object is not an IComponent.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendObjectProperties(PythonCodeBuilder codeBuilder, object obj, int count) |
||||||
|
{ |
||||||
|
AppendProperties(codeBuilder, PythonDesignerComponent.GetVariableName(obj, count), obj); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the comment lines containing the component name before the component has its properties set.
|
||||||
|
/// </summary>
|
||||||
|
///
|
||||||
|
public void AppendComment(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
codeBuilder.AppendIndentedLine("# "); |
||||||
|
codeBuilder.AppendIndentedLine("# " + component.Site.Name); |
||||||
|
codeBuilder.AppendIndentedLine("# "); |
||||||
|
} |
||||||
|
|
||||||
|
public bool HasSitedChildComponents() |
||||||
|
{ |
||||||
|
return HasSitedComponents(GetChildComponents()); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the method calls if this component.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendMethodCalls(PythonCodeBuilder codeBuilder, string[] methods) |
||||||
|
{ |
||||||
|
foreach (string method in methods) { |
||||||
|
codeBuilder.AppendIndentedLine(GetPropertyOwnerName() + "." + method); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the variable name for the specified type.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The variable name is simply the type name with the first character in lower case followed by the
|
||||||
|
/// count.
|
||||||
|
/// </remarks>
|
||||||
|
public static string GetVariableName(object obj, int count) |
||||||
|
{ |
||||||
|
string typeName = obj.GetType().Name; |
||||||
|
return typeName[0].ToString().ToLowerInvariant() + typeName.Substring(1) + count; |
||||||
|
} |
||||||
|
|
||||||
|
/// <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>
|
||||||
|
public static void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, 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(codeBuilder, 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 (PythonDesignerComponent.IsSitedComponent(collectionComponent)) { |
||||||
|
codeBuilder.AppendIndentedLine(propertyOwnerName + "." + propertyDescriptor.Name + "." + addMethod.Name + "(self._" + collectionComponent.Site.Name + ")"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends a property.
|
||||||
|
/// </summary>
|
||||||
|
public static void AppendProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj, PropertyDescriptor propertyDescriptor) |
||||||
|
{ |
||||||
|
object propertyValue = propertyDescriptor.GetValue(obj); |
||||||
|
if (propertyValue == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (propertyDescriptor.SerializationVisibility == DesignerSerializationVisibility.Visible) { |
||||||
|
string propertyName = propertyOwnerName + "." + propertyDescriptor.Name; |
||||||
|
Control control = propertyValue as Control; |
||||||
|
if (control != null) { |
||||||
|
codeBuilder.AppendIndentedLine(propertyName + " = self._" + control.Name); |
||||||
|
} else { |
||||||
|
codeBuilder.AppendIndentedLine(propertyName + " = " + PythonPropertyValueAssignment.ToString(propertyValue)); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// DesignerSerializationVisibility.Content
|
||||||
|
AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, obj, propertyDescriptor); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the properties of the object to the code builder.
|
||||||
|
/// </summary>
|
||||||
|
public static void AppendProperties(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj) |
||||||
|
{ |
||||||
|
foreach (PropertyDescriptor property in GetSerializableProperties(obj)) { |
||||||
|
AppendProperty(codeBuilder, propertyOwnerName, obj, property); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the properties of the component.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendProperties(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendProperties(codeBuilder, GetPropertyOwnerName(), component); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates python code for the component.
|
||||||
|
/// </summary>
|
||||||
|
public void AppendComponentProperties(PythonCodeBuilder codeBuilder, bool addComponentNameToProperty, bool addChildComponentProperties, bool addComment) |
||||||
|
{ |
||||||
|
if (addComment) { |
||||||
|
AppendComment(codeBuilder); |
||||||
|
} |
||||||
|
|
||||||
|
AppendProperties(codeBuilder); |
||||||
|
AppendEventHandlers(codeBuilder, eventBindingService); |
||||||
|
|
||||||
|
if (addChildComponentProperties) { |
||||||
|
AppendChildComponentProperties(codeBuilder); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates code that wires an event to an event handler.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Note that the EventDescriptorCollection.Sort method does not work if the
|
||||||
|
/// enumerator is called first. Sorting will only occur if an item is retrieved after calling
|
||||||
|
/// Sort or CopyTo is called. The PropertyDescriptorCollection class does not behave
|
||||||
|
/// in the same way.</remarks>
|
||||||
|
public void AppendEventHandlers(PythonCodeBuilder codeBuilder, IEventBindingService eventBindingService) |
||||||
|
{ |
||||||
|
EventDescriptorCollection events = TypeDescriptor.GetEvents(component, notDesignOnlyFilter).Sort(); |
||||||
|
if (events.Count > 0) { |
||||||
|
EventDescriptor dummyEventDescriptor = events[0]; |
||||||
|
} |
||||||
|
foreach (EventDescriptor eventDescriptor in events) { |
||||||
|
AppendEventHandler(codeBuilder, component, eventDescriptor, eventBindingService); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AppendEventHandler(PythonCodeBuilder codeBuilder, object component, EventDescriptor eventDescriptor, IEventBindingService eventBindingService) |
||||||
|
{ |
||||||
|
PropertyDescriptor propertyDescriptor = eventBindingService.GetEventProperty(eventDescriptor); |
||||||
|
if (propertyDescriptor.ShouldSerializeValue(component)) { |
||||||
|
string methodName = (string)propertyDescriptor.GetValue(component); |
||||||
|
codeBuilder.AppendIndentedLine(GetPropertyOwnerName() + "." + eventDescriptor.Name + " += self." + methodName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the owner of any properties generated (e.g. "self._textBox1").
|
||||||
|
public virtual string GetPropertyOwnerName() |
||||||
|
{ |
||||||
|
return "self._" + component.Site.Name; |
||||||
|
} |
||||||
|
|
||||||
|
protected IComponent Component { |
||||||
|
get { return component; } |
||||||
|
} |
||||||
|
|
||||||
|
static bool HasSitedComponents(ICollection items) |
||||||
|
{ |
||||||
|
foreach (object item in items) { |
||||||
|
if (IsSitedComponent(item)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void AppendCreateChildComponents(PythonCodeBuilder codeBuilder, ICollection childComponents) |
||||||
|
{ |
||||||
|
foreach (object obj in childComponents) { |
||||||
|
IComponent component = obj as IComponent; |
||||||
|
PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(component); |
||||||
|
if (designerComponent.IsSited) { |
||||||
|
designerComponent.AppendCreateInstance(codeBuilder); |
||||||
|
designerComponent.AppendCreateChildComponents(codeBuilder); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <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>
|
||||||
|
static 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(); |
||||||
|
} |
||||||
|
|
||||||
|
static void AppendSystemArray(PythonCodeBuilder codeBuilder, string componentName, string methodName, string typeName, ICollection components) |
||||||
|
{ |
||||||
|
if (components.Count > 0) { |
||||||
|
codeBuilder.AppendIndentedLine("self._" + componentName + "." + methodName + "(System.Array[" + typeName + "]("); |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
int i = 0; |
||||||
|
foreach (object component in components) { |
||||||
|
if (i == 0) { |
||||||
|
codeBuilder.AppendIndented("["); |
||||||
|
} else { |
||||||
|
codeBuilder.Append(","); |
||||||
|
codeBuilder.AppendLine(); |
||||||
|
codeBuilder.AppendIndented(String.Empty); |
||||||
|
} |
||||||
|
if (component is IComponent) { |
||||||
|
codeBuilder.Append("self._" + ((IComponent)component).Site.Name); |
||||||
|
} else if (component is String) { |
||||||
|
codeBuilder.Append(PythonPropertyValueAssignment.ToString(component)); |
||||||
|
} else { |
||||||
|
codeBuilder.Append(GetVariableName(component, i + 1)); |
||||||
|
} |
||||||
|
++i; |
||||||
|
} |
||||||
|
codeBuilder.Append("]))"); |
||||||
|
codeBuilder.AppendLine(); |
||||||
|
codeBuilder.DecreaseIndent(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
// <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; |
||||||
|
|
||||||
|
namespace ICSharpCode.PythonBinding |
||||||
|
{ |
||||||
|
public class PythonDesignerComponentFactory |
||||||
|
{ |
||||||
|
PythonDesignerComponentFactory() |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a PythonDesignerComponent class for the specified component.
|
||||||
|
/// </summary>
|
||||||
|
public static PythonDesignerComponent CreateDesignerComponent(IComponent component) |
||||||
|
{ |
||||||
|
if (component is ListView) { |
||||||
|
return new PythonListViewComponent(component); |
||||||
|
} |
||||||
|
return new PythonDesignerComponent(component); |
||||||
|
} |
||||||
|
|
||||||
|
public static PythonDesignerComponent CreateDesignerRootComponent(IComponent component) |
||||||
|
{ |
||||||
|
return new PythonDesignerRootComponent(component); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
// <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; |
||||||
|
|
||||||
|
namespace ICSharpCode.PythonBinding |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents a root component in the designer.
|
||||||
|
/// </summary>
|
||||||
|
public class PythonDesignerRootComponent : PythonDesignerComponent |
||||||
|
{ |
||||||
|
public PythonDesignerRootComponent(IComponent component) |
||||||
|
: base(component) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
public override string GetPropertyOwnerName() |
||||||
|
{ |
||||||
|
return "self"; |
||||||
|
} |
||||||
|
|
||||||
|
public override void AppendSuspendLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendMethodCalls(codeBuilder, suspendLayoutMethods); |
||||||
|
} |
||||||
|
|
||||||
|
public override void AppendResumeLayout(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendMethodCalls(codeBuilder, resumeLayoutMethods); |
||||||
|
} |
||||||
|
|
||||||
|
public override void AppendComponent(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
// Add the child component's first.
|
||||||
|
foreach (IComponent component in GetChildComponents()) { |
||||||
|
PythonDesignerComponentFactory.CreateDesignerComponent(component).AppendComponent(codeBuilder); |
||||||
|
} |
||||||
|
|
||||||
|
// Add root component
|
||||||
|
AppendComponentProperties(codeBuilder, false, false, true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
// <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; |
||||||
|
|
||||||
|
namespace ICSharpCode.PythonBinding |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Used to generate code for a ListView component currently being designed.
|
||||||
|
/// </summary>
|
||||||
|
public class PythonListViewComponent : PythonDesignerComponent |
||||||
|
{ |
||||||
|
public PythonListViewComponent(IComponent component) : base(component) |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends code that creates an instance of the list view.
|
||||||
|
/// </summary>
|
||||||
|
public override void AppendCreateInstance(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
// Append list view item creation first.
|
||||||
|
int count = 1; |
||||||
|
foreach (ListViewItem item in GetListViewItems(Component)) { |
||||||
|
AppendObjectCreation(codeBuilder, item, count, GetConstructorParameters(item)); |
||||||
|
++count; |
||||||
|
} |
||||||
|
|
||||||
|
// Append list view creation.
|
||||||
|
base.AppendCreateInstance(codeBuilder); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Appends the component's properties.
|
||||||
|
/// </summary>
|
||||||
|
public override void AppendComponent(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
AppendComment(codeBuilder); |
||||||
|
AppendListViewItemProperties(codeBuilder); |
||||||
|
AppendComponentProperties(codeBuilder); |
||||||
|
AppendChildComponentProperties(codeBuilder); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the parameters to the ListViewItem constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The constructors that are used:
|
||||||
|
/// ListViewItem()
|
||||||
|
/// ListViewItem(String text)
|
||||||
|
/// ListViewItem(string[] subItems)
|
||||||
|
/// </remarks>
|
||||||
|
object[] GetConstructorParameters(ListViewItem item) |
||||||
|
{ |
||||||
|
if (String.IsNullOrEmpty(item.Text)) { |
||||||
|
return new object[0]; |
||||||
|
} |
||||||
|
return new object[] {item.Text}; |
||||||
|
} |
||||||
|
|
||||||
|
static ListView.ListViewItemCollection GetListViewItems(IComponent component) |
||||||
|
{ |
||||||
|
ListView listView = (ListView)component; |
||||||
|
return listView.Items; |
||||||
|
} |
||||||
|
|
||||||
|
void AppendListViewItemProperties(PythonCodeBuilder codeBuilder) |
||||||
|
{ |
||||||
|
int count = 1; |
||||||
|
foreach (ListViewItem item in GetListViewItems(Component)) { |
||||||
|
AppendObjectProperties(codeBuilder, item, count); |
||||||
|
++count; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
// <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.Windows.Forms; |
||||||
|
using ICSharpCode.PythonBinding; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace PythonBinding.Tests.Designer |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Tests the PythonControl's CreateDesignerComponent method.
|
||||||
|
/// </summary>
|
||||||
|
[TestFixture] |
||||||
|
public class CreateDesignerComponentTests |
||||||
|
{ |
||||||
|
[Test] |
||||||
|
public void ListViewComponent() |
||||||
|
{ |
||||||
|
using (ListView listView = new ListView()) { |
||||||
|
Assert.IsInstanceOfType(typeof(PythonListViewComponent), PythonDesignerComponentFactory.CreateDesignerComponent(listView)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void TextBoxComponent() |
||||||
|
{ |
||||||
|
using (TextBox textBox = new TextBox()) { |
||||||
|
Assert.IsInstanceOfType(typeof(PythonDesignerComponent), PythonDesignerComponentFactory.CreateDesignerComponent(textBox)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void CreateRootDesigner() |
||||||
|
{ |
||||||
|
using (TextBox textBox = new TextBox()) { |
||||||
|
Assert.IsInstanceOfType(typeof(PythonDesignerRootComponent), PythonDesignerComponentFactory.CreateDesignerRootComponent(textBox)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
// <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 ICSharpCode.PythonBinding; |
||||||
|
using NUnit.Framework; |
||||||
|
|
||||||
|
namespace PythonBinding.Tests.Designer |
||||||
|
{ |
||||||
|
[TestFixture] |
||||||
|
public class PythonCodeBuilderTests |
||||||
|
{ |
||||||
|
PythonCodeBuilder codeBuilder; |
||||||
|
|
||||||
|
[SetUp] |
||||||
|
public void Init() |
||||||
|
{ |
||||||
|
codeBuilder = new PythonCodeBuilder(); |
||||||
|
codeBuilder.IndentString = "\t"; |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void AppendNewLine() |
||||||
|
{ |
||||||
|
codeBuilder.AppendLine(); |
||||||
|
Assert.AreEqual("\r\n", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void AppendText() |
||||||
|
{ |
||||||
|
codeBuilder.Append("abc"); |
||||||
|
Assert.AreEqual("abc", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void AppendIndentedText() |
||||||
|
{ |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
codeBuilder.AppendIndented("abc"); |
||||||
|
Assert.AreEqual("\tabc", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void IncreaseIndentTwice() |
||||||
|
{ |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
codeBuilder.AppendIndented("abc"); |
||||||
|
Assert.AreEqual("\t\tabc", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void DecreaseIndent() |
||||||
|
{ |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
codeBuilder.AppendIndented("abc"); |
||||||
|
codeBuilder.AppendLine(); |
||||||
|
codeBuilder.DecreaseIndent(); |
||||||
|
codeBuilder.AppendIndented("abc"); |
||||||
|
Assert.AreEqual("\tabc\r\nabc", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void AppendIndentedLine() |
||||||
|
{ |
||||||
|
codeBuilder.IncreaseIndent(); |
||||||
|
codeBuilder.AppendIndentedLine("abc"); |
||||||
|
Assert.AreEqual("\tabc\r\n", codeBuilder.ToString()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue