[reflection] Coop handles icalls in System.Reflection and System.RuntimeTypeHandle...
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Base / Core / Internal / PropertyEditing / Model / ModelUtilities.cs
1 //----------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //----------------------------------------------------------------
4 namespace System.Activities.Presentation.Internal.PropertyEditing.Model
5 {
6     using System;
7     using System.Collections.Generic;
8     using System.Diagnostics.CodeAnalysis;
9     using System.Text;
10     using System.Windows.Markup;
11     using System.Activities.Presentation.Model;
12     using System.Activities.Presentation.PropertyEditing;
13
14     // <summary>
15     // Static class full of useful helpers
16     // </summary>
17     internal static class ModelUtilities
18     {
19         public static Type GetPropertyType(IEnumerable<ModelProperty> propertySet)
20         {
21             // all the ModelProperty should be of the same type, so returning the first type.
22             foreach (ModelProperty property in propertySet)
23             {
24                 return property.PropertyType;
25             }
26             return null;
27         }
28
29         // <summary>
30         // Compares the name and Type of the specified ModelProperties,
31         // returning true if they are equal.
32         // </summary>
33         // <param name="a">ModelProperty A</param>
34         // <param name="b">ModelProperty B</param>
35         // <returns>True if the names and Types of the specified ModelProperties
36         // match, false otherwise.</returns>
37         public static bool AreEquivalent(ModelProperty a, ModelProperty b)
38         {
39             return object.Equals(a.Name, b.Name) &&
40                 object.Equals(a.PropertyType, b.PropertyType);
41         }
42
43         // <summary>
44         // Gets the underlying value object of the specified ModelProperty.  MarkupExtensions
45         // (resources and such) will be returned as they are, with the exception of NullExtension,
46         // which will be returned as null.
47         // </summary>
48         // <param name="property">ModelProperty to ---- open (can be null)</param>
49         // <returns>Underlying value object, if any</returns>
50         public static object GetSafeRawValue(ModelProperty property)
51         {
52             return GetSafeValue(property, false);
53         }
54
55         // <summary>
56         // Gets the underlying computed value object of the specified ModelProperty.  MarkupExtensions
57         // (resources and such) will be resolved into their final value.
58         // </summary>
59         // <param name="property">ModelProperty to ---- open (can be null)</param>
60         // <returns>Underlying value object, if any</returns>
61         public static object GetSafeComputedValue(ModelProperty property)
62         {
63             return GetSafeValue(property, true);
64         }
65
66         private static object GetSafeValue(ModelProperty property, bool resolveReferences)
67         {
68             if (property == null)
69             {
70                 return null;
71             }
72
73             object value;
74
75             // We have to special case TextBlock due to IAddChild behavior with Text and Inlines
76             if (resolveReferences && !(typeof(System.Windows.Controls.TextBlock).IsAssignableFrom(property.Parent.ItemType) &&
77                 property.Name.Equals(System.Windows.Controls.TextBlock.TextProperty.Name)))
78             {
79                 value = property.ComputedValue;
80             }
81             else
82             {
83                 value = property.Value == null ? null : property.Value.GetCurrentValue();
84             }
85
86             if (value == null || value.GetType().Equals(typeof(NullExtension)))
87             {
88                 return null;
89             }
90
91             return value;
92         }
93
94         // <summary>
95         // Looks for the x:Name or Name property of the given PropertyValue and returns it if found.
96         // Note: this method is expensive because it evaluates all the sub-properties of the given
97         // PropertyValue.
98         // </summary>
99         // <param name="propertyValue">PropertyValue instance to look at</param>
100         // <returns>Name if the PropertyValue defines one, null otherwise</returns>
101         public static string GetPropertyName(PropertyValue propertyValue)
102         {
103             if (propertyValue == null)
104             {
105                 return null;
106             }
107
108             if (propertyValue.HasSubProperties)
109             {
110                 PropertyEntry nameProperty = propertyValue.SubProperties["Name"];
111                 if (nameProperty != null)
112                 {
113                     return nameProperty.PropertyValue.StringValue;
114                 }
115             }
116
117             return null;
118         }
119
120         // <summary>
121         // Returns ',' separated property name for sub-properties, going all the way
122         // to the root ancestor in the property editing OM.  (ie. you get strings
123         // such as 'ContextMenu,IsEnabled' instead of just 'IsEnabled'.
124         // </summary>
125         // <param name="property">Property to get the name of</param>
126         // <returns>',' separated property name for sub-properties</returns>
127         public static string GetSubPropertyHierarchyPath(PropertyEntry property)
128         {
129             if (property == null)
130             {
131                 return null;
132             }
133
134             if (property.ParentValue == null)
135             {
136                 return property.PropertyName;
137             }
138
139             StringBuilder sb = new StringBuilder();
140             do
141             {
142                 if (sb.Length > 0)
143                 {
144                     sb.Insert(0, ',');
145                 }
146
147                 sb.Insert(0, property.PropertyName);
148                 property = property.ParentValue == null ? null : property.ParentValue.ParentProperty;
149
150             } while (property != null && !(property is ModelPropertyIndexer));
151
152             return sb.ToString();
153         }
154
155         // <summary>
156         // Same as GetSubPropertyHierarchyPath(), but it looks up a cached version
157         // of this path, if one exists, or calculates one from scratch and caches it
158         // if it doesn't.
159         // </summary>
160         // <param name="property">Property to get the name of</param>
161         // <returns>',' separated property name for sub-properties</returns>
162         public static string GetCachedSubPropertyHierarchyPath(PropertyEntry property)
163         {
164             ModelPropertyEntry mpe = property as ModelPropertyEntry;
165             return mpe == null ? GetSubPropertyHierarchyPath(property) : mpe.SubPropertyHierarchyPath;
166         }
167
168         // <summary>
169         // Determines whether the specified type is implement generic Ilist interface.
170         // </summary>
171         // <param name="type">The type.</param>
172         // <returns>
173         // <c>true</c> if the specified type is implement generic Ilist interface;otherwise, <c>false</c>.
174         // </returns>
175         public static bool ImplementsIList(Type type)
176         {
177             bool ret = false;
178             if (!type.IsGenericType)
179             {
180                 ret = false;
181             }
182             Type[] interfaceTypes = type.GetInterfaces();
183             foreach (Type interfaceType in interfaceTypes)
184             {
185                 if (interfaceType.IsGenericType &&
186                     interfaceType.GetGenericTypeDefinition() == typeof(IList<>))
187                 {
188                     ret = true;
189                     break;
190                 }
191             }
192             return ret;
193         }
194
195         // <summary>
196         // Determines whether the specified type is implement generic ICollection interface.
197         // </summary>
198         // <param name="type">The type.</param>
199         // <returns>
200         // <c>true</c> if the specified type is implement generic ICollection interface;otherwise, <c>false</c>.
201         // </returns>
202         public static bool ImplementsICollection(Type type)
203         {
204             bool ret = false;
205             if (!type.IsGenericType)
206             {
207                 ret = false;
208             }
209             Type[] interfaceTypes = type.GetInterfaces();
210             foreach (Type interfaceType in interfaceTypes)
211             {
212                 if (interfaceType.IsGenericType &&
213                     interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
214                 {
215                     ret = true;
216                     break;
217                 }
218             }
219             return ret;
220         }
221
222         // <summary>
223         // Tries to determine the common type ancestor of the specified types
224         // </summary>
225         // <param name="t1">Type 1</param>
226         // <param name="t2">Type 2</param>
227         // <returns>Common ancestor Type, if any</returns>
228         public static Type GetCommonAncestor(Type t1, Type t2)
229         {
230             if (t1 == null || t2 == null)
231             {
232                 return null;
233             }
234
235             if (t1 == typeof(object) || t2 == typeof(object))
236             {
237                 return typeof(object);
238             }
239
240             if (t1.IsAssignableFrom(t2))
241             {
242                 return t1;
243             }
244
245             while (t2 != typeof(object))
246             {
247                 if (t2.IsAssignableFrom(t1))
248                 {
249                     return t2;
250                 }
251
252                 t2 = t2.BaseType;
253             }
254
255             return typeof(object);
256         }
257     }
258 }