[NUI] Change GetDefaultWindow() to static func (#900)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / XamlBinding / BindablePropertyConverter.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Globalization;
5 using System.Linq;
6 using System.Reflection;
7 using System.Xml;
8 using Tizen.NUI.Binding.Internals;
9 using Tizen.NUI.Xaml;
10
11 namespace Tizen.NUI.Binding
12 {
13     [Xaml.ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.BindablePropertyConverter")]
14     [Xaml.TypeConversion(typeof(BindableProperty))]
15     internal sealed class BindablePropertyConverter : TypeConverter, IExtendedTypeConverter
16     {
17         object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider)
18         {
19             return ((IExtendedTypeConverter)this).ConvertFromInvariantString(value as string, serviceProvider);
20         }
21
22         object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider)
23         {
24             if (string.IsNullOrWhiteSpace(value))
25                 return null;
26             if (serviceProvider == null)
27                 return null;
28             var parentValuesProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideParentValues;
29             var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver;
30             if (typeResolver == null)
31                 return null;
32             IXmlLineInfo lineinfo = null;
33             var xmlLineInfoProvider = serviceProvider.GetService(typeof(IXmlLineInfoProvider)) as IXmlLineInfoProvider;
34             if (xmlLineInfoProvider != null)
35                 lineinfo = xmlLineInfoProvider.XmlLineInfo;
36             string[] parts = value.Split('.');
37             Type type = null;
38             if (parts.Length == 1)
39             {
40                 if (parentValuesProvider == null)
41                 {
42                     string msg = string.Format("Can't resolve {0}", parts[0]);
43                     throw new XamlParseException(msg, lineinfo);
44                 }
45                 object parent = parentValuesProvider.ParentObjects.Skip(1).FirstOrDefault();
46                 if (parentValuesProvider.TargetObject is Setter)
47                 {
48                     var style = parent as Style;
49                     var triggerBase = parent as TriggerBase;
50                     var visualState = parent as VisualState;
51                     if (style != null)
52                         type = style.TargetType;
53                     else if (triggerBase != null)
54                         type = triggerBase.TargetType;
55                     else if (visualState != null)
56                         type = FindTypeForVisualState(parentValuesProvider, lineinfo);
57                 }
58                 else if (parentValuesProvider.TargetObject is Trigger)
59                     type = (parentValuesProvider.TargetObject as Trigger).TargetType;
60                 else if (parentValuesProvider.TargetObject is XamlPropertyCondition && (parent as TriggerBase) != null)
61                     type = (parent as TriggerBase).TargetType;
62
63                 if (type == null)
64                     throw new XamlParseException($"Can't resolve {parts [0]}", lineinfo);
65
66                 return ConvertFrom(type, parts[0], lineinfo);
67             }
68             if (parts.Length == 2)
69             {
70                 if (!typeResolver.TryResolve(parts[0], out type))
71                 {
72                     string msg = string.Format("Can't resolve {0}", parts[0]);
73                     throw new XamlParseException(msg, lineinfo);
74                 }
75                 return ConvertFrom(type, parts[1], lineinfo);
76             }
77             throw new XamlParseException($"Can't resolve {value}. Syntax is [[prefix:]Type.]PropertyName.", lineinfo);
78         }
79
80         public override object ConvertFromInvariantString(string value)
81         {
82             if (string.IsNullOrWhiteSpace(value))
83                 return null;
84             if (value.Contains(":"))
85             {
86                 Console.WriteLine(null, "Can't resolve properties with xml namespace prefix.");
87                 return null;
88             }
89             string[] parts = value.Split('.');
90             if (parts.Length != 2)
91             {
92                 Console.WriteLine(null, $"Can't resolve {value}. Accepted syntax is Type.PropertyName.");
93                 return null;
94             }
95             Type type = Type.GetType("Tizen.NUI." + parts[0]);
96             return ConvertFrom(type, parts[1], null);
97         }
98
99         BindableProperty ConvertFrom(Type type, string propertyName, IXmlLineInfo lineinfo)
100         {
101             string name = propertyName + "Property";
102             FieldInfo bpinfo = type.GetField(fi => fi.Name == name && fi.IsStatic && fi.IsPublic && fi.FieldType == typeof(BindableProperty));
103             if (bpinfo == null)
104                 throw new XamlParseException($"Can't resolve {name} on {type.Name}", lineinfo);
105             var bp = bpinfo.GetValue(null) as BindableProperty;
106             var isObsolete = bpinfo.GetCustomAttribute<ObsoleteAttribute>() != null;
107             if (bp != null && bp.PropertyName != propertyName && !isObsolete)
108                 throw new XamlParseException($"The PropertyName of {type.Name}.{name} is not {propertyName}", lineinfo);
109             return bp;
110         }
111
112         Type FindTypeForVisualState(IProvideParentValues parentValueProvider, IXmlLineInfo lineInfo)
113         {
114             var parents = parentValueProvider.ParentObjects.ToList();
115
116             // Skip 0; we would not be making this check if TargetObject were not a Setter
117             // Skip 1; we would not be making this check if the immediate parent were not a VisualState
118
119             // VisualStates must be in a VisualStateGroup
120             if(!(parents[2] is VisualStateGroup)) {
121                 throw new XamlParseException($"Expected {nameof(VisualStateGroup)} but found {parents[2]}.", lineInfo);
122             }
123
124             var vsTarget = parents[3];
125
126             // Are these Visual States directly on a VisualElement?
127             if (vsTarget is /*VisualElement*/BaseHandle)
128             {
129                 return vsTarget.GetType();
130             }
131
132             if (!(parents[3] is VisualStateGroupList))
133             {
134                 throw new XamlParseException($"Expected {nameof(VisualStateGroupList)} but found {parents[3]}.", lineInfo);
135             }
136
137             if (!(parents[4] is Setter))
138             {
139                 throw new XamlParseException($"Expected {nameof(Setter)} but found {parents[4]}.", lineInfo);
140             }
141
142             // These must be part of a Style; verify that 
143             if (!(parents[5] is Style style))
144             {
145                 throw new XamlParseException($"Expected {nameof(Style)} but found {parents[5]}.", lineInfo);
146             }
147
148             return style.TargetType;
149         }
150     }
151 }