2005-08-26 Iain McCoy <iain@mccoy.id.au>
[mono.git] /
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 System.Windows.Serialization;
39 using System.Xml;
40
41 namespace Mono.Windows.Serialization {
42         public class ObjectWriter {
43                 public object instance;
44                 ArrayList objects = new ArrayList();
45
46                 public static object Parse(XmlTextReader reader)
47                 {
48                         ObjectWriter ow = new ObjectWriter(reader);
49                         return ow.instance;
50                 }
51                 private ObjectWriter(XmlTextReader reader)
52                 {
53                         XamlParser p = new XamlParser(reader);
54                         XamlNode n;
55                         while (true) {
56                                 n = p.GetNextNode();
57                                 if (n == null)
58                                         break;
59                                 Debug.WriteLine("ObjectWriter: INCOMING " + n.GetType());
60                                 if (n is XamlDocumentStartNode) {
61                                         Debug.WriteLine("ObjectWriter: document begins");
62                                         // do nothing
63                                 } else if (n is XamlElementStartNode && n.Depth == 0) {
64                                         Debug.WriteLine("ObjectWriter: element begins as top-level");
65                                         CreateTopLevel(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
66                                 } else if (n is XamlElementStartNode && peek() is PropertyInfo) {
67                                         Debug.WriteLine("ObjectWriter: element begins as property value");
68                                         CreatePropertyObject(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
69                                 } else if (n is XamlElementStartNode) {
70                                         Debug.WriteLine("ObjectWriter: element begins");
71                                         CreateObject(((XamlElementStartNode)n).ElementType, ((XamlElementStartNode)n).name);
72                                 } else if (n is XamlPropertyNode && ((XamlPropertyNode)n).PropInfo != null) {
73                                         Debug.WriteLine("ObjectWriter: normal property begins");
74                                         CreateProperty(((XamlPropertyNode)n).PropInfo);
75                                 } else if (n is XamlPropertyNode && ((XamlPropertyNode)n).DP != null) {
76                                         Debug.WriteLine("ObjectWriter: dependency property begins");
77                                         DependencyProperty dp = ((XamlPropertyNode)n).DP;
78                                         Type typeAttachedTo = dp.OwnerType;
79                                         string propertyName = ((XamlPropertyNode)n).PropertyName;
80                                         
81                                         CreateDependencyProperty(typeAttachedTo, propertyName, dp.PropertyType);
82                                 } else if (n is XamlClrEventNode) {
83                                         Debug.WriteLine("ObjectWriter: event");
84                                         CreateEvent((EventInfo)((XamlClrEventNode)n).EventMember);
85                                         CreateEventDelegate(((XamlClrEventNode)n).Value, ((EventInfo)((XamlClrEventNode)n).EventMember).EventHandlerType);
86                                         EndEvent();
87
88                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.Object){
89                                         Debug.WriteLine("ObjectWriter: text for object");
90                                         CreateObjectText(((XamlTextNode)n).TextContent);
91                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.Property){
92                                         Debug.WriteLine("ObjectWriter: text for property");
93                                         Debug.WriteLine("THINGTYPE = " + peek().GetType());
94                                         CreatePropertyText(((XamlTextNode)n).TextContent, ((PropertyInfo)peek()).PropertyType);
95                                         EndProperty();
96                                 } else if (n is XamlTextNode && ((XamlTextNode)n).mode == XamlParseMode.DependencyProperty){
97                                         Debug.WriteLine("ObjectWriter: text for dependency property");
98                                         string propertyName = (string)peek();
99                                         Type attachedTo = (Type)peek(1);
100                                         CreateDependencyPropertyText(((XamlTextNode)n).TextContent, ((DependencyProperty)attachedTo.GetField(propertyName + "Property").GetValue(null)).PropertyType);
101                                         EndDependencyProperty();
102                                 } else if (n is XamlPropertyComplexEndNode) {
103                                         Debug.WriteLine("ObjectWriter: end complex property");
104                                         Debug.WriteLine("ObjectWriter: final type is " + ((XamlPropertyComplexEndNode)n).finalType);
105                                         EndPropertyObject(((XamlPropertyComplexEndNode)n).finalType);
106                                         EndProperty();
107                                 } else if (n is XamlElementEndNode) {
108                                         Debug.WriteLine("ObjectWriter: end element");
109                                         if (!((XamlElementEndNode)n).propertyObject)
110                                                 EndObject();
111                                 } else if (n is XamlDocumentEndNode) {
112                                         Debug.WriteLine("ObjectWriter: end document");
113                                         Finish();
114                                 } else {
115                                         throw new Exception("Unknown node " + n.GetType());
116                                 }
117                         }
118                 }
119
120         
121                 public void CreateTopLevel(Type parent, string className)
122                 {
123                         instance = Activator.CreateInstance(parent);
124                         push(instance);
125                 }
126
127                 public void CreateObject(Type type, string varName)
128                 {
129                         Object o = Activator.CreateInstance(type);
130                         ((IAddChild)peek()).AddChild(o);
131                         push(o);
132                 }
133
134                 public void CreateProperty(PropertyInfo property)
135                 {
136                         push(property);
137                 }
138
139                 // top of stack is a reference to an object
140                 // pushes a reference to the event
141                 public void CreateEvent(EventInfo evt)
142                 {
143                         push(evt);
144                 }
145
146                 public void CreateDependencyProperty(Type attachedTo, string propertyName, Type propertyType)
147                 {
148                         push(attachedTo);
149                         push(propertyName);
150                 }
151
152                 public void EndDependencyProperty()
153                 {
154                         object value = pop();
155                         string propertyName = (string)pop();
156                         Type attachedTo = (Type)pop();
157
158                         MethodInfo setter = attachedTo.GetMethod("Set" + propertyName);
159                         setter.Invoke(null, new object[] { peek(), value});
160                 }
161
162                 public void CreateObjectText(string text)
163                 {
164                         ((IAddChild)peek()).AddText(text);
165                 }
166
167                 // top of stack is reference to an event
168                 public void CreateEventDelegate(string functionName, Type eventDelegateType)
169                 {
170                         EventInfo e = (EventInfo)peek();
171                         object o = peek(1);
172                         e.AddEventHandler(o, Delegate.CreateDelegate(o.GetType(), o, functionName));
173                 }
174                 // top of stack is reference to a property
175                 public void CreatePropertyDelegate(string functionName, Type propertyType)
176                 {
177                         PropertyInfo p = (PropertyInfo)peek();
178                         object o = peek(1);
179                         p.SetValue(o, Delegate.CreateDelegate(o.GetType(), o, functionName), null);
180                 }
181
182                 public void CreatePropertyText(string text, Type propertyType)
183                 {
184                         object value = text;
185                         if (propertyType != typeof(string)) {
186                                 TypeConverter tc = TypeDescriptor.GetConverter(propertyType);
187                                 value = tc.ConvertFromString(text);
188                         }
189                         PropertyInfo p = (PropertyInfo)peek();
190                         object o = peek(1);
191                         p.SetValue(o, value, null);
192                 }
193                 
194                 public void CreatePropertyObject(Type type, string name)
195                 {
196                         object value = Activator.CreateInstance(type);
197                         Debug.WriteLine("ObjectWriter CREATING PROPERTY OBJECT of type" + type);
198                         push(value);
199                 }
200                 public void EndPropertyObject(Type destType)
201                 {
202                         object value = pop();
203                         Type sourceType = value.GetType();
204                         Debug.WriteLine("ObjectWriter: EndPropertyObject has a " + value + value.GetType() + ", needs a " + destType);
205                         if (destType != sourceType && !sourceType.IsSubclassOf(destType)) {
206                                 TypeConverter tc = TypeDescriptor.GetConverter(destType);
207                                 value = tc.ConvertFrom(value);
208                         }
209                         PropertyInfo p = (PropertyInfo)peek();
210                         object o = peek(1);
211                         p.SetValue(o, value, null);
212                 }
213
214                 // top of stack is reference to an attached property
215                 public void CreateDependencyPropertyText(string text, Type propertyType)
216                 {
217                         object value = text;
218                         if (propertyType != typeof(string)) {
219                                 TypeConverter tc = TypeDescriptor.GetConverter(propertyType);
220                                 value = tc.ConvertFromString(text);
221                         }
222                         push(value);
223                 }
224                 
225                 public void EndObject()
226                 {
227                         pop();
228                 }
229
230                 public void EndProperty()
231                 {
232                         pop();
233                 }
234                 
235                 public void EndEvent()
236                 {
237                         pop();
238                 }
239
240                 public void Finish()
241                 {
242                 }
243
244                 public void CreateCode(string code)
245                 {
246                         throw new NotImplementedException();
247                 }
248
249                 private object peek()
250                 {
251                         return peek(0);
252                 }
253                 private object peek(int i)
254                 {
255                         return objects[objects.Count - 1 - i];
256                 }
257                 private object pop()
258                 {
259                         object v = objects[objects.Count - 1];
260                         objects.RemoveAt(objects.Count - 1);
261                         Debug.WriteLine("ObjectWriter POPPING");
262                         return v;
263                 }
264                 private void push(object v)
265                 {
266                         Debug.WriteLine("ObjectWriter PUSHING " + v);
267                         objects.Add(v);
268                 }
269         }
270 }