[NUI] Change GetDefaultWindow() to static func (#900)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / Registrar.cs
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Linq;
5 using System.Reflection;
6 using Tizen.NUI.Binding;
7
8 namespace Tizen.NUI.Binding
9 {
10     // Previewer uses reflection to bind to this method; Removal or modification of visibility will break previewer.
11     internal static class Registrar
12     {
13         internal static void RegisterAll(Type[] attrTypes) => Internals.Registrar.RegisterAll(attrTypes);
14     }
15 }
16
17 namespace Tizen.NUI.Binding.Internals
18 {
19     /// <summary>
20     /// For internal use.
21     /// </summary>
22     /// <typeparam name="TRegistrable"></typeparam>
23     [EditorBrowsable(EditorBrowsableState.Never)]
24     internal class Registrar<TRegistrable> where TRegistrable : class
25     {
26         readonly Dictionary<Type, Type> _handlers = new Dictionary<Type, Type>();
27
28         /// <summary>
29         /// Register.
30         /// </summary>
31         /// <param name="tview">The type of the view</param>
32         /// <param name="trender">The type of the render.</param>
33         public void Register(Type tview, Type trender)
34         {
35             //avoid caching null renderers
36             if (trender == null)
37                 return;
38             _handlers[tview] = trender;
39         }
40
41         internal TRegistrable GetHandler(Type type)
42         {
43             Type handlerType = GetHandlerType(type);
44             if (handlerType == null)
45                 return null;
46
47             object handler = DependencyResolver.ResolveOrCreate(handlerType);
48
49             return (TRegistrable)handler;
50         }
51
52         internal TRegistrable GetHandler(Type type, params object[] args)
53         {
54             if (args.Length == 0)
55             {
56                 return GetHandler(type);
57             }
58
59             Type handlerType = GetHandlerType(type);
60             if (handlerType == null)
61                 return null;
62
63             return (TRegistrable)DependencyResolver.ResolveOrCreate(handlerType, args);
64         }
65
66         /// <summary>
67         /// For internal use. Returns handler.
68         /// </summary>
69         /// <typeparam name="TOut">The type of the handler</typeparam>
70         /// <param name="type">The type.</param>
71         /// <returns>The handler instance.</returns>
72         public TOut GetHandler<TOut>(Type type) where TOut : TRegistrable
73         {
74             return (TOut)GetHandler(type);
75         }
76
77         /// <summary>
78         /// For internal use. Returns handler.
79         /// </summary>
80         /// <typeparam name="TOut">The type of the handler</typeparam>
81         /// <param name="type">The type.</param>
82         /// <param name="args">The args of the type</param>
83         /// <returns>The handler instance.</returns>
84         public TOut GetHandler<TOut>(Type type, params object[] args) where TOut : TRegistrable
85         {
86             return (TOut)GetHandler(type, args);
87         }
88
89         /// <summary>
90         /// For internal use. Return the handler of the object.
91         /// </summary>
92         /// <typeparam name="TOut">Thetype</typeparam>
93         /// <param name="obj">The object instance.</param>
94         /// <returns>The handle of the obj.</returns>
95         public TOut GetHandlerForObject<TOut>(object obj) where TOut : TRegistrable
96         {
97             if (obj == null)
98                 throw new ArgumentNullException(nameof(obj));
99
100             var reflectableType = obj as IReflectableType;
101             var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
102
103             return (TOut)GetHandler(type);
104         }
105
106         /// <summary>
107         /// For inetrnal use. Return the handler of the object.
108         /// </summary>
109         /// <typeparam name="TOut">The type</typeparam>
110         /// <param name="obj">The object instance</param>
111         /// <param name="args">The args of the type</param>
112         /// <returns>The handler of the object.</returns>
113         public TOut GetHandlerForObject<TOut>(object obj, params object[] args) where TOut : TRegistrable
114         {
115             if (obj == null)
116                 throw new ArgumentNullException(nameof(obj));
117
118             var reflectableType = obj as IReflectableType;
119             var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
120
121             return (TOut)GetHandler(type, args);
122         }
123
124         /// <summary>
125         /// For internal use. Returns the handle type.
126         /// </summary>
127         /// <param name="viewType">The view type.</param>
128         /// <returns>The type of the handle.</returns>
129         public Type GetHandlerType(Type viewType)
130         {
131             Type type;
132             if (LookupHandlerType(viewType, out type))
133                 return type;
134
135             // lazy load render-view association with RenderWithAttribute (as opposed to using ExportRenderer)
136             var attribute = viewType.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
137             if (attribute == null)
138             {
139                 Register(viewType, null); // Cache this result so we don't have to do GetCustomAttribute again
140                 return null;
141             }
142
143             type = attribute.Type;
144
145             if (type.Name.StartsWith("_", StringComparison.Ordinal))
146             {
147                 // TODO: Remove attribute2 once renderer names have been unified across all platforms
148                 var attribute2 = type.GetTypeInfo().GetCustomAttribute<RenderWithAttribute>();
149                 if (attribute2 != null)
150                     type = attribute2.Type;
151
152                 if (type.Name.StartsWith("_", StringComparison.Ordinal))
153                 {
154                     Register(viewType, null); // Cache this result so we don't work through this chain again
155                     return null;
156                 }
157             }
158
159             Register(viewType, type); // Register this so we don't have to look for the RenderWith Attibute again in the future
160
161             return type;
162         }
163
164         /// <summary>
165         /// For internal use. Return the handle type of the object
166         /// </summary>
167         /// <param name="obj">The object instance.</param>
168         /// <returns>The type of the handler.</returns>
169         public Type GetHandlerTypeForObject(object obj)
170         {
171             if (obj == null)
172                 throw new ArgumentNullException(nameof(obj));
173
174             var reflectableType = obj as IReflectableType;
175             var type = reflectableType != null ? reflectableType.GetTypeInfo().AsType() : obj.GetType();
176
177             return GetHandlerType(type);
178         }
179
180         bool LookupHandlerType(Type viewType, out Type handlerType)
181         {
182             Type type = viewType;
183
184             while (type != null)
185             {
186                 if (_handlers.ContainsKey(type))
187                 {
188                     handlerType = _handlers[type];
189                     return true;
190                 }
191
192                 type = type.GetTypeInfo().BaseType;
193             }
194
195             handlerType = null;
196             return false;
197         }
198     }
199
200     /// <summary>
201     /// For internal use
202     /// </summary>
203     [EditorBrowsable(EditorBrowsableState.Never)]
204     internal static class Registrar
205     {
206         static Registrar()
207         {
208             Registered = new Registrar<IRegisterable>();
209         }
210
211         internal static Dictionary<string, Type> Effects { get; } = new Dictionary<string, Type>();
212         internal static Dictionary<string, StyleSheets.StylePropertyAttribute> StyleProperties { get; } = new Dictionary<string, StyleSheets.StylePropertyAttribute>();
213
214         public static IEnumerable<Assembly> ExtraAssemblies { get; set; }
215
216         public static Registrar<IRegisterable> Registered { get; internal set; }
217
218         public static void RegisterAll(Type[] attrTypes)
219         {
220             Assembly[] assemblies = Device.GetAssemblies();
221             if (ExtraAssemblies != null)
222                 assemblies = assemblies.Union(ExtraAssemblies).ToArray();
223
224             Assembly defaultRendererAssembly = Device.PlatformServices.GetType().GetTypeInfo().Assembly;
225             int indexOfExecuting = Array.IndexOf(assemblies, defaultRendererAssembly);
226
227             if (indexOfExecuting > 0)
228             {
229                 assemblies[indexOfExecuting] = assemblies[0];
230                 assemblies[0] = defaultRendererAssembly;
231             }
232
233             // Don't use LINQ for performance reasons
234             // Naive implementation can easily take over a second to run
235             foreach (Assembly assembly in assemblies)
236             {
237                 foreach (Type attrType in attrTypes)
238                 {
239                     Attribute[] attributes;
240                     try
241                     {
242                         attributes = assembly.GetCustomAttributes(attrType).ToArray();
243                     }
244                     catch (System.IO.FileNotFoundException)
245                     {
246                         // Sometimes the previewer doesn't actually have everything required for these loads to work
247                         Console.WriteLine(nameof(Registrar), "Could not load assembly: {0} for Attibute {1} | Some renderers may not be loaded", assembly.FullName, attrType.FullName);
248                         continue;
249                     }
250                     var length = attributes.Length;
251                     for (var i = 0; i < length;i++)
252                     {
253                         var attribute = (HandlerAttribute)attributes[i];
254                         if (attribute.ShouldRegister())
255                             Registered.Register(attribute.HandlerType, attribute.TargetType);
256                     }
257                 }
258
259                 string resolutionName = assembly.FullName;
260                 var resolutionNameAttribute = (ResolutionGroupNameAttribute)assembly.GetCustomAttribute(typeof(ResolutionGroupNameAttribute));
261                 if (resolutionNameAttribute != null)
262                     resolutionName = resolutionNameAttribute.ShortName;
263
264                 Attribute[] effectAttributes = assembly.GetCustomAttributes(typeof(ExportEffectAttribute)).ToArray();
265                 var exportEffectsLength = effectAttributes.Length;
266                 for (var i = 0; i < exportEffectsLength;i++)
267                 {
268                     var effect = (ExportEffectAttribute)effectAttributes[i];
269                     Effects [resolutionName + "." + effect.Id] = effect.Type;
270                 }
271
272                 Attribute[] styleAttributes = assembly.GetCustomAttributes(typeof(StyleSheets.StylePropertyAttribute)).ToArray();
273                 var stylePropertiesLength = styleAttributes.Length;
274                 for (var i = 0; i < stylePropertiesLength; i++)
275                 {
276                     var attribute = (StyleSheets.StylePropertyAttribute)styleAttributes[i];
277                     StyleProperties[attribute.CssPropertyName] = attribute;
278                 }
279             }
280
281             DependencyService.Initialize(assemblies);
282         }
283     }
284 }