2005-08-31 Iain McCoy <iain@mccoy.id.au>
[mono.git] / mcs / class / PresentationFramework / System.Windows.Serialization / Parser.cs
1 //
2 // Parser.cs - instantiate an object according to a Xaml file
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
44                 public static object LoadXml(Stream s)
45                 {
46                         return LoadXml(new XmlTextReader(s));
47                 }
48                 // TODO: this should take a XmlReader in order to be same as MSFT
49                 public static object LoadXml(XmlTextReader reader)
50                 {
51                         Consumer r = new Consumer();
52                         r.crunch(reader);
53                         return r.instance;
54                 }
55                 private class Consumer : ParserConsumerBase {
56                 
57                         public object instance;
58                         ArrayList objects = new ArrayList();
59
60                         Hashtable keys = new Hashtable();
61
62                         public override void CreateTopLevel(Type parent, string className)
63                         {
64                                 instance = Activator.CreateInstance(parent);
65                                 push(instance);
66                         }
67
68                         public override void CreateObject(Type type, string varName, string key)
69                         {
70                                 Object o = Activator.CreateInstance(type);
71                                 ((IAddChild)peek()).AddChild(o);
72
73                                 if (key != null)
74                                         keys[key] = o;
75                                 push(o);
76                         }
77
78                         public override void CreateProperty(PropertyInfo property)
79                         {
80                                 push(property);
81                         }
82
83                         // top of stack is a reference to an object
84                         // pushes a reference to the event
85                         public override void CreateEvent(EventInfo evt)
86                         {
87                                 push(evt);
88                         }
89
90                         public override void CreateDependencyProperty(Type attachedTo, string propertyName, Type propertyType)
91                         {
92                                 push(attachedTo);
93                                 push(propertyName);
94                         }
95
96                         public override void EndDependencyProperty()
97                         {
98                                 object value = pop();
99                                 string propertyName = (string)pop();
100                                 Type attachedTo = (Type)pop();
101
102
103                                 MethodInfo setter = attachedTo.GetMethod("Set" + propertyName);
104                                 setter.Invoke(null, new object[] { peek(), value});
105                         }
106
107                         public override void CreateObjectText(string text)
108                         {
109                                 ((IAddChild)peek()).AddText(text);
110                         }
111
112                         // top of stack is reference to an event
113                         public override void CreateEventDelegate(string functionName, Type eventDelegateType)
114                         {
115                                 EventInfo e = (EventInfo)peek();
116                                 object o = peek(1);
117                                 e.AddEventHandler(o, Delegate.CreateDelegate(o.GetType(), o, functionName));
118                         }
119                         // top of stack is reference to a property
120                         public override void CreatePropertyDelegate(string functionName, Type propertyType)
121                         {
122                                 PropertyInfo p = (PropertyInfo)peek();
123                                 object o = peek(1);
124                                 p.SetValue(o, Delegate.CreateDelegate(o.GetType(), o, functionName), null);
125                         }
126
127                         public override void CreatePropertyText(string text, Type propertyType)
128                         {
129                                 object value = convertText(propertyType, text);
130                                 storeToProperty(value);
131                         }
132                         
133                         public override void CreatePropertyObject(Type type, string name, string key)
134                         {
135                                 object value = Activator.CreateInstance(type);
136                                 Debug.WriteLine("ObjectWriter CREATING PROPERTY OBJECT of type" + type);
137                                 if (key != null)
138                                         keys[key] = value;
139                                 push(value);
140                         }
141
142                         public override void CreatePropertyReference(string key)
143                         {
144                                 push(keys[key]);
145                         }
146                         public override void CreateDependencyPropertyReference(string key)
147                         {
148                                 push(keys[key]);
149                         }
150                         public override void EndPropertyObject(Type destType)
151                         {
152                                 object value = convertPropertyObjectValue(destType, pop());
153                                 storeToProperty(value);
154                         }
155                         private void storeToProperty(object value)
156                         {
157                                 PropertyInfo p = (PropertyInfo)peek();
158                                 object o = peek(1);
159                                 p.SetValue(o, value, null);
160                         }
161                         private object convertPropertyObjectValue(Type destType, object value)
162                         {
163                                 Type sourceType = value.GetType();
164                                 if (destType != sourceType && !sourceType.IsSubclassOf(destType)) {
165                                         TypeConverter tc = TypeDescriptor.GetConverter(sourceType);
166                                         value = tc.ConvertTo(value, destType);
167                                 }
168                                 return value;
169                         }
170                         private object convertText(Type propertyType, string text)
171                         {
172                                 if (propertyType != typeof(string)) {
173                                         TypeConverter tc = TypeDescriptor.GetConverter(propertyType);
174                                         return tc.ConvertFromString(text);
175                                 } else {
176                                         return text;
177                                 }
178                         }
179
180                         public override void CreateDependencyPropertyObject(Type type, string name, string key)
181                         {
182                                 CreatePropertyObject(type, name, key);
183                         }
184                         public override void EndDependencyPropertyObject(Type finalType)
185                         {
186                                 push(convertPropertyObjectValue(finalType, pop()));
187                         }
188
189                         // top of stack is reference to an attached property
190                         public override void CreateDependencyPropertyText(string text, Type propertyType)
191                         {
192                                 object value = convertText(propertyType, text);
193                                 push(value);
194                         }
195                         
196                         public override void EndObject()
197                         {
198                                 pop();
199                         }
200
201                         public override void EndProperty()
202                         {
203                                 pop();
204                         }
205                         
206                         public override void EndEvent()
207                         {
208                                 pop();
209                         }
210
211                         public override void Finish()
212                         {
213                         }
214
215                         public override void CreateCode(string code)
216                         {
217                                 throw new NotImplementedException();
218                         }
219
220                         private object peek()
221                         {
222                                 return peek(0);
223                         }
224                         private object peek(int i)
225                         {
226                                 return objects[objects.Count - 1 - i];
227                         }
228                         private object pop()
229                         {
230                                 object v = objects[objects.Count - 1];
231                                 objects.RemoveAt(objects.Count - 1);
232                                 Debug.WriteLine("ObjectWriter: POPPING");
233                                 return v;
234                         }
235                         private void push(object v)
236                         {
237                                 Debug.WriteLine("ObjectWriter: PUSHING " + v);
238                                 objects.Add(v);
239                         }
240                 }
241         }
242 }