2005-08-26 Iain McCoy <iain@mccoy.id.au>
[mono.git] / mcs / class / PresentationFramework / System.Windows.Serialization / Parser.cs
1 //
2 // CodeWriter.cs
3 //
4 // Author:
5 //   Iain McCoy (iain@mccoy.id.au)
6 //
7 // (C) 2005 Iain McCoy
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System;
30 using System.Reflection;
31 using System.IO;
32 using System.Collections;
33 using System.CodeDom;
34 using System.CodeDom.Compiler;
35 using System.ComponentModel;
36 using System.Diagnostics;
37 using System.Windows;
38 using Mono.Windows.Serialization;
39 using System.Xml;
40
41 namespace System.Windows.Serialization {
42         public class Parser {
43                 private object instance;
44                 ArrayList objects = new ArrayList();
45
46                 public static object LoadXml(Stream s)
47                 {
48                         return LoadXml(new XmlTextReader(s));
49                 }
50                 // TODO: this should take a XmlReader in order to be same as MSFT
51                 public static object LoadXml(XmlTextReader reader)
52                 {
53                         Parser r = new Parser(reader);
54                         return r.instance;
55                 }
56                 private Parser(XmlTextReader reader)
57                 {
58                         XamlParser p = new XamlParser(reader);
59                         XamlNode n;
60                         while (true) {
61                                 n = p.GetNextNode();
62                                 if (n == null)
63                                         break;
64                                 Debug.WriteLine("ObjectWriter: INCOMING " + n.GetType());
65                                 if (n is XamlDocumentStartNode) {
66                                         Debug.WriteLine("ObjectWriter: document begins");
67                                         // do nothing
68                                 } else if (n is XamlElementStartNode && n.Depth == 0) {
69                                         Debug.WriteLine("ObjectWriter: element begins as top-level");
70                                         CreateTopLevel(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
71                                 } else if (n is XamlElementStartNode && peek() is PropertyInfo) {
72                                         Debug.WriteLine("ObjectWriter: element begins as property value");
73                                         CreatePropertyObject(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
74                                 } else if (n is XamlElementStartNode) {
75                                         Debug.WriteLine("ObjectWriter: element begins");
76                                         CreateObject(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
77                                 } else if (n is XamlPropertyNode && ((XamlPropertyNode)n).PropInfo != null) {
78                                         Debug.WriteLine("ObjectWriter: normal property begins");
79                                         CreateProperty(((XamlPropertyNode)n).PropInfo);
80                                 } else if (n is XamlPropertyNode && ((XamlPropertyNode)n).DP != null) {
81                                         Debug.WriteLine("ObjectWriter: dependency property begins");
82                                         DependencyProperty dp = ((XamlPropertyNode)n).DP;
83                                         Type typeAttachedTo = dp.OwnerType;
84                                         string propertyName = ((XamlPropertyNode)n).PropertyName;
85                                         
86                                         CreateDependencyProperty(typeAttachedTo, propertyName, dp.PropertyType);
87                                 } else if (n is XamlClrEventNode) {
88                                         Debug.WriteLine("ObjectWriter: event");
89                                         CreateEvent((EventInfo)((XamlClrEventNode)n).EventMember);
90                                         CreateEventDelegate(((XamlClrEventNode)n).Value, ((EventInfo)((XamlClrEventNode)n).EventMember).EventHandlerType);
91                                         EndEvent();
92
93                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.Object){
94                                         Debug.WriteLine("ObjectWriter: text for object");
95                                         CreateObjectText(((XamlTextNode)n).TextContent);
96                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.Property){
97                                         Debug.WriteLine("ObjectWriter: text for property");
98                                         Debug.WriteLine("THINGTYPE = " + peek().GetType());
99                                         CreatePropertyText(((XamlTextNode)n).TextContent, ((PropertyInfo)peek()).PropertyType);
100                                         EndProperty();
101                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.DependencyProperty){
102                                         Debug.WriteLine("ObjectWriter: text for dependency property");
103                                         string propertyName = (string)peek();
104                                         Type attachedTo = (Type)peek(1);
105                                         CreateDependencyPropertyText(((XamlTextNode)n).TextContent, ((DependencyProperty)attachedTo.GetField(propertyName + "Property").GetValue(null)).PropertyType);
106                                         EndDependencyProperty();
107                                 } else if (n is XamlPropertyComplexEndNode) {
108                                         Debug.WriteLine("ObjectWriter: end complex property");
109                                         Debug.WriteLine("ObjectWriter: final type is " + ((XamlPropertyComplexEndNode)n).finalType);
110                                         EndPropertyObject(((XamlPropertyComplexEndNode)n).finalType);
111                                         EndProperty();
112                                 } else if (n is XamlElementEndNode) {
113                                         Debug.WriteLine("ObjectWriter: end element");
114                                         if (!((XamlElementEndNode)n).propertyObject)
115                                                 EndObject();
116                                 } else if (n is XamlDocumentEndNode) {
117                                         Debug.WriteLine("ObjectWriter: end document");
118                                         Finish();
119                                 } else {
120                                         throw new Exception("Unknown node " + n.GetType());
121                                 }
122                         }
123                 }
124
125         
126                 public void CreateTopLevel(Type parent, string className)
127                 {
128                         instance = Activator.CreateInstance(parent);
129                         push(instance);
130                 }
131
132                 public void CreateObject(Type type, string varName)
133                 {
134                         Object o = Activator.CreateInstance(type);
135                         ((IAddChild)peek()).AddChild(o);
136                         push(o);
137                 }
138
139                 public void CreateProperty(PropertyInfo property)
140                 {
141                         push(property);
142                 }
143
144                 // top of stack is a reference to an object
145                 // pushes a reference to the event
146                 public void CreateEvent(EventInfo evt)
147                 {
148                         push(evt);
149                 }
150
151                 public void CreateDependencyProperty(Type attachedTo, string propertyName, Type propertyType)
152                 {
153                         push(attachedTo);
154                         push(propertyName);
155                 }
156
157                 public void EndDependencyProperty()
158                 {
159                         object value = pop();
160                         string propertyName = (string)pop();
161                         Type attachedTo = (Type)pop();
162
163                         MethodInfo setter = attachedTo.GetMethod("Set" + propertyName);
164                         setter.Invoke(null, new object[] { peek(), value});
165                 }
166
167                 public void CreateObjectText(string text)
168                 {
169                         ((IAddChild)peek()).AddText(text);
170                 }
171
172                 // top of stack is reference to an event
173                 public void CreateEventDelegate(string functionName, Type eventDelegateType)
174                 {
175                         EventInfo e = (EventInfo)peek();
176                         object o = peek(1);
177                         e.AddEventHandler(o, Delegate.CreateDelegate(o.GetType(), o, functionName));
178                 }
179                 // top of stack is reference to a property
180                 public void CreatePropertyDelegate(string functionName, Type propertyType)
181                 {
182                         PropertyInfo p = (PropertyInfo)peek();
183                         object o = peek(1);
184                         p.SetValue(o, Delegate.CreateDelegate(o.GetType(), o, functionName), null);
185                 }
186
187                 public void CreatePropertyText(string text, Type propertyType)
188                 {
189                         object value = text;
190                         if (propertyType != typeof(string)) {
191                                 TypeConverter tc = TypeDescriptor.GetConverter(propertyType);
192                                 value = tc.ConvertFromString(text);
193                         }
194                         PropertyInfo p = (PropertyInfo)peek();
195                         object o = peek(1);
196                         p.SetValue(o, value, null);
197                 }
198                 
199                 public void CreatePropertyObject(Type type, string name)
200                 {
201                         object value = Activator.CreateInstance(type);
202                         Debug.WriteLine("ObjectWriter CREATING PROPERTY OBJECT of type" + type);
203                         push(value);
204                 }
205                 public void EndPropertyObject(Type destType)
206                 {
207                         object value = pop();
208                         Type sourceType = value.GetType();
209                         Debug.WriteLine("ObjectWriter: EndPropertyObject has a " + value + value.GetType() + ", needs a " + destType);
210                         if (destType != sourceType && !sourceType.IsSubclassOf(destType)) {
211                                 TypeConverter tc = TypeDescriptor.GetConverter(destType);
212                                 value = tc.ConvertFrom(value);
213                         }
214                         PropertyInfo p = (PropertyInfo)peek();
215                         object o = peek(1);
216                         p.SetValue(o, value, null);
217                 }
218
219                 // top of stack is reference to an attached property
220                 public void CreateDependencyPropertyText(string text, Type propertyType)
221                 {
222                         object value = text;
223                         if (propertyType != typeof(string)) {
224                                 TypeConverter tc = TypeDescriptor.GetConverter(propertyType);
225                                 value = tc.ConvertFromString(text);
226                         }
227                         push(value);
228                 }
229                 
230                 public void EndObject()
231                 {
232                         pop();
233                 }
234
235                 public void EndProperty()
236                 {
237                         pop();
238                 }
239                 
240                 public void EndEvent()
241                 {
242                         pop();
243                 }
244
245                 public void Finish()
246                 {
247                 }
248
249                 public void CreateCode(string code)
250                 {
251                         throw new NotImplementedException();
252                 }
253
254                 private object peek()
255                 {
256                         return peek(0);
257                 }
258                 private object peek(int i)
259                 {
260                         return objects[objects.Count - 1 - i];
261                 }
262                 private object pop()
263                 {
264                         object v = objects[objects.Count - 1];
265                         objects.RemoveAt(objects.Count - 1);
266                         Debug.WriteLine("ObjectWriter POPPING");
267                         return v;
268                 }
269                 private void push(object v)
270                 {
271                         Debug.WriteLine("ObjectWriter PUSHING " + v);
272                         objects.Add(v);
273                 }
274         }
275 }