// // System.ComponentModel.TypeDescriptor.cs // // Authors: // Gonzalo Paniagua Javier (gonzalo@ximian.com) // Andreas Nahr (ClassDevelopment@A-SoftTech.com) // // (C) 2002 Ximian, Inc (http://www.ximian.com) // (C) 2003 Andreas Nahr // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.Collections; using System.Reflection; using System.Globalization; using System.ComponentModel.Design; using System.Security.Permissions; namespace System.ComponentModel { public sealed class TypeDescriptor { private static readonly object creatingDefaultConverters = new object (); private static Hashtable defaultConverters; private static IComNativeDescriptorHandler descriptorHandler; private static Hashtable componentTable = new Hashtable (); private static Hashtable typeTable = new Hashtable (); private TypeDescriptor () { } [MonoTODO] public static void AddEditorTable (Type editorBaseType, Hashtable table) { throw new NotImplementedException (); } public static IDesigner CreateDesigner(IComponent component, Type designerBaseType) { string tn = designerBaseType.AssemblyQualifiedName; AttributeCollection col = GetAttributes (component); foreach (Attribute at in col) { DesignerAttribute dat = at as DesignerAttribute; if (dat != null && tn == dat.DesignerBaseTypeName) { return (IDesigner) Activator.CreateInstance (GetTypeFromName (component, dat.DesignerTypeName)); } } return null; } [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)] public static EventDescriptor CreateEvent (Type componentType, string name, Type type, Attribute [] attributes) { return new ReflectionEventDescriptor (componentType, name, type, attributes); } [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)] public static EventDescriptor CreateEvent (Type componentType, EventDescriptor oldEventDescriptor, Attribute [] attributes) { return new ReflectionEventDescriptor (componentType, oldEventDescriptor, attributes); } [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)] public static PropertyDescriptor CreateProperty (Type componentType, string name, Type type, Attribute [] attributes) { return new ReflectionPropertyDescriptor (componentType, name, type, attributes); } [ReflectionPermission (SecurityAction.LinkDemand, TypeInformation = true, MemberAccess = true)] public static PropertyDescriptor CreateProperty (Type componentType, PropertyDescriptor oldPropertyDescriptor, Attribute [] attributes) { return new ReflectionPropertyDescriptor (componentType, oldPropertyDescriptor, attributes); } public static AttributeCollection GetAttributes (Type componentType) { if (componentType == null) return AttributeCollection.Empty; return GetTypeInfo (componentType).GetAttributes (); } public static AttributeCollection GetAttributes (object component) { return GetAttributes (component, false); } public static AttributeCollection GetAttributes (object component, bool noCustomTypeDesc) { if (component == null) return AttributeCollection.Empty; if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) { return ((ICustomTypeDescriptor) component).GetAttributes (); } else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetAttributes (); else return GetTypeInfo (component.GetType()).GetAttributes (); } } public static string GetClassName (object component) { return GetClassName (component, false); } public static string GetClassName (object component, bool noCustomTypeDesc) { if (component == null) throw new ArgumentNullException ("component", "component cannot be null"); if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) { String res = ((ICustomTypeDescriptor) component).GetClassName (); if (res == null) res = ((ICustomTypeDescriptor) component).GetComponentName (); if (res == null) res = component.GetType ().FullName; return res; } else { return component.GetType ().FullName; } } public static string GetComponentName (object component) { return GetComponentName (component, false); } public static string GetComponentName (object component, bool noCustomTypeDesc) { if (component == null) throw new ArgumentNullException ("component", "component cannot be null"); if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) { return ((ICustomTypeDescriptor) component).GetComponentName (); } else { IComponent c = component as IComponent; if (c != null && c.Site != null) return c.Site.Name; #if NET_2_0 return null; #else return component.GetType().Name; #endif } } public static TypeConverter GetConverter (object component) { return GetConverter (component, false); } public static TypeConverter GetConverter (object component, bool noCustomTypeDesc) { if (component == null) throw new ArgumentNullException ("component", "component cannot be null"); if (noCustomTypeDesc == false && component is ICustomTypeDescriptor) { return ((ICustomTypeDescriptor) component).GetConverter (); } else { Type t = null; AttributeCollection atts = GetAttributes (component, false); TypeConverterAttribute tca = (TypeConverterAttribute) atts[typeof(TypeConverterAttribute)]; if (tca != null && tca.ConverterTypeName.Length > 0) { t = GetTypeFromName (component as IComponent, tca.ConverterTypeName); } if (t != null) { ConstructorInfo ci = t.GetConstructor (new Type[] { typeof(Type) }); if (ci != null) return (TypeConverter) ci.Invoke (new object[] { component.GetType () }); else return (TypeConverter) Activator.CreateInstance (t); } else return GetConverter (component.GetType ()); } } private static Hashtable DefaultConverters { get { lock (creatingDefaultConverters) { if (defaultConverters != null) return defaultConverters; defaultConverters = new Hashtable (); defaultConverters.Add (typeof (bool), typeof (BooleanConverter)); defaultConverters.Add (typeof (byte), typeof (ByteConverter)); defaultConverters.Add (typeof (sbyte), typeof (SByteConverter)); defaultConverters.Add (typeof (string), typeof (StringConverter)); defaultConverters.Add (typeof (char), typeof (CharConverter)); defaultConverters.Add (typeof (short), typeof (Int16Converter)); defaultConverters.Add (typeof (int), typeof (Int32Converter)); defaultConverters.Add (typeof (long), typeof (Int64Converter)); defaultConverters.Add (typeof (ushort), typeof (UInt16Converter)); defaultConverters.Add (typeof (uint), typeof (UInt32Converter)); defaultConverters.Add (typeof (ulong), typeof (UInt64Converter)); defaultConverters.Add (typeof (float), typeof (SingleConverter)); defaultConverters.Add (typeof (double), typeof (DoubleConverter)); defaultConverters.Add (typeof (decimal), typeof (DecimalConverter)); defaultConverters.Add (typeof (object), typeof (TypeConverter)); defaultConverters.Add (typeof (void), typeof (TypeConverter)); defaultConverters.Add (typeof (Array), typeof (ArrayConverter)); defaultConverters.Add (typeof (CultureInfo), typeof (CultureInfoConverter)); defaultConverters.Add (typeof (DateTime), typeof (DateTimeConverter)); defaultConverters.Add (typeof (Guid), typeof (GuidConverter)); defaultConverters.Add (typeof (TimeSpan), typeof (TimeSpanConverter)); defaultConverters.Add (typeof (ICollection), typeof (CollectionConverter)); } return defaultConverters; } } public static TypeConverter GetConverter (Type type) { TypeConverterAttribute tca = null; Type t = null; object [] atts = type.GetCustomAttributes (typeof(TypeConverterAttribute), true); if (atts.Length > 0) tca = (TypeConverterAttribute)atts[0]; if (tca != null) { t = GetTypeFromName (null, tca.ConverterTypeName); } if (t == null) { if (type.IsEnum) { // EnumConverter needs to know the enum type return new EnumConverter(type); } else if (type.IsArray) { return new ArrayConverter (); } } if (t == null) t = FindConverterType (type); if (t != null) { Exception exc = null; try { return (TypeConverter) Activator.CreateInstance (t); } catch (MissingMethodException e) { exc = e; } try { return (TypeConverter) Activator.CreateInstance (t, new object [] {type}); } catch (MissingMethodException e) { throw exc; } } return new ReferenceConverter (type); // Default? } private static Type FindConverterType (Type type) { Type t = null; // Is there a default converter t = (Type) DefaultConverters [type]; if (t != null) return t; // Find default converter with a type this type is assignable to foreach (Type defType in DefaultConverters.Keys) { if (defType.IsInterface && defType.IsAssignableFrom (type)) { return (Type) DefaultConverters [defType]; } } // Nothing found, try the same with our base type if (type.BaseType != null) return FindConverterType (type.BaseType); else return null; } public static EventDescriptor GetDefaultEvent (Type componentType) { return GetTypeInfo (componentType).GetDefaultEvent (); } public static EventDescriptor GetDefaultEvent (object component) { return GetDefaultEvent (component, false); } public static EventDescriptor GetDefaultEvent (object component, bool noCustomTypeDesc) { if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetDefaultEvent (); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetDefaultEvent (); else return GetTypeInfo (component.GetType()).GetDefaultEvent (); } } public static PropertyDescriptor GetDefaultProperty (Type componentType) { return GetTypeInfo (componentType).GetDefaultProperty (); } public static PropertyDescriptor GetDefaultProperty (object component) { return GetDefaultProperty (component, false); } public static PropertyDescriptor GetDefaultProperty (object component, bool noCustomTypeDesc) { if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetDefaultProperty (); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetDefaultProperty (); else return GetTypeInfo (component.GetType()).GetDefaultProperty (); } } public static object GetEditor (Type componentType, Type editorBaseType) { Type t = null; object [] atts = componentType.GetCustomAttributes (typeof(EditorAttribute), true); if (atts == null || atts.Length == 0) return null; foreach (EditorAttribute ea in atts) { t = GetTypeFromName (null, ea.EditorTypeName); if (t.IsSubclassOf(editorBaseType)) break; } if (t != null) { Exception exc = null; try { return Activator.CreateInstance (t); } catch (MissingMethodException e) { exc = e; } try { return Activator.CreateInstance (t, new object [] {componentType}); } catch (MissingMethodException e) { throw exc; } } return null; // No editor specified } public static object GetEditor (object component, Type editorBaseType) { return GetEditor (component, editorBaseType, false); } public static object GetEditor (object component, Type editorBaseType, bool noCustomTypeDesc) { if (component == null) throw new ArgumentNullException ("component"); if (editorBaseType == null) throw new ArgumentNullException ("editorBaseType"); if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetEditor (editorBaseType); object [] atts = component.GetType ().GetCustomAttributes (typeof (EditorAttribute), true); if (atts.Length == 0) return null; string target = editorBaseType.AssemblyQualifiedName; foreach (EditorAttribute ea in atts){ if (ea.EditorBaseTypeName == target){ Type t = Type.GetType (ea.EditorTypeName, true); return Activator.CreateInstance (t); } } return null; } public static EventDescriptorCollection GetEvents (object component) { return GetEvents (component, false); } public static EventDescriptorCollection GetEvents (Type componentType) { return GetEvents (componentType, null); } public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes) { return GetEvents (component, attributes, false); } public static EventDescriptorCollection GetEvents (object component, bool noCustomTypeDesc) { if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetEvents (); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetEvents (); else return GetTypeInfo (component.GetType()).GetEvents (); } } public static EventDescriptorCollection GetEvents (Type componentType, Attribute [] attributes) { return GetTypeInfo (componentType).GetEvents (attributes); } public static EventDescriptorCollection GetEvents (object component, Attribute [] attributes, bool noCustomTypeDesc) { if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetEvents (attributes); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetEvents (attributes); else return GetTypeInfo (component.GetType()).GetEvents (attributes); } } public static PropertyDescriptorCollection GetProperties (object component) { return GetProperties (component, false); } public static PropertyDescriptorCollection GetProperties (Type componentType) { return GetProperties (componentType, null); } public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes) { return GetProperties (component, attributes, false); } public static PropertyDescriptorCollection GetProperties (object component, Attribute [] attributes, bool noCustomTypeDesc) { if (component == null) return PropertyDescriptorCollection.Empty; if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetProperties (attributes); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetProperties (attributes); else return GetTypeInfo (component.GetType()).GetProperties (attributes); } } public static PropertyDescriptorCollection GetProperties (object component, bool noCustomTypeDesc) { if (component == null) return PropertyDescriptorCollection.Empty; if (!noCustomTypeDesc && (component is ICustomTypeDescriptor)) return ((ICustomTypeDescriptor) component).GetProperties (); else { IComponent com = component as IComponent; if (com != null && com.Site != null) return GetComponentInfo (com).GetProperties (); else return GetTypeInfo (component.GetType()).GetProperties (); } } public static PropertyDescriptorCollection GetProperties (Type componentType, Attribute [] attributes) { return GetTypeInfo (componentType).GetProperties (attributes); } public static void SortDescriptorArray (IList infos) { string[] names = new string [infos.Count]; object[] values = new object [infos.Count]; for (int n=0; n 0) _defaultEvent = events [0]; #endif } _gotDefaultEvent = true; return _defaultEvent; } public PropertyDescriptor GetDefaultProperty () { if (_gotDefaultProperty) return _defaultProperty; DefaultPropertyAttribute attr = (DefaultPropertyAttribute) GetAttributes()[typeof(DefaultPropertyAttribute)]; if (attr == null || attr.Name == null) _defaultProperty = null; else { PropertyDescriptorCollection properties = GetProperties (); _defaultProperty = properties[attr.Name]; } _gotDefaultProperty = true; return _defaultProperty; } protected AttributeCollection GetAttributes (IComponent comp) { if (_attributes != null) return _attributes; bool cache = true; object[] ats = _infoType.GetCustomAttributes (true); Hashtable t = new Hashtable (); // Filter the custom attributes, so that only the top // level of the same type are left. // for (int i = ats.Length -1; i >= 0; i--) { t [((Attribute) ats[i]).TypeId] = ats[i]; } if (comp != null && comp.Site != null) { ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) comp.Site.GetService (typeof(ITypeDescriptorFilterService)); if (filter != null) cache = filter.FilterAttributes (comp, t); } ArrayList atts = new ArrayList (); atts.AddRange (t.Values); AttributeCollection attCol = new AttributeCollection (atts); if (cache) _attributes = attCol; return attCol; } } internal class ComponentInfo : Info { IComponent _component; EventDescriptorCollection _events; PropertyDescriptorCollection _properties; public ComponentInfo (IComponent component): base (component.GetType()) { _component = component; } public override AttributeCollection GetAttributes () { return base.GetAttributes (_component); } public override EventDescriptorCollection GetEvents () { if (_events != null) return _events; bool cache = true; EventInfo[] events = _component.GetType().GetEvents (); Hashtable t = new Hashtable (); foreach (EventInfo ev in events) t [ev.Name] = new ReflectionEventDescriptor (ev); if (_component.Site != null) { ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService)); if (filter != null) cache = filter.FilterEvents (_component, t); } ArrayList atts = new ArrayList (); atts.AddRange (t.Values); EventDescriptorCollection attCol = new EventDescriptorCollection (atts); if (cache) _events = attCol; return attCol; } public override PropertyDescriptorCollection GetProperties () { if (_properties != null) return _properties; bool cache = true; PropertyInfo[] props = _component.GetType().GetProperties (BindingFlags.Instance | BindingFlags.Public); Hashtable t = new Hashtable (); foreach (PropertyInfo pr in props) t [pr.Name] = new ReflectionPropertyDescriptor (pr); if (_component.Site != null) { ITypeDescriptorFilterService filter = (ITypeDescriptorFilterService) _component.Site.GetService (typeof(ITypeDescriptorFilterService)); if (filter != null) cache = filter.FilterProperties (_component, t); } PropertyDescriptor[] descriptors = new PropertyDescriptor[t.Values.Count]; t.Values.CopyTo (descriptors, 0); PropertyDescriptorCollection attCol = new PropertyDescriptorCollection (descriptors, true); if (cache) _properties = attCol; return attCol; } } internal class TypeInfo : Info { EventDescriptorCollection _events; PropertyDescriptorCollection _properties; public TypeInfo (Type t): base (t) { } public override AttributeCollection GetAttributes () { return base.GetAttributes (null); } public override EventDescriptorCollection GetEvents () { if (_events != null) return _events; EventInfo[] events = InfoType.GetEvents (); EventDescriptor[] descs = new EventDescriptor [events.Length]; for (int n=0; n