llvm-project/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyDescriptor.cs

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);
}
}
}
}