You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
873 lines
30 KiB
873 lines
30 KiB
// <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.Globalization; |
|
using System.Drawing; |
|
using System.Reflection; |
|
using System.Resources; |
|
using System.Text; |
|
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; |
|
PythonDesignerComponent parent; |
|
Dictionary<string, object> resources = new Dictionary<string, object>(); |
|
List<PythonDesignerComponent> designerContainerComponents; |
|
|
|
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(null, component) |
|
{ |
|
} |
|
|
|
public PythonDesignerComponent(PythonDesignerComponent parent, IComponent component) |
|
: this(parent, component, new PythonEventBindingService()) |
|
{ |
|
} |
|
|
|
PythonDesignerComponent(PythonDesignerComponent parent, IComponent component, IEventBindingService eventBindingService) |
|
{ |
|
this.parent = parent; |
|
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> |
|
/// Returns true if the component has the DesignTimeVisible attribute set to false. |
|
/// </summary> |
|
public static bool IsHiddenFromDesigner(IComponent component) |
|
{ |
|
foreach (DesignTimeVisibleAttribute attribute in component.GetType().GetCustomAttributes(typeof(DesignTimeVisibleAttribute), true)) { |
|
return !attribute.Visible; |
|
} |
|
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 component type. |
|
/// </summary> |
|
public Type GetComponentType() |
|
{ |
|
return component.GetType(); |
|
} |
|
|
|
/// <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) |
|
{ |
|
if (HasIContainerConstructor()) { |
|
codeBuilder.InsertCreateComponentsContainer(); |
|
AppendCreateInstance(codeBuilder, "self._components"); |
|
} else { |
|
AppendComponentCreation(codeBuilder, component); |
|
} |
|
} |
|
|
|
public void AppendCreateInstance(PythonCodeBuilder codeBuilder, string parameters) |
|
{ |
|
AppendComponentCreation(codeBuilder, component, parameters); |
|
} |
|
|
|
/// <summary> |
|
/// Appends the code to create the child components. |
|
/// </summary> |
|
public void AppendCreateChildComponents(PythonCodeBuilder codeBuilder) |
|
{ |
|
AppendCreateChildComponents(codeBuilder, GetChildComponents()); |
|
} |
|
|
|
/// <summary> |
|
/// Adds all the components that have been added to the design surface container. |
|
/// </summary> |
|
public void AppendCreateContainerComponents(PythonCodeBuilder codeBuilder) |
|
{ |
|
AppendCreateChildComponents(codeBuilder, GetContainerComponents()); |
|
} |
|
|
|
/// <summary> |
|
/// Gets all the components added to the design surface container excluding the |
|
/// root component. |
|
/// </summary> |
|
public PythonDesignerComponent[] GetContainerComponents() |
|
{ |
|
if (designerContainerComponents == null) { |
|
designerContainerComponents = new List<PythonDesignerComponent>(); |
|
ComponentCollection components = Component.Site.Container.Components; |
|
for (int i = 1; i < components.Count; ++i) { |
|
PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(this, components[i]); |
|
if (!designerComponent.IsInheritedReadOnly) { |
|
designerContainerComponents.Add(designerComponent); |
|
} |
|
} |
|
} |
|
return designerContainerComponents.ToArray(); |
|
} |
|
|
|
/// <summary> |
|
/// Appends the component's properties. |
|
/// </summary> |
|
public virtual void AppendComponent(PythonCodeBuilder codeBuilder) |
|
{ |
|
AppendComponentProperties(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> |
|
/// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.Inherited or |
|
/// InheritanceLevel.InheritedReadOnly |
|
/// </summary> |
|
public static bool IsInheritedComponent(object component) |
|
{ |
|
if (component != null) { |
|
InheritanceAttribute attribute = GetInheritanceAttribute(component); |
|
return attribute.InheritanceLevel != InheritanceLevel.NotInherited; |
|
} |
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.Inherited or |
|
/// InheritanceLevel.InheritedReadOnly |
|
/// </summary> |
|
public bool IsInherited { |
|
get { return IsInheritedComponent(component); } |
|
} |
|
|
|
/// <summary> |
|
/// Returns true if the component has an InheritanceAttribute set to InheritanceLevel.InheritedReadOnly |
|
/// </summary> |
|
public bool IsInheritedReadOnly { |
|
get { |
|
InheritanceAttribute attribute = GetInheritanceAttribute(component); |
|
if (attribute != null) { |
|
return attribute.InheritanceLevel == InheritanceLevel.InheritedReadOnly; |
|
} |
|
return false; |
|
} |
|
} |
|
|
|
public static InheritanceAttribute GetInheritanceAttribute(object component) |
|
{ |
|
if (component != null) { |
|
AttributeCollection attributes = TypeDescriptor.GetAttributes(component); |
|
return attributes[typeof(InheritanceAttribute)] as InheritanceAttribute; |
|
} |
|
return null; |
|
} |
|
|
|
/// <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 virtual PythonDesignerComponent[] GetChildComponents() |
|
{ |
|
List<PythonDesignerComponent> components = new List<PythonDesignerComponent>(); |
|
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 (childComponent != null) { |
|
PythonDesignerComponent designerComponent = PythonDesignerComponentFactory.CreateDesignerComponent(this, childComponent); |
|
if (designerComponent.IsSited) { |
|
components.Add(designerComponent); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
return components.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); |
|
} |
|
|
|
/// <summary> |
|
/// Appends the code to create the specified object. |
|
/// </summary> |
|
public void AppendCreateInstance(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(", "); |
|
} |
|
object currentParameter = parameters[i]; |
|
Array array = currentParameter as Array; |
|
if (array != null) { |
|
AppendSystemArray(codeBuilder, array.GetValue(0).GetType().FullName, currentParameter as ICollection); |
|
codeBuilder.DecreaseIndent(); |
|
} else { |
|
codeBuilder.Append(PythonPropertyValueAssignment.ToString(currentParameter)); |
|
} |
|
} |
|
codeBuilder.Append(")"); |
|
codeBuilder.AppendLine(); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Appends the code to create the specified IComponent |
|
/// </summary> |
|
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component) |
|
{ |
|
AppendComponentCreation(codeBuilder, component, String.Empty); |
|
} |
|
|
|
/// <summary> |
|
/// Appends the code to create the specified IComponent |
|
/// </summary> |
|
public void AppendComponentCreation(PythonCodeBuilder codeBuilder, IComponent component, string parameters) |
|
{ |
|
codeBuilder.AppendIndentedLine("self._" + component.Site.Name + " = " + component.GetType().FullName + "(" + parameters + ")"); |
|
} |
|
|
|
/// <summary> |
|
/// Generates the code for the component's properties. |
|
/// </summary> |
|
public void AppendComponentProperties(PythonCodeBuilder codeBuilder) |
|
{ |
|
AppendComponentProperties(codeBuilder, 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 for 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> |
|
public virtual void AppendMethodCallWithArrayParameter(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor) |
|
{ |
|
AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor, false); |
|
} |
|
|
|
/// <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, bool reverse) |
|
{ |
|
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(); |
|
if (reverse) { |
|
collectionProperty = ReverseCollection(collectionProperty); |
|
} |
|
foreach (object item in collectionProperty) { |
|
IComponent collectionComponent = item as IComponent; |
|
if (PythonDesignerComponent.IsSitedComponent(collectionComponent) && !PythonDesignerComponent.IsInheritedComponent(collectionComponent)) { |
|
codeBuilder.AppendIndentedLine(propertyOwnerName + "." + propertyDescriptor.Name + "." + addMethod.Name + "(self._" + collectionComponent.Site.Name + ")"); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Appends a property. |
|
/// </summary> |
|
public void AppendProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj, PropertyDescriptor propertyDescriptor) |
|
{ |
|
object propertyValue = propertyDescriptor.GetValue(obj); |
|
ExtenderProvidedPropertyAttribute extender = GetExtenderAttribute(propertyDescriptor); |
|
if (extender != null) { |
|
AppendExtenderProperty(codeBuilder, propertyOwnerName, extender, propertyDescriptor, propertyValue); |
|
} else if (propertyDescriptor.SerializationVisibility == DesignerSerializationVisibility.Visible) { |
|
string propertyName = propertyOwnerName + "." + propertyDescriptor.Name; |
|
IComponent component = propertyValue as IComponent; |
|
if (component != null) { |
|
string componentRef = GetComponentReference(component); |
|
if (componentRef != null) { |
|
codeBuilder.AppendIndentedLine(propertyName + " = " + componentRef); |
|
} |
|
} else if (IsResourcePropertyValue(propertyValue)) { |
|
AppendResourceProperty(codeBuilder, propertyName, propertyValue); |
|
} else { |
|
codeBuilder.AppendIndentedLine(propertyName + " = " + PythonPropertyValueAssignment.ToString(propertyValue)); |
|
} |
|
} else { |
|
// DesignerSerializationVisibility.Content |
|
AppendPropertyContents(codeBuilder, propertyOwnerName, obj, propertyDescriptor); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Appends an extender provider property. |
|
/// </summary> |
|
public void AppendExtenderProperty(PythonCodeBuilder codeBuilder, string propertyOwnerName, ExtenderProvidedPropertyAttribute extender, PropertyDescriptor propertyDescriptor, object propertyValue) |
|
{ |
|
IComponent component = extender.Provider as IComponent; |
|
codeBuilder.AppendIndented("self._" + component.Site.Name); |
|
codeBuilder.Append(".Set" + propertyDescriptor.Name); |
|
codeBuilder.Append("("); |
|
codeBuilder.Append(propertyOwnerName); |
|
codeBuilder.Append(", "); |
|
codeBuilder.Append(PythonPropertyValueAssignment.ToString(propertyValue)); |
|
codeBuilder.Append(")"); |
|
codeBuilder.AppendLine(); |
|
} |
|
|
|
/// <summary> |
|
/// Appends a property whose value is a resource. |
|
/// </summary> |
|
public void AppendResourceProperty(PythonCodeBuilder codeBuilder, string propertyName, object propertyValue) |
|
{ |
|
string resourceName = propertyName.Replace("self._", String.Empty); |
|
resourceName = resourceName.Replace("self.", "$this."); |
|
codeBuilder.AppendIndented(propertyName); |
|
codeBuilder.Append(" = resources.GetObject(\""); |
|
codeBuilder.Append(resourceName); |
|
codeBuilder.Append("\")"); |
|
codeBuilder.AppendLine(); |
|
|
|
resources.Add(resourceName, propertyValue); |
|
} |
|
|
|
/// <summary> |
|
/// Returns true if the property value will be obtained from a resource. |
|
/// </summary> |
|
public static bool IsResourcePropertyValue(object propertyValue) |
|
{ |
|
return (propertyValue is Image) || (propertyValue is Icon) || (propertyValue is ImageListStreamer); |
|
} |
|
|
|
/// <summary> |
|
/// Appends the properties of the object to the code builder. |
|
/// </summary> |
|
public void AppendProperties(PythonCodeBuilder codeBuilder, string propertyOwnerName, object obj) |
|
{ |
|
foreach (PropertyDescriptor property in GetSerializableProperties(obj)) { |
|
if (!IgnoreProperty(property)) { |
|
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 addComment) |
|
{ |
|
PythonCodeBuilder propertiesBuilder = new PythonCodeBuilder(codeBuilder.Indent); |
|
propertiesBuilder.IndentString = codeBuilder.IndentString; |
|
|
|
AppendProperties(propertiesBuilder); |
|
AppendEventHandlers(propertiesBuilder, eventBindingService); |
|
|
|
// Add comment if we have added some properties or event handlers. |
|
if (addComment && propertiesBuilder.Length > 0) { |
|
AppendComment(codeBuilder); |
|
} |
|
codeBuilder.Append(propertiesBuilder.ToString()); |
|
} |
|
|
|
/// <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"). |
|
/// For an inherited component the actual component name is used without any underscore prefix. |
|
/// </summary> |
|
public virtual string GetPropertyOwnerName() |
|
{ |
|
string componentName = component.Site.Name; |
|
if (IsInherited) { |
|
return "self." + componentName; |
|
} |
|
return "self._" + componentName; |
|
} |
|
|
|
/// <summary> |
|
/// Determines whether the component has a constructor that takes a single IContainer parameter. |
|
/// </summary> |
|
public bool HasIContainerConstructor() |
|
{ |
|
foreach (ConstructorInfo constructor in GetComponentType().GetConstructors()) { |
|
ParameterInfo[] parameters = constructor.GetParameters(); |
|
if (parameters.Length == 1) { |
|
ParameterInfo parameter = parameters[0]; |
|
if (parameter.ParameterType.IsAssignableFrom(typeof(IContainer))) { |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
/// <summary> |
|
/// Writes resources for this component to the resource writer. |
|
/// </summary> |
|
public void GenerateResources(IResourceWriter writer) |
|
{ |
|
foreach (KeyValuePair<string, object> entry in resources) { |
|
writer.AddResource(entry.Key, entry.Value); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Returns true if this component has any properties that are resources. |
|
/// </summary> |
|
public bool HasResources { |
|
get { return resources.Count > 0; } |
|
} |
|
|
|
/// <summary> |
|
/// Gets the parent of this component. |
|
/// </summary> |
|
public PythonDesignerComponent Parent { |
|
get { return parent; } |
|
} |
|
|
|
public static void AppendSystemArray(PythonCodeBuilder codeBuilder, string componentName, string methodName, string typeName, ICollection components) |
|
{ |
|
if (components.Count > 0) { |
|
codeBuilder.AppendIndented("self._" + componentName + "." + methodName + "("); |
|
AppendSystemArray(codeBuilder, typeName, components); |
|
codeBuilder.Append(")"); |
|
codeBuilder.AppendLine(); |
|
} |
|
} |
|
|
|
public static void AppendSystemArray(PythonCodeBuilder codeBuilder, string typeName, ICollection components) |
|
{ |
|
if (components.Count > 0) { |
|
codeBuilder.Append("System.Array[" + typeName + "]("); |
|
codeBuilder.AppendLine(); |
|
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 if (component is IArrayItem) { |
|
codeBuilder.Append(((IArrayItem)component).Name); |
|
} else { |
|
codeBuilder.Append(GetVariableName(component, i + 1)); |
|
} |
|
++i; |
|
} |
|
codeBuilder.Append("])"); |
|
} |
|
codeBuilder.DecreaseIndent(); |
|
} |
|
|
|
protected IComponent Component { |
|
get { return component; } |
|
} |
|
|
|
/// <summary> |
|
/// Return true to prevent the property from being added to the generated code. |
|
/// </summary> |
|
protected virtual bool IgnoreProperty(PropertyDescriptor property) |
|
{ |
|
return false; |
|
} |
|
|
|
static bool HasSitedComponents(PythonDesignerComponent[] components) |
|
{ |
|
foreach (PythonDesignerComponent component in components) { |
|
if (component.IsSited && !component.IsInherited) { |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
void AppendCreateChildComponents(PythonCodeBuilder codeBuilder, PythonDesignerComponent[] childComponents) |
|
{ |
|
foreach (PythonDesignerComponent designerComponent in childComponents) { |
|
if (designerComponent.IsSited && !designerComponent.IsInherited) { |
|
designerComponent.AppendCreateInstance(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(); |
|
} |
|
|
|
void AppendChildComponentsMethodCalls(PythonCodeBuilder codeBuilder, string[] methods) |
|
{ |
|
foreach (PythonDesignerComponent designerComponent in GetChildComponents()) { |
|
if (typeof(Control).IsAssignableFrom(designerComponent.GetComponentType())) { |
|
if (designerComponent.HasSitedChildComponents()) { |
|
designerComponent.AppendMethodCalls(codeBuilder, methods); |
|
} |
|
} |
|
designerComponent.AppendChildComponentsMethodCalls(codeBuilder, methods); |
|
} |
|
} |
|
|
|
bool IsRootComponent(IComponent component) |
|
{ |
|
if (parent == null) { |
|
return this.component == component; |
|
} |
|
return parent.IsRootComponent(component); |
|
} |
|
|
|
string GetComponentReference(IComponent component) |
|
{ |
|
if (IsRootComponent(component)) { |
|
return "self"; |
|
} else { |
|
foreach (PythonDesignerComponent designerComponent in GetContainerComponents()) { |
|
string name = component.Site.Name; |
|
if ((designerComponent.component == component) && (!String.IsNullOrEmpty(name))) { |
|
return "self._" + name; |
|
} |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
static ExtenderProvidedPropertyAttribute GetExtenderAttribute(PropertyDescriptor property) |
|
{ |
|
foreach (Attribute attribute in property.Attributes) { |
|
ExtenderProvidedPropertyAttribute extenderAttribute = attribute as ExtenderProvidedPropertyAttribute; |
|
if (extenderAttribute != null) { |
|
return extenderAttribute; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
static ICollection ReverseCollection(ICollection collection) |
|
{ |
|
List<object> reversedCollection = new List<object>(); |
|
foreach (object item in collection) { |
|
reversedCollection.Add(item); |
|
} |
|
reversedCollection.Reverse(); |
|
return reversedCollection; |
|
} |
|
|
|
/// <summary> |
|
/// Appends a property that needs its contents serialized. |
|
/// </summary> |
|
void AppendPropertyContents(PythonCodeBuilder codeBuilder, string propertyOwnerName, object propertyOwner, PropertyDescriptor propertyDescriptor) |
|
{ |
|
object propertyValue = propertyDescriptor.GetValue(propertyOwner); |
|
if (propertyValue is ICollection) { |
|
AppendMethodCallWithArrayParameter(codeBuilder, propertyOwnerName, propertyOwner, propertyDescriptor); |
|
} else { |
|
propertyOwnerName += "." + propertyDescriptor.Name; |
|
AppendProperties(codeBuilder, propertyOwnerName, propertyValue); |
|
} |
|
} |
|
} |
|
}
|
|
|