summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clang-tidy-vs/ClangTidy/DynamicPropertyComponent.cs
blob: e8843db40e21c99c7099cb9cb9cb1006d23263bd (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
138
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LLVM.ClangTidy
{
    /// <summary>
    /// The goal of this class is to enable displaying of a PropertyGrid in much the
    /// same way that Visual Studio's C++ project system does.  A project or file can
    /// have properties which might inherit from their parent, or be overridden.
    /// It turns out this is somewhat non-trivial.  The .NET PropertyGrid is good makes
    /// displaying simple properties with a static notion of what constitutes a
    /// "default" value very easy.  You simply apply an Attribute to the class that says
    /// what the default value is and you're done.  But when you try to introduce the idea
    /// that a property's default value depends on some other factor, things get much more
    /// complicated due to the static nature of Attributes.
    /// 
    /// The solution to this is to inherit from ICustomTypeDescriptor.  This is the mechanism
    /// by which you can inject or modify attributes or properties at runtime.  The .NET
    /// PropertyGrid is designed in such a way that instead of using simple .NET Reflection to
    /// look for the properties and attributes on a class, it will invoke the methods of
    /// ICustomTypeDescriptor (if your type inherits from it), and ask those methods.  Our
    /// implementation of ICustomTypeDescriptor works by waiting until the PropertyGrid requests
    /// PropertyDescriptors for each of the properties, and then "decorating" them with our
    /// own custom PropertyDescriptor implementation which understands the proeprty inheritance
    /// model we wish to implement.
    /// </summary>
    public partial class DynamicPropertyComponent : Component, ICustomTypeDescriptor
    {
        PropertyDescriptorCollection DynamicProperties_ = new PropertyDescriptorCollection(null);
        private DynamicPropertyComponent Parent_;

        public DynamicPropertyComponent(DynamicPropertyComponent Parent)
        {
            Parent_ = Parent;
        }

        public DynamicPropertyComponent(DynamicPropertyComponent Parent, IContainer container)
        {
            Parent_ = Parent;

            container.Add(this);
            InitializeComponent();
        }

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(GetType());
        }

        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(GetType());
        }

        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(GetType());
        }

        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(GetType());
        }

        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(GetType());
        }

        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(GetType());
        }

        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(GetType(), editorBaseType);
        }

        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(GetType());
        }

        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(GetType(), attributes);
        }

        public PropertyDescriptorCollection GetProperties()
        {
            return DynamicProperties_;
        }

        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var Props = DynamicProperties_.OfType<PropertyDescriptor>();
            var Filtered = Props.Where(x => x.Attributes.Contains(attributes)).ToArray();
            return new PropertyDescriptorCollection(Filtered);
        }

        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return this;
        }

        public void SetDynamicValue<T>(string Name, T Value)
        {
            Name = Name.Replace('-', '_');
            DynamicPropertyDescriptor<T> Descriptor = (DynamicPropertyDescriptor<T>)DynamicProperties_.Find(Name, false);
            Descriptor.SetValue(this, Value);
        }

        public T GetDynamicValue<T>(string Name)
        {
            Name = Name.Replace('-', '_');
            DynamicPropertyDescriptor<T> Descriptor = (DynamicPropertyDescriptor<T>)DynamicProperties_.Find(Name, false);
            return (T)Descriptor.GetValue(this);
        }

        protected void AddDynamicProperty<T>(string Name, Attribute[] Attributes)
        {
            Name = Name.Replace('-', '_');

            // If we have a parent, find the corresponding PropertyDescriptor with the same
            // name from the parent.
            DynamicPropertyDescriptor<T> ParentDescriptor = null;
            if (Parent_ != null)
                ParentDescriptor = (DynamicPropertyDescriptor<T>)Parent_.GetProperties().Find(Name, false);

            DynamicProperties_.Add(new DynamicPropertyDescriptor<T>(Name, ParentDescriptor, Name, Attributes));
        }
    }
}
OpenPOWER on IntegriCloud