diff --git a/Perspex.sln b/Perspex.sln index 4952c2b257..93b8598998 100644 --- a/Perspex.sln +++ b/Perspex.sln @@ -90,6 +90,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Cairo", "src\Gtk\Pe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.ReactiveUI", "src\Perspex.ReactiveUI\Perspex.ReactiveUI.csproj", "{6417B24E-49C2-4985-8DB2-3AB9D898EC91}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Markup.Xaml.Schema.Generator", "src\Markup\Perspex.Markup.Xaml.Schema.Generator\Perspex.Markup.Xaml.Schema.Generator.csproj", "{5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -212,6 +214,10 @@ Global {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Debug|Any CPU.Build.0 = Debug|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.ActiveCfg = Release|Any CPU {6417B24E-49C2-4985-8DB2-3AB9D898EC91}.Release|Any CPU.Build.0 = Release|Any CPU + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -234,5 +240,6 @@ Global {78CAFE33-DBEB-4132-8A28-81CFE8A4933C} = {9B9E3891-2366-4253-A952-D08BCEB71098} {54F237D5-A70A-4752-9656-0C70B1A7B047} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} {FB05AC90-89BA-4F2F-A924-F37875FB547C} = {B9894058-278A-46B5-B6ED-AD613FCC03B3} + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749} = {8B6A8209-894F-4BA1-B880-965FD453982C} EndGlobalSection EndGlobal diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/.gitignore b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/.gitignore new file mode 100644 index 0000000000..61dbb11f6b --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/.gitignore @@ -0,0 +1 @@ +*.xsd diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/App.config b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/App.config new file mode 100644 index 0000000000..8324aa6ff1 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/CSharpClassTest.vstemplate b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/CSharpClassTest.vstemplate new file mode 100644 index 0000000000..4fe258b002 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/CSharpClassTest.vstemplate @@ -0,0 +1,22 @@ + + + + CSharpClassTemplate.cs + CSharpClassTemplate + Example template for VsTemplate Designer + CSharp + 10 + __TemplateIcon.ico + + + + + Microsoft.CSharp + + + System + + + Class1.cs + + \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Perspex.Markup.Xaml.Schema.Generator.csproj b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Perspex.Markup.Xaml.Schema.Generator.csproj new file mode 100644 index 0000000000..f176fba6f8 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Perspex.Markup.Xaml.Schema.Generator.csproj @@ -0,0 +1,112 @@ + + + + + Debug + AnyCPU + {5658F6CE-8F9D-4A8F-AF8F-0A2D0B7A2749} + Exe + Properties + Perspex.Markup.Xaml.Schema.Generator + Perspex.Markup.Xaml.Schema.Generator + v4.6 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + Designer + + + + + {d211e587-d8bc-45b9-95a4-f297c8fa5200} + Perspex.Animation + + + {799a7bb5-3c2c-48b6-85a7-406a12c420da} + Perspex.Application + + + {b09b78d8-9b26-48b0-9149-d64a2f120f3f} + Perspex.Base + + + {d2221c82-4a25-4583-9b43-d791e3f6820c} + Perspex.Controls + + + {62024b2d-53eb-4638-b26b-85eeaa54866e} + Perspex.Input + + + {42472427-4774-4c81-8aff-9f27b8e31721} + Perspex.Layout + + + {6417b24e-49c2-4985-8db2-3ab9d898ec91} + Perspex.ReactiveUI + + + {eb582467-6abb-43a1-b052-e981ba910e3a} + Perspex.SceneGraph + + + {f1baa01a-f176-4c6a-b39d-5b40bb1b148f} + Perspex.Styling + + + {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f} + Perspex.Themes.Default + + + + + + Designer + MSBuild:Compile + + + + + \ No newline at end of file diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Program.cs b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Program.cs new file mode 100644 index 0000000000..b468ceb04b --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Program.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; + +namespace Perspex.Markup.Xaml.Schema.Generator +{ + public class Program + { + private const string Xs = "http://www.w3.org/2001/XMLSchema"; + + const string Namespace = "https://github.com/grokys/Perspex"; + private static readonly XmlQualifiedName StringType = new XmlQualifiedName("string", Xs); + private const string TypeSuffix = "PerspexType"; + static void Main(string[] args) + { + var outputFile = args.Length > 0 ? args[0] : @"..\..\perspex.xsd"; + + var schema = new XmlSchema() + { + TargetNamespace = Namespace, ElementFormDefault = XmlSchemaForm.Qualified + }; + + var globalChoice = new XmlSchemaChoice(); + schema.Items.Add(new XmlSchemaGroup() {Name = "all", Particle = globalChoice}); + var declared = new HashSet(); + foreach (var dll in + Directory.GetFiles(Path.Combine(typeof (Program).Assembly.GetModules()[0].FullyQualifiedName, ".."), + "*.dll")) + { + foreach (var t in Assembly.LoadFrom(dll).GetTypes()) + { + if (typeof (PerspexObject).IsAssignableFrom(t)) + { + if (!declared.Add(t.Name)) + continue; + var ctype = new XmlSchemaComplexType {Name = t.Name + TypeSuffix, IsMixed = true}; + schema.Items.Add(ctype); + var element = new XmlSchemaElement() + { + SchemaTypeName = new XmlQualifiedName(t.Name + TypeSuffix, Namespace), + Name = t.Name + }; + schema.Items.Add(element); + globalChoice.Items.Add(new XmlSchemaElement() + { + RefName = new XmlQualifiedName(element.Name, Namespace) + }); + + var sequence = new XmlSchemaChoice() {MaxOccursString = "unbounded"}; + ctype.Particle = sequence; + var hs = new HashSet(); + foreach (var prop in t.GetProperties()) + { + if (!hs.Add(prop.Name)) + continue; + var propType = prop.PropertyType; + var name = prop.Name; + + ctype.Attributes.Add(new XmlSchemaAttribute() + { + Name = prop.Name, + Use = XmlSchemaUse.Optional, + SchemaTypeName = ResolveTypeName(propType, true) + }); + var subElement = new XmlSchemaElement() + { + // ReSharper disable once PossibleNullReferenceException + Name = prop.DeclaringType.Name + "." + prop.Name, + SchemaTypeName = ResolveTypeName(propType, false), + MaxOccurs = 1, + MinOccurs = 0 + }; + sequence.Items.Add(subElement); + } + sequence.Items.Add(new XmlSchemaGroupRef() {RefName = new XmlQualifiedName("all", Namespace)}); + } + if (t.IsEnum) + { + if (!declared.Add(t.Name)) + continue; + + const string EnumTypeSuffix = "Enumeration"; + + var restriction = new XmlSchemaSimpleTypeRestriction() {BaseTypeName = StringType}; + foreach (var name in Enum.GetNames(t)) + restriction.Facets.Add(new XmlSchemaEnumerationFacet() + { + Value = name + }); + schema.Items.Add(new XmlSchemaSimpleType + { + Content = restriction, + Name = t.Name + TypeSuffix + EnumTypeSuffix + }); + + schema.Items.Add(new XmlSchemaSimpleType() + { + Name = t.Name + TypeSuffix, + + Content = new XmlSchemaSimpleTypeUnion() + { + MemberTypes =new[] + { + new XmlQualifiedName(t.Name + TypeSuffix + EnumTypeSuffix, Namespace), + new XmlQualifiedName("bindingPattern", Namespace), + } + } + }); + + } + } + } + + schema.Items.Add(new XmlSchemaSimpleType() + { + Name = "bindingPattern", + Content = new XmlSchemaSimpleTypeRestriction() + { + BaseTypeName = StringType, + Facets = + { + new XmlSchemaPatternFacet() + { + Value = "^{.*}$" + } + } + } + }); + + + var schemaSet = new XmlSchemaSet(); + schemaSet.ValidationEventHandler += ValidationCallback; + schemaSet.Add(schema); + schemaSet.Compile(); + + foreach (XmlSchema s in schemaSet.Schemas()) + schema = s; + + using (var fs = new StreamWriter(outputFile)) + schema.Write(fs); + } + + private static XmlQualifiedName ResolveTypeName(Type type, bool attribute) + { + if ((!attribute && typeof (PerspexObject).IsAssignableFrom(type)) || (attribute && type.IsEnum)) + return new XmlQualifiedName(type.Name + TypeSuffix, Namespace); + + return StringType; + } + + + private static void ValidationCallback(object sender, ValidationEventArgs e) + { + Console.WriteLine(e.Message); + Environment.Exit(1); + } + } +} diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Properties/AssemblyInfo.cs b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c9174039ce --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Perspex.Markup.Xaml.Schema.Generator")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Perspex.Markup.Xaml.Schema.Generator")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5658f6ce-8f9d-4a8f-af8f-0a2d0b7a2749")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Test.xml b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Test.xml new file mode 100644 index 0000000000..33a5d99985 --- /dev/null +++ b/src/Markup/Perspex.Markup.Xaml.Schema.Generator/Test.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file