| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Threading.Tasks; | |
| namespace LLVM.ClangTidy | |
| { | |
| public class DynamicPropertyDescriptor<T> : PropertyDescriptor | |
| { | |
| T Value_; | |
| DynamicPropertyDescriptor<T> Parent_; | |
| bool IsInheriting_; | |
| object Component_; | |
| public DynamicPropertyDescriptor(object Component, DynamicPropertyDescriptor<T> Parent, string Name, Attribute[] Attrs) | |
| : base(Name, Attrs) | |
| { | |
| foreach (DefaultValueAttribute Attr in Attrs.OfType<DefaultValueAttribute>()) | |
| { | |
| Value_ = (T)Attr.Value; | |
| } | |
| Parent_ = Parent; | |
| IsInheriting_ = true; | |
| Component_ = Component; | |
| } | |
| public bool IsInheriting { get { return IsInheriting_; } set { IsInheriting_ = value; } } | |
| public DynamicPropertyDescriptor<T> Parent { get { return Parent_; } } | |
| /// <summary> | |
| /// Determines whether this property's value should be considered "default" (e.g. | |
| /// displayed in bold in the property grid). Root properties are unmodifiable and | |
| /// always default. Non-root properties are default iff they are inheriting. | |
| /// That is to say, if a property is explicitly set to False, the property should | |
| /// be serialized even if the parent is also False. It would only not be serialized | |
| /// if the user had explicitly chosen to inherit it. | |
| /// </summary> | |
| /// <param name="component"></param> | |
| /// <returns></returns> | |
| public override bool ShouldSerializeValue(object component) | |
| { | |
| return (Parent_ != null) && !IsInheriting; | |
| } | |
| /// <summary> | |
| /// Set the value back to the default. For root properties, this essentially does | |
| /// nothing as they are read-only anyway. For non-root properties, this only means | |
| /// that the property is now inheriting. | |
| /// </summary> | |
| /// <param name="component"></param> | |
| public override void ResetValue(object component) | |
| { | |
| IsInheriting_ = true; | |
| } | |
| public override void SetValue(object component, object value) | |
| { | |
| // This is a bit of a trick. If the user chose the inheritance option from the | |
| // dropdown, we will try to set the value to that string. So look for that and | |
| // then just reset the value. | |
| if (value.Equals(MagicInheritance.Text)) | |
| ResetValue(component); | |
| else | |
| { | |
| // By explicitly setting the value, this property is no longer inheriting, | |
| // even if the value the property is being set to is the same as that of | |
| // the parent. | |
| IsInheriting_ = false; | |
| Value_ = (T)value; | |
| } | |
| } | |
| public override TypeConverter Converter | |
| { | |
| get | |
| { | |
| // We need to return a DynamicPropertyConverter<> that can deal with our requirement | |
| // to inject the inherit property option into the dropdown. But we still need to use | |
| // the "real" converter to do the actual work for the underlying type. Therefore, | |
| // we need to look for a TypeConverter<> attribute on the property, and if it is present | |
| // forward an instance of that converter to the DynamicPropertyConverter<>. Otherwise, | |
| // forward an instance of the default converter for type T to the DynamicPropertyConverter<>. | |
| TypeConverter UnderlyingConverter = null; | |
| var ConverterAttr = this.Attributes.OfType<TypeConverterAttribute>().LastOrDefault(); | |
| if (ConverterAttr != null) | |
| { | |
| Type ConverterType = Type.GetType(ConverterAttr.ConverterTypeName); | |
| UnderlyingConverter = (TypeConverter)Activator.CreateInstance(ConverterType); | |
| } | |
| else | |
| UnderlyingConverter = TypeDescriptor.GetConverter(typeof(T)); | |
| return new DynamicPropertyConverter<T>(this, UnderlyingConverter); | |
| } | |
| } | |
| public override bool IsReadOnly | |
| { | |
| get | |
| { | |
| return (Parent_ == null); | |
| } | |
| } | |
| public override Type ComponentType | |
| { | |
| get | |
| { | |
| return Component_.GetType(); | |
| } | |
| } | |
| public override object GetValue(object component) | |
| { | |
| // Return either this property's value or the parents value, depending on | |
| // whether or not this property is inheriting. | |
| if (IsInheriting_ && Parent != null) | |
| return Parent.GetValue(component); | |
| return Value_; | |
| } | |
| public override bool CanResetValue(object component) | |
| { | |
| return !IsReadOnly; | |
| } | |
| public override Type PropertyType | |
| { | |
| get | |
| { | |
| return typeof(T); | |
| } | |
| } | |
| } | |
| } |