New tests.
[mono.git] / mcs / class / System.Xaml / System.Xaml / TypeExtensionMethods.cs
1 //
2 // Copyright (C) 2010 Novell Inc. http://novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 using System;
24 using System.Collections;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.Linq;
28 using System.Reflection;
29 using System.Windows.Markup;
30 using System.Xaml.Schema;
31
32 namespace System.Xaml
33 {
34         static class TypeExtensionMethods
35         {
36                 // FIXME: this likely needs to be replaced with XamlTypeName
37                 public static string GetXamlName (this Type type)
38                 {
39                         if (!type.IsNested)
40                                 return type.Name;
41                         return type.DeclaringType.GetXamlName () + "+" + type.Name;
42                 }
43
44                 #region inheritance search and custom attribute provision
45
46                 public static T GetCustomAttribute<T> (this ICustomAttributeProvider type, bool inherit) where T : Attribute
47                 {
48                         foreach (var a in type.GetCustomAttributes (typeof (T), inherit))
49                                 return (T) (object) a;
50                         return null;
51                 }
52
53                 public static T GetCustomAttribute<T> (this XamlType type) where T : Attribute
54                 {
55                         if (type.UnderlyingType == null)
56                                 return null;
57
58                         T ret = type.CustomAttributeProvider.GetCustomAttribute<T> (true);
59                         if (ret != null)
60                                 return ret;
61                         if (type.BaseType != null)
62                                 return type.BaseType.GetCustomAttribute<T> ();
63                         return null;
64                 }
65
66                 public static bool ImplementsAnyInterfacesOf (this Type type, params Type [] definitions)
67                 {
68                         return definitions.Any (t => ImplementsInterface (type, t));
69                 }
70
71                 public static bool ImplementsInterface (this Type type, Type definition)
72                 {
73                         if (type == null)
74                                 throw new ArgumentNullException ("type");
75                         if (definition == null)
76                                 throw new ArgumentNullException ("definition");
77
78                         foreach (var iface in type.GetInterfaces ())
79                                 if (iface == definition || (iface.IsGenericType && iface.GetGenericTypeDefinition () == definition))
80                                         return true;
81                         return false;
82                 }
83                 
84                 #endregion
85                 
86                 #region type conversion and member value retrieval
87                 
88                 public static string GetStringValue (this XamlType xt, object obj, INamespacePrefixLookup prefixLookup)
89                 {
90                         if (obj == null)
91                                 return String.Empty;
92                         if (obj is Type)
93                                 return new XamlTypeName (xt.SchemaContext.GetXamlType ((Type) obj)).ToString (prefixLookup);
94
95                         if (obj is DateTime)
96                                 // FIXME: DateTimeValueSerializer should apply
97                                 return (string) TypeDescriptor.GetConverter (typeof (DateTime)).ConvertToInvariantString (obj);
98                         else
99                                 return (string) xt.ConvertObject (obj, typeof (string));
100                 }
101
102                 public static object ConvertObject (this XamlType xt, object target, Type explicitTargetType)
103                 {
104                         return DoConvert (xt.TypeConverter, target, explicitTargetType ?? xt.UnderlyingType);
105                 }
106                 
107                 public static object GetMemberValueForObjectReader (this XamlMember xm, XamlType xt, object target, INamespacePrefixLookup prefixLookup)
108                 {
109                         object native = GetPropertyOrFieldValueForObjectReader (xm, xt, target, prefixLookup);
110                         var convertedType = xm.Type == null ? null : xm.Type.UnderlyingType;
111                         return DoConvert (xm.TypeConverter, native, convertedType);
112                 }
113                 
114                 static object DoConvert (XamlValueConverter<TypeConverter> converter, object value, Type targetType)
115                 {
116                         // First get member value, then convert it to appropriate target type.
117                         var tc = converter != null ? converter.ConverterInstance : null;
118                         if (tc != null && targetType != null && tc.CanConvertTo (targetType))
119                                 return tc.ConvertTo (value, targetType);
120                         return value;
121                 }
122
123                 static object GetPropertyOrFieldValueForObjectReader (this XamlMember xm, XamlType xt, object target, INamespacePrefixLookup prefixLookup)
124                 {
125                         // FIXME: should this be done here??
126                         if (xm == XamlLanguage.Initialization)
127                                 return target;
128                         if (xm == XamlLanguage.PositionalParameters) {
129                                 var argdefs = xt.GetConstructorArguments ().ToArray ();
130                                 string [] args = new string [argdefs.Length];
131                                 for (int i = 0; i < args.Length; i++) {
132                                         var am = argdefs [i];
133                                         args [i] = GetStringValue (am.Type, GetMemberValueForObjectReader (am, xt, target, prefixLookup), prefixLookup);
134                                 }
135                                 return String.Join (", ", args);
136                         }
137
138                         var mi = xm.UnderlyingMember;
139                         var fi = mi as FieldInfo;
140                         if (fi != null)
141                                 return fi.GetValue (target);
142                         var pi = mi as PropertyInfo;
143                         if (pi != null)
144                                 return pi.GetValue (target, null);
145
146                         throw new NotImplementedException (String.Format ("Cannot get value for {0}", xm));
147                 }
148                 
149                 #endregion
150
151                 public static bool IsContentValue (this XamlMember member)
152                 {
153                         if (member == XamlLanguage.Initialization)
154                                 return true;
155                         if (member == XamlLanguage.PositionalParameters)
156                                 return true;
157                         return IsContentValue (member.Type);
158                 }
159
160                 public static bool IsContentValue (this XamlType type)
161                 {
162                         var t = type.UnderlyingType;
163                         if (Type.GetTypeCode (t) != TypeCode.Object)
164                                 return true;
165                         else if (t == typeof (Type) || t == typeof (TimeSpan) || t == typeof (Uri)) // special predefined types
166                                 return true;
167                         return false;
168                 }
169
170                 public static IEnumerable<XamlMember> GetAllReadWriteMembers (this XamlType type)
171                 {
172                         // FIXME: find out why only TypeExtension yields this directive. Seealso XamlObjectReaderTest
173                         if (type == XamlLanguage.Type) {
174                                 yield return XamlLanguage.PositionalParameters;
175                                 yield break;
176                         }
177
178                         if (type.IsContentValue ())
179                                 yield return XamlLanguage.Initialization;
180
181                         foreach (var m in type.GetAllMembers ())
182                                 yield return m;
183                 }
184
185                 public static bool ListEquals (this IList<XamlType> a1, IList<XamlType> a2)
186                 {
187                         if (a1 == null || a1.Count == 0)
188                                 return a2 == null || a2.Count == 0;
189                         if (a2 == null || a2.Count == 0)
190                                 return false;
191                         if (a1.Count != a2.Count)
192                                 return false;
193                         for (int i = 0; i < a1.Count; i++)
194                                 if (a1 [i] != a2 [i])
195                                         return false;
196                         return true;
197                 }
198         }
199 }