138 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C#
		
	
	
	
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);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |