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 : PropertyDescriptor { T Value_; DynamicPropertyDescriptor Parent_; bool IsInheriting_; object Component_; public DynamicPropertyDescriptor(object Component, DynamicPropertyDescriptor Parent, string Name, Attribute[] Attrs) : base(Name, Attrs) { foreach (DefaultValueAttribute Attr in Attrs.OfType()) { Value_ = (T)Attr.Value; } Parent_ = Parent; IsInheriting_ = true; Component_ = Component; } public bool IsInheriting { get { return IsInheriting_; } set { IsInheriting_ = value; } } public DynamicPropertyDescriptor Parent { get { return Parent_; } } /// /// 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. /// /// /// public override bool ShouldSerializeValue(object component) { return (Parent_ != null) && !IsInheriting; } /// /// 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. /// /// 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().LastOrDefault(); if (ConverterAttr != null) { Type ConverterType = Type.GetType(ConverterAttr.ConverterTypeName); UnderlyingConverter = (TypeConverter)Activator.CreateInstance(ConverterType); } else UnderlyingConverter = TypeDescriptor.GetConverter(typeof(T)); return new DynamicPropertyConverter(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); } } } }