Implemented IAmbientProvider support in XamlObjectWriter. Fixed bug #682102.
[mono.git] / mcs / class / System.Xaml / System.Xaml / ValueSerializerContext.cs
1 //
2 // Copyright (C) 2010 Novell Inc. http://novell.com
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23
24 using System;
25 using System.Collections.Generic;
26 using System.ComponentModel;
27 using System.IO;
28 using System.Linq;
29 using System.Reflection;
30 using System.Text;
31 using System.Windows.Markup;
32 using System.Xaml;
33 using System.Xaml.Schema;
34 using System.Xml;
35
36 namespace System.Xaml
37 {
38         internal class ValueSerializerContext : IValueSerializerContext, IXamlSchemaContextProvider
39         {
40                 XamlNameResolver name_resolver = new XamlNameResolver ();
41                 XamlTypeResolver type_resolver;
42                 NamespaceResolver namespace_resolver;
43                 PrefixLookup prefix_lookup;
44                 XamlSchemaContext sctx;
45                 IAmbientProvider ambient_provider;
46
47                 public ValueSerializerContext (PrefixLookup prefixLookup, XamlSchemaContext schemaContext, IAmbientProvider ambientProvider)
48                 {
49                         if (prefixLookup == null)
50                                 throw new ArgumentNullException ("prefixLookup");
51                         if (schemaContext == null)
52                                 throw new ArgumentNullException ("schemaContext");
53                         prefix_lookup = prefixLookup;
54                         namespace_resolver = new NamespaceResolver (prefix_lookup.Namespaces);
55                         type_resolver = new XamlTypeResolver (namespace_resolver, schemaContext);
56                         sctx = schemaContext;
57                         ambient_provider = ambientProvider;
58                 }
59
60                 public object GetService (Type serviceType)
61                 {
62                         if (serviceType == typeof (INamespacePrefixLookup))
63                                 return prefix_lookup;
64                         if (serviceType == typeof (IXamlNamespaceResolver))
65                                 return namespace_resolver;
66                         if (serviceType == typeof (IXamlNameResolver))
67                                 return name_resolver;
68                         if (serviceType == typeof (IXamlNameProvider))
69                                 return name_resolver;
70                         if (serviceType == typeof (IXamlTypeResolver))
71                                 return type_resolver;
72                         if (serviceType == typeof (IAmbientProvider))
73                                 return ambient_provider;
74                         if (serviceType == typeof (IXamlSchemaContextProvider))
75                                 return this;
76                         return null;
77                 }
78                 
79                 XamlSchemaContext IXamlSchemaContextProvider.SchemaContext {
80                         get { return sctx; }
81                 }
82                 
83                 public IContainer Container {
84                         get { throw new NotImplementedException (); }
85                 }
86                 public object Instance {
87                         get { throw new NotImplementedException (); }
88                 }
89                 public PropertyDescriptor PropertyDescriptor {
90                         get { throw new NotImplementedException (); }
91                 }
92                 public void OnComponentChanged ()
93                 {
94                         throw new NotImplementedException ();
95                 }
96                 public bool OnComponentChanging ()
97                 {
98                         throw new NotImplementedException ();
99                 }
100                 public ValueSerializer GetValueSerializerFor (PropertyDescriptor descriptor)
101                 {
102                         throw new NotImplementedException ();
103                 }
104                 public ValueSerializer GetValueSerializerFor (Type type)
105                 {
106                         throw new NotImplementedException ();
107                 }
108         }
109
110         internal class XamlTypeResolver : IXamlTypeResolver
111         {
112                 NamespaceResolver ns_resolver;
113                 XamlSchemaContext schema_context;
114
115                 public XamlTypeResolver (NamespaceResolver namespaceResolver, XamlSchemaContext schemaContext)
116                 {
117                         ns_resolver = namespaceResolver;
118                         schema_context = schemaContext;
119                 }
120
121                 public Type Resolve (string typeName)
122                 {
123                         var tn = XamlTypeName.Parse (typeName, ns_resolver);
124                         var xt = schema_context.GetXamlType (tn);
125                         return xt != null ? xt.UnderlyingType : null;
126                 }
127         }
128
129         internal class NamespaceResolver : IXamlNamespaceResolver
130         {
131                 public NamespaceResolver (IList<NamespaceDeclaration> source)
132                 {
133                         this.source = source;
134                 }
135         
136                 IList<NamespaceDeclaration> source;
137         
138                 public string GetNamespace (string prefix)
139                 {
140                         foreach (var nsd in source)
141                                 if (nsd.Prefix == prefix)
142                                         return nsd.Namespace;
143                         return null;
144                 }
145         
146                 public IEnumerable<NamespaceDeclaration> GetNamespacePrefixes ()
147                 {
148                         return source;
149                 }
150         }
151
152         internal class AmbientProvider : IAmbientProvider
153         {
154                 List<AmbientPropertyValue> values = new List<AmbientPropertyValue> ();
155                 Stack<AmbientPropertyValue> live_stack = new Stack<AmbientPropertyValue> ();
156
157                 public void Push (AmbientPropertyValue v)
158                 {
159                         live_stack.Push (v);
160                         values.Add (v);
161                 }
162
163                 public void Pop ()
164                 {
165                         live_stack.Pop ();
166                 }
167
168                 public IEnumerable<object> GetAllAmbientValues (params XamlType [] types)
169                 {
170                         return GetAllAmbientValues (null, false, types);
171                 }
172                 
173                 public IEnumerable<AmbientPropertyValue> GetAllAmbientValues (IEnumerable<XamlType> ceilingTypes, params XamlMember [] properties)
174                 {
175                         return GetAllAmbientValues (ceilingTypes, false, null, properties);
176                 }
177                 
178                 public IEnumerable<AmbientPropertyValue> GetAllAmbientValues (IEnumerable<XamlType> ceilingTypes, bool searchLiveStackOnly, IEnumerable<XamlType> types, params XamlMember [] properties)
179                 {
180                         return DoGetAllAmbientValues (ceilingTypes, searchLiveStackOnly, types, properties).ToList ();
181                 }
182                 
183                 IEnumerable<AmbientPropertyValue> DoGetAllAmbientValues (IEnumerable<XamlType> ceilingTypes, bool searchLiveStackOnly, IEnumerable<XamlType> types, params XamlMember [] properties)
184                 {
185                         if (searchLiveStackOnly) {
186                                 if (live_stack.Count > 0) {
187                                         // pop, call recursively, then push back.
188                                         var p = live_stack.Pop ();
189                                         if (p.RetrievedProperty != null && ceilingTypes != null && ceilingTypes.Contains (p.RetrievedProperty.Type))
190                                                 yield break;
191                                         if (DoesAmbientPropertyApply (p, types, properties))
192                                                 yield return p;
193
194                                         foreach (var i in GetAllAmbientValues (ceilingTypes, searchLiveStackOnly, types, properties))
195                                                 yield return i;
196
197                                         live_stack.Push (p);
198                                 }
199                         } else {
200                                 // FIXME: does ceilingTypes matter?
201                                 foreach (var p in values)
202                                         if (DoesAmbientPropertyApply (p, types, properties))
203                                                 yield return p;
204                         }
205                 }
206                 
207                 bool DoesAmbientPropertyApply (AmbientPropertyValue p, IEnumerable<XamlType> types, params XamlMember [] properties)
208                 {
209                         if (types == null || !types.Any () || types.Any (xt => xt.UnderlyingType != null && xt.UnderlyingType.IsInstanceOfType (p.Value)))
210                                 if (properties == null || !properties.Any () || properties.Contains (p.RetrievedProperty))
211                                         return true;
212                         return false;
213                 }
214                 
215                 public object GetFirstAmbientValue (params XamlType [] types)
216                 {
217                         foreach (var obj in GetAllAmbientValues (types))
218                                 return obj;
219                         return null;
220                 }
221                 
222                 public AmbientPropertyValue GetFirstAmbientValue (IEnumerable<XamlType> ceilingTypes, params XamlMember [] properties)
223                 {
224                         foreach (var obj in GetAllAmbientValues (ceilingTypes, properties))
225                                 return obj;
226                         return null;
227                 }
228         }
229 }