summaryrefslogtreecommitdiffstats
path: root/clang-tidy-vs/ClangTidy/DynamicPropertyDescriptor.cs
blob: f0d76914d845dc26a9ab70558200946b01f1c95b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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);
            }
        }
    }
}