[NUI]Add xaml support for nui and nui xaml test sample (#230)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / ExpandMarkupsVisitor.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Xml;
4 using Tizen.NUI.Internals;
5
6 namespace Tizen.NUI.Xaml
7 {
8         class ExpandMarkupsVisitor : IXamlNodeVisitor
9         {
10                 public ExpandMarkupsVisitor(HydrationContext context)
11                 {
12                         Context = context;
13                 }
14
15                 public static readonly IList<XmlName> Skips = new List<XmlName>
16                 {
17                         XmlName.xKey,
18                         XmlName.xTypeArguments,
19                         XmlName.xFactoryMethod,
20                         XmlName.xName,
21                         XmlName.xDataType
22                 };
23
24                 Dictionary<INode, object> Values
25                 {
26                         get { return Context.Values; }
27                 }
28
29                 HydrationContext Context { get; }
30
31                 public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
32                 public bool StopOnDataTemplate => false;
33                 public bool StopOnResourceDictionary => false;
34                 public bool VisitNodeOnDataTemplate => true;
35                 public bool SkipChildren(INode node, INode parentNode) => false;
36
37                 public void Visit(ValueNode node, INode parentNode)
38                 {
39                 }
40
41                 public void Visit(MarkupNode markupnode, INode parentNode)
42                 {
43                         var parentElement = parentNode as IElementNode;
44                         XmlName propertyName;
45                         if (!ApplyPropertiesVisitor.TryGetPropertyName(markupnode, parentNode, out propertyName))
46                                 return;
47                         if (Skips.Contains(propertyName))
48                                 return;
49                         if (parentElement.SkipProperties.Contains(propertyName))
50                                 return;
51
52                         var markupString = markupnode.MarkupString;
53                         var node =
54                                 ParseExpression(ref markupString, markupnode.NamespaceResolver, markupnode, markupnode, parentNode) as IElementNode;
55                         if (node != null)
56                         {
57                                 ((IElementNode)parentNode).Properties[propertyName] = node;
58                                 node.Parent = parentNode;
59                         }
60                 }
61
62                 public void Visit(ElementNode node, INode parentNode)
63                 {
64                 }
65
66                 public void Visit(RootNode node, INode parentNode)
67                 {
68                 }
69
70                 public void Visit(ListNode node, INode parentNode)
71                 {
72                 }
73
74                 INode ParseExpression(ref string expression, IXmlNamespaceResolver nsResolver, IXmlLineInfo xmlLineInfo, INode node,
75                         INode parentNode)
76                 {
77                         if (expression.StartsWith("{}", StringComparison.Ordinal))
78                                 return new ValueNode(expression.Substring(2), null);
79
80                         if (expression[expression.Length - 1] != '}')
81                                 throw new Exception("Expression must end with '}'");
82
83                         int len;
84                         string match;
85                         if (!MarkupExpressionParser.MatchMarkup(out match, expression, out len))
86                                 throw new Exception();
87                         expression = expression.Substring(len).TrimStart();
88                         if (expression.Length == 0)
89                                 throw new Exception("Expression did not end in '}'");
90
91                         var serviceProvider = new XamlServiceProvider(node, Context);
92                         serviceProvider.Add(typeof (IXmlNamespaceResolver), nsResolver);
93
94                         return new MarkupExpansionParser().Parse(match, ref expression, serviceProvider);
95                 }
96
97                 public class MarkupExpansionParser : MarkupExpressionParser, IExpressionParser<INode>
98                 {
99                         IElementNode node;
100
101                         object IExpressionParser.Parse(string match, ref string remaining, IServiceProvider serviceProvider)
102                         {
103                                 return Parse(match, ref remaining, serviceProvider);
104                         }
105
106                         public INode Parse(string match, ref string remaining, IServiceProvider serviceProvider)
107                         {
108                                 var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
109                                 if (nsResolver == null)
110                                         throw new ArgumentException();
111                                 IXmlLineInfo xmlLineInfo = null;
112                                 var xmlLineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
113                                 if (xmlLineInfoProvider != null)
114                                         xmlLineInfo = xmlLineInfoProvider.XmlLineInfo;
115
116                                 var split = match.Split(':');
117                                 if (split.Length > 2)
118                                         throw new ArgumentException();
119
120                                 string prefix; //, name;
121                                 if (split.Length == 2)
122                                 {
123                                         prefix = split[0];
124                                         //                                      name = split [1];
125                                 }
126                                 else
127                                 {
128                                         prefix = "";
129                                         //                                      name = split [0];
130                                 }
131
132                                 Type type;
133                                 var typeResolver = serviceProvider.GetService(typeof (IXamlTypeResolver)) as IXamlTypeResolver;
134                                 if (typeResolver == null)
135                                         type = null;
136                 // Add Binding and StaticResource support, The ordinal code can't find BindingExtension for Binding
137                 //else if (match == "Binding")
138                 //{
139                 //    type = typeof(BindingExtension);
140                 //}
141                 //else if (match == "StaticResource")
142                 //{
143                 //    type = typeof(StaticResourceExtension);
144                 //}
145                                 else
146                                 {
147                                         //The order of lookup is to look for the Extension-suffixed class name first and then look for the class name without the Extension suffix.
148                                         if (!typeResolver.TryResolve(match + "Extension", out type) && !typeResolver.TryResolve(match, out type))
149                                         {
150                                                 var lineInfoProvider = serviceProvider.GetService(typeof (IXmlLineInfoProvider)) as IXmlLineInfoProvider;
151                                                 var lineInfo = (lineInfoProvider != null) ? lineInfoProvider.XmlLineInfo : new XmlLineInfo();
152                                                 throw new XamlParseException(String.Format("MarkupExtension not found for {0}", match), lineInfo);
153                                         }
154                                 }
155
156                                 var namespaceuri = nsResolver.LookupNamespace(prefix) ?? "";
157                                 var xmltype = new XmlType(namespaceuri, type.Name, null);
158
159                                 if (type == null)
160                                         throw new NotSupportedException();
161
162                                 node = xmlLineInfo == null
163                                         ? new ElementNode(xmltype, null, nsResolver)
164                                         : new ElementNode(xmltype, null, nsResolver, xmlLineInfo.LineNumber, xmlLineInfo.LinePosition);
165
166                                 if (remaining.StartsWith("}", StringComparison.Ordinal))
167                                 {
168                                         remaining = remaining.Substring(1);
169                                         return node;
170                                 }
171
172                                 char next;
173                                 string piece;
174                                 while ((piece = GetNextPiece(ref remaining, out next)) != null)
175                                         HandleProperty(piece, serviceProvider, ref remaining, next != '=');
176
177                                 return node;
178                         }
179
180                         protected override void SetPropertyValue(string prop, string strValue, object value, IServiceProvider serviceProvider)
181                         {
182                                 var nsResolver = serviceProvider.GetService(typeof (IXmlNamespaceResolver)) as IXmlNamespaceResolver;
183
184                                 var childnode = value as INode ?? new ValueNode(strValue, nsResolver);
185                                 childnode.Parent = node;
186                                 if (prop != null)
187                                 {
188                                         var name = new XmlName(node.NamespaceURI, prop);
189                                         node.Properties[name] = childnode;
190                                 }
191                                 else //ContentProperty
192                                         node.CollectionItems.Add(childnode);
193                         }
194                 }
195         }
196 }