Add support for MarkupExtension attribute in XamlXmlReader.
authorAtsushi Eno <atsushi@ximian.com>
Fri, 12 Nov 2010 06:11:19 +0000 (15:11 +0900)
committerAtsushi Eno <atsushi@ximian.com>
Fri, 12 Nov 2010 06:11:19 +0000 (15:11 +0900)
mcs/class/System.Xaml/System.Xaml.dll.sources
mcs/class/System.Xaml/System.Xaml/ParsedMarkupExtensionInfo.cs [new file with mode: 0644]
mcs/class/System.Xaml/System.Xaml/XamlXmlReader.cs
mcs/class/System.Xaml/Test/System.Xaml/XamlXmlReaderTest.cs

index c730c8c9d019649608bb27f9adce9e214f4cd6f0..88df06ce20ddbdf31cf3ea2b9dbf5c629fce2e67 100644 (file)
@@ -76,6 +76,7 @@ System.Xaml/IXamlNamespaceResolver.cs
 System.Xaml/IXamlObjectWriterFactory.cs
 System.Xaml/IXamlSchemaContextProvider.cs
 System.Xaml/NamespaceDeclaration.cs
+System.Xaml/ParsedMarkupExtensionInfo.cs
 System.Xaml/PrefixLookup.cs
 System.Xaml/TypeExtensionMethods.cs
 System.Xaml/ValueSerializerContext.cs
diff --git a/mcs/class/System.Xaml/System.Xaml/ParsedMarkupExtensionInfo.cs b/mcs/class/System.Xaml/System.Xaml/ParsedMarkupExtensionInfo.cs
new file mode 100644 (file)
index 0000000..3e322f7
--- /dev/null
@@ -0,0 +1,90 @@
+//
+// Copyright (C) 2010 Novell Inc. http://novell.com
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xaml.Schema;
+
+namespace System.Xaml
+{
+       internal class ParsedMarkupExtensionInfo
+       {
+               Dictionary<XamlMember,object> args = new Dictionary<XamlMember,object> ();
+               public Dictionary<XamlMember,object> Arguments {
+                       get { return args; }
+               }
+       
+               public XamlType Type { get; set; }
+
+               public static ParsedMarkupExtensionInfo Parse (string raw, IXamlNamespaceResolver nsResolver, XamlSchemaContext sctx)
+               {
+                       if (raw == null)
+                               throw new ArgumentNullException ("raw");
+                       if (raw.Length == 0 || raw [0] != '{')
+                               throw Error ("Invalid markup extension attribute. It should begin with '{{', but was {0}", raw);
+                       var ret = new ParsedMarkupExtensionInfo ();
+                       int idx = raw.IndexOf ('}');
+                       if (idx < 0)
+                               throw Error ("Expected '}}' in the markup extension attribute: '{0}'", raw);
+                       raw = raw.Substring (1, idx - 1);
+                       idx = raw.IndexOf (' ');
+                       string name = idx < 0 ? raw : raw.Substring (0, idx);
+
+                       XamlTypeName xtn;
+                       if (!XamlTypeName.TryParse (name, nsResolver, out xtn))
+                               throw Error ("Failed to parse type name '{0}'", name);
+                       var xt = sctx.GetXamlType (xtn);
+                       ret.Type = xt;
+
+                       if (idx < 0)
+                               return ret;
+
+                       string [] vpairs = raw.Substring (idx + 1, raw.Length - idx - 2).Split (',');
+                       List<string> posPrms = null;
+                       foreach (string vpair in vpairs) {
+                               idx = vpair.IndexOf ('=');
+                               // FIXME: unescape string (e.g. comma)
+                               if (idx < 0) {
+                                       if (posPrms == null) {
+                                               posPrms = new List<string> ();
+                                               ret.Arguments.Add (XamlLanguage.PositionalParameters, posPrms);
+                                       }
+                                       posPrms.Add (vpair.Trim ());
+                               } else {
+                                       var key = vpair.Substring (0, idx).Trim ();
+                                       // FIXME: is unknown member always isAttacheable = false?
+                                       var xm = xt.GetMember (key) ?? new XamlMember (key, xt, false);
+                                       ret.Arguments.Add (xm, vpair.Substring (idx + 1).Trim ());
+                               }
+                       }
+                       return ret;
+               }
+       
+               static Exception Error (string format, params object [] args)
+               {
+                       return new XamlParseException (String.Format (format, args));
+               }
+       }
+}
index 5ec8df522be06103d2dc831b42bb2db68067a54d..99160679ecd6f6920776cb60d12163790675c26d 100644 (file)
@@ -512,9 +512,59 @@ namespace System.Xaml
                        }
                        return atts;
                }
+               
+               IEnumerator<KeyValuePair<XamlMember,object>> markup_extension_attr_members;
+               IEnumerator<string> markup_extension_attr_values;
+
+               bool MoveToNextMarkupExtensionAttributeMember ()
+               {
+                       if (markup_extension_attr_members != null) {
+                               switch (node_type) {
+                               case XamlNodeType.StartObject:
+                               case XamlNodeType.EndMember:
+                                       // -> next member or end object
+                                       if (!markup_extension_attr_members.MoveNext ()) {
+                                               node_type = XamlNodeType.EndObject;
+                                       } else {
+                                               current = current_member = markup_extension_attr_members.Current.Key;
+                                               members.Push (current_member);
+                                               node_type = XamlNodeType.StartMember;
+                                       }
+                                       return true;
+                               case XamlNodeType.EndObject:
+                                       types.Pop ();
+                                       markup_extension_attr_members = null;
+                                       return false;
+                               case XamlNodeType.StartMember:
+                                       node_type = XamlNodeType.Value;
+                                       current = markup_extension_attr_members.Current.Value;
+                                       if (current_member == XamlLanguage.PositionalParameters) {
+                                               markup_extension_attr_values = ((List<string>) current).GetEnumerator ();
+                                               goto case XamlNodeType.Value;
+                                       }
+                                       return true;
+                               case XamlNodeType.Value:
+                                       if (markup_extension_attr_values != null) {
+                                               if (markup_extension_attr_values.MoveNext ())
+                                                       current = markup_extension_attr_values.Current;
+                                               else {
+                                                       node_type = XamlNodeType.EndMember;
+                                                       markup_extension_attr_values = null;
+                                               }
+                                       }
+                                       else
+                                               node_type = XamlNodeType.EndMember;
+                                       return true;
+                               }
+                       }
+                       return false;
+               }
 
                bool MoveToNextStoredMember ()
                {
+                       if (MoveToNextMarkupExtensionAttributeMember ())
+                               return true;
+
                        if (stored_member_enumerator != null) {
                                // FIXME: value might have to be deserialized.
                                switch (node_type) {
@@ -528,10 +578,22 @@ namespace System.Xaml
                                        }
                                        break;
                                case XamlNodeType.StartMember:
-                                       // -> Value
-                                       current = stored_member_enumerator.Current.Value;
-                                       node_type = XamlNodeType.Value;
+                                       // -> Value or StartObject (of MarkupExtension)
+                                       var v = stored_member_enumerator.Current.Value;
+                                       current = v;
+                                       // Try markup extension
+                                       // FIXME: is this rule correct?
+                                       if (!String.IsNullOrEmpty (v) && v [0] == '{') {
+                                               var pai = ParsedMarkupExtensionInfo.Parse (v, xaml_namespace_resolver, sctx);
+                                               types.Push (pai.Type);
+                                               current = pai.Type;
+                                               node_type = XamlNodeType.StartObject;
+                                               markup_extension_attr_members = pai.Arguments.GetEnumerator ();
+                                       }
+                                       else
+                                               node_type = XamlNodeType.Value;
                                        return true;
+                               case XamlNodeType.EndObject: // of MarkupExtension
                                case XamlNodeType.Value:
                                        // -> EndMember
                                        current = null;
@@ -566,3 +628,4 @@ namespace System.Xaml
                }
        }
 }
+
index 9de0417b33b0b328c4d0c603072ba37fb4799286..839f1ee4662ccbe51580f431a467be70ded4d382 100755 (executable)
@@ -270,7 +270,6 @@ namespace MonoTests.System.Xaml
                }
 
                [Test]
-               [Category ("NotWorking")]
                public void WriteNullMemberAsObject ()
                {
                        var r = GetReader ("TestClass4.xml");
@@ -278,7 +277,6 @@ namespace MonoTests.System.Xaml
                }
                
                [Test]
-               [Category ("NotWorking")]
                public void StaticMember ()
                {
                        var r = GetReader ("TestClass5.xml");
@@ -310,7 +308,6 @@ namespace MonoTests.System.Xaml
                }
 
                [Test]
-               [Category ("NotWorking")]
                public void Read_NonPrimitive ()
                {
                        var r = GetReader ("NonPrimitive.xml");