Merge remote-tracking branch 'origin/master' into tizen
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / internal / Xaml / FillResourceDictionariesVisitor.cs
1 /*
2  * Copyright(c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections;
20 using System.Collections.Generic;
21 using System.Reflection;
22 using Tizen.NUI.Binding;
23
24 namespace Tizen.NUI.Xaml
25 {
26     internal class FillResourceDictionariesVisitor : IXamlNodeVisitor
27     {
28         public FillResourceDictionariesVisitor(HydrationContext context)
29         {
30             Context = context;
31         }
32
33         HydrationContext Context { get; }
34         Dictionary<INode, object> Values => Context.Values;
35
36         public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
37         public bool StopOnDataTemplate => true;
38         public bool StopOnResourceDictionary => false;
39         public bool VisitNodeOnDataTemplate => false;
40
41         public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
42
43         public void Visit(ValueNode node, INode parentNode)
44         {
45                         if (!Context.Types.TryGetValue((IElementNode)parentNode, out var type) || !typeof(ResourceDictionary).IsAssignableFrom(type))
46                 return;
47
48             node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
49         }
50
51         public void Visit(MarkupNode node, INode parentNode)
52         {
53         }
54
55         public void Visit(ElementNode node, INode parentNode)
56         {
57             if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null)
58                                 return;
59             XmlName propertyName;
60             //Set RD to VE
61             if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
62             {
63                 if ((propertyName.LocalName == "XamlResources" ||
64                      propertyName.LocalName.EndsWith(".XamlResources", StringComparison.Ordinal)) && value is ResourceDictionary)
65                 {
66                     var source = Values[parentNode];
67                     ApplyPropertiesVisitor.SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
68                     return;
69                 }
70             }
71
72             //Only proceed further if the node is a keyless RD
73             if (parentNode is IElementNode
74                                 && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
75                                 && typeof(ResourceDictionary).IsAssignableFrom(parentType)
76                 && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
77                 node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
78             else if (parentNode is ListNode
79                      && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode.Parent)])
80                      && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
81                 node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode);
82         }
83
84         public void Visit(RootNode node, INode parentNode)
85         {
86         }
87
88         public void Visit(ListNode node, INode parentNode)
89         {
90         }
91
92         public bool SkipChildren(INode node, INode parentNode)
93         {
94             var enode = node as ElementNode;
95             if (enode is null)
96                 return false;
97             if (parentNode is IElementNode
98                                 && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType)
99                                 && typeof(ResourceDictionary).IsAssignableFrom(parentType)
100                 && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey))
101                 return true;
102             if (parentNode is ListNode
103                 && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode.Parent)])
104                 && !((IElementNode)parentNode.Parent).Properties.ContainsKey(XmlName.xKey))
105                 return true;
106             return false;
107         }
108     }
109 }