bool ProcessFactory(IUxmlFactory factory, FactoryProcessingHelper processingData) { if (!string.IsNullOrEmpty(factory.substituteForTypeName)) { if (!processingData.IsKnownElementType(factory.substituteForTypeName, factory.substituteForTypeNamespace)) { // substituteForTypeName is not yet known. Defer processing to later. return(false); } } processingData.RegisterElementType(factory); return(true); }
void ImportFactoriesFromSource(LibraryTreeItem sourceCategory) { List <IUxmlFactory> deferredFactories = new List <IUxmlFactory>(); FactoryProcessingHelper processingData = new FactoryProcessingHelper(); foreach (var factories in VisualElementFactoryRegistry.factories) { if (factories.Value.Count == 0) { continue; } var factory = factories.Value[0]; if (!ProcessFactory(factory, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing. deferredFactories.Add(factory); } } List <IUxmlFactory> deferredFactoriesCopy; do { deferredFactoriesCopy = new List <IUxmlFactory>(deferredFactories); foreach (var factory in deferredFactoriesCopy) { deferredFactories.Remove(factory); if (!ProcessFactory(factory, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing again. deferredFactories.Add(factory); } } }while (deferredFactoriesCopy.Count > deferredFactories.Count); if (deferredFactories.Count > 0) { Debug.Log("Some factories could not be processed because their base type is missing."); } var categoryStack = new List <LibraryTreeItem>(); foreach (var known in processingData.knownTypes.Values) { var split = known.uxmlNamespace.Split('.'); // Avoid adding our own internal factories (like Package Manager templates). if (!Unsupported.IsDeveloperMode() && split.Count() > 0 && s_NameSpacesToAvoid.Contains(split[0])) { continue; } // Avoid adding UI Builder's own types, even in internal mode. if (split.Count() >= 3 && split[0] == "Unity" && split[1] == "UI" && split[2] == "Builder") { continue; } AddCategoriesToStack(sourceCategory, categoryStack, split); var asset = new VisualElementAsset(known.uxmlQualifiedName); var slots = new Dictionary <string, VisualElement>(); var overrides = new List <TemplateAsset.AttributeOverride>(); var vta = ScriptableObject.CreateInstance <VisualTreeAsset>(); var context = new CreationContext(slots, overrides, vta, null); var newItem = new LibraryTreeItem( known.uxmlName, () => known.Create(asset, context)); if (categoryStack.Count == 0) { sourceCategory.AddChild(newItem); } else { categoryStack.Last().AddChild(newItem); } } }
static XmlQualifiedName AddAttributeTypeToXmlSchema(SchemaInfo schemaInfo, UxmlAttributeDescription description, IUxmlFactory factory, FactoryProcessingHelper processingData) { if (description.name == null) { return(null); } string attrTypeName = factory.uxmlQualifiedName + "_" + description.name + "_" + k_TypeSuffix; string attrTypeNameInBaseElement = factory.substituteForTypeQualifiedName + "_" + description.name + "_" + k_TypeSuffix; FactoryProcessingHelper.AttributeRecord attrRecord; if (processingData.attributeTypeNames.TryGetValue(attrTypeNameInBaseElement, out attrRecord)) { // If restriction != baseElement.restriction, we need to declare a new type. // Note: we do not support attributes having a less restrictive restriction than its base type. if ((description.restriction == null && attrRecord.desc.restriction == null) || (description.restriction != null && description.restriction.Equals(attrRecord.desc.restriction))) { // Register attrTypeName -> attrRecord for potential future derived elements. processingData.attributeTypeNames.Add(attrTypeName, attrRecord); return(attrRecord.name); } } XmlQualifiedName xqn; FactoryProcessingHelper.AttributeRecord attributeRecord; if (description.restriction == null) { // Type is a built-in type. xqn = new XmlQualifiedName(description.type, description.typeNamespace); attributeRecord = new FactoryProcessingHelper.AttributeRecord { name = xqn, desc = description }; processingData.attributeTypeNames.Add(attrTypeName, attributeRecord); return(xqn); } string attrTypeNameForSchema = factory.uxmlName + "_" + description.name + "_" + k_TypeSuffix; xqn = new XmlQualifiedName(attrTypeNameForSchema, schemaInfo.schema.TargetNamespace); XmlSchemaSimpleType simpleType = new XmlSchemaSimpleType(); simpleType.Name = attrTypeNameForSchema; UxmlEnumeration enumRestriction = description.restriction as UxmlEnumeration; if (enumRestriction != null) { XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); simpleType.Content = restriction; restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); foreach (var v in enumRestriction.values) { XmlSchemaEnumerationFacet enumValue = new XmlSchemaEnumerationFacet(); enumValue.Value = v; restriction.Facets.Add(enumValue); } } else { UxmlValueMatches regexRestriction = description.restriction as UxmlValueMatches; if (regexRestriction != null) { XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); simpleType.Content = restriction; restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); XmlSchemaPatternFacet pattern = new XmlSchemaPatternFacet(); pattern.Value = regexRestriction.regex; restriction.Facets.Add(pattern); } else { UxmlValueBounds bounds = description.restriction as UxmlValueBounds; if (bounds != null) { XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction(); simpleType.Content = restriction; restriction.BaseTypeName = new XmlQualifiedName(description.type, description.typeNamespace); XmlSchemaFacet facet; if (bounds.excludeMin) { facet = new XmlSchemaMinExclusiveFacet(); } else { facet = new XmlSchemaMinInclusiveFacet(); } facet.Value = bounds.min; restriction.Facets.Add(facet); if (bounds.excludeMax) { facet = new XmlSchemaMaxExclusiveFacet(); } else { facet = new XmlSchemaMaxInclusiveFacet(); } facet.Value = bounds.max; restriction.Facets.Add(facet); } else { Debug.Log("Unsupported restriction type."); } } } schemaInfo.schema.Items.Add(simpleType); attributeRecord = new FactoryProcessingHelper.AttributeRecord { name = xqn, desc = description }; processingData.attributeTypeNames.Add(attrTypeName, attributeRecord); return(xqn); }
static XmlSchemaType AddElementTypeToXmlSchema(IUxmlFactory factory, SchemaInfo schemaInfo, FactoryProcessingHelper processingData) { // We always have complex types with complex content. XmlSchemaComplexType elementType = new XmlSchemaComplexType(); elementType.Name = factory.uxmlName + k_TypeSuffix; XmlSchemaComplexContent content = new XmlSchemaComplexContent(); elementType.ContentModel = content; // We only support restrictions of base types. XmlSchemaComplexContentRestriction restriction = new XmlSchemaComplexContentRestriction(); content.Content = restriction; if (factory.substituteForTypeName == String.Empty) { restriction.BaseTypeName = new XmlQualifiedName("anyType", k_XmlSchemaNamespace); } else { restriction.BaseTypeName = new XmlQualifiedName(factory.substituteForTypeName + k_TypeSuffix, factory.substituteForTypeNamespace); schemaInfo.importNamespaces.Add(factory.substituteForTypeNamespace); } if (factory.canHaveAnyAttribute) { XmlSchemaAnyAttribute anyAttribute = new XmlSchemaAnyAttribute(); anyAttribute.ProcessContents = XmlSchemaContentProcessing.Lax; restriction.AnyAttribute = anyAttribute; } foreach (UxmlAttributeDescription attrDesc in factory.uxmlAttributesDescription) { XmlQualifiedName typeName = AddAttributeTypeToXmlSchema(schemaInfo, attrDesc, factory, processingData); if (typeName != null) { AddAttributeToXmlSchema(restriction, attrDesc, typeName); schemaInfo.importNamespaces.Add(attrDesc.typeNamespace); } } bool hasChildElements = false; foreach (UxmlChildElementDescription childDesc in factory.uxmlChildElementsDescription) { hasChildElements = true; schemaInfo.importNamespaces.Add(childDesc.elementNamespace); } if (hasChildElements) { restriction.Particle = MakeChoiceSequence(factory.uxmlChildElementsDescription); } schemaInfo.schema.Items.Add(elementType); return(elementType); }
static bool ProcessFactory(IUxmlFactory factory, Dictionary <string, SchemaInfo> schemas, FactoryProcessingHelper processingData) { if (!string.IsNullOrEmpty(factory.substituteForTypeName)) { if (!processingData.IsKnownElementType(factory.substituteForTypeName, factory.substituteForTypeNamespace)) { // substituteForTypeName is not yet known. Defer processing to later. return(false); } } string uxmlNamespace = factory.uxmlNamespace; SchemaInfo schemaInfo; if (!schemas.TryGetValue(uxmlNamespace, out schemaInfo)) { schemaInfo = new SchemaInfo(uxmlNamespace); schemas[uxmlNamespace] = schemaInfo; } XmlSchemaType type = AddElementTypeToXmlSchema(factory, schemaInfo, processingData); AddElementToXmlSchema(factory, schemaInfo, type); processingData.RegisterElementType(factory.uxmlName, factory.uxmlNamespace); return(true); }
internal static IEnumerable <string> GenerateSchemaFiles(string baseDir = null) { Dictionary <string, SchemaInfo> schemas = new Dictionary <string, SchemaInfo>(); List <IUxmlFactory> deferredFactories = new List <IUxmlFactory>(); FactoryProcessingHelper processingData = new FactoryProcessingHelper(); if (baseDir == null) { baseDir = Application.temporaryCachePath + "/"; } // Convert the factories into schemas info. foreach (var factories in VisualElementFactoryRegistry.factories) { if (factories.Value.Count == 0) { continue; } // Only process the first factory, as the other factories define the same element. IUxmlFactory factory = factories.Value[0]; if (!ProcessFactory(factory, schemas, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing. deferredFactories.Add(factory); } } List <IUxmlFactory> deferredFactoriesCopy; do { deferredFactoriesCopy = new List <IUxmlFactory>(deferredFactories); foreach (var factory in deferredFactoriesCopy) { deferredFactories.Remove(factory); if (!ProcessFactory(factory, schemas, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing again. deferredFactories.Add(factory); } } }while (deferredFactoriesCopy.Count > deferredFactories.Count); if (deferredFactories.Count > 0) { Debug.Log("Some factories could not be processed because their base type is missing."); } // Compile schemas. XmlSchemaSet schemaSet = new XmlSchemaSet(); XmlSchema masterSchema = new XmlSchema(); masterSchema.ElementFormDefault = XmlSchemaForm.Qualified; XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); nsmgr.AddNamespace("xs", k_XmlSchemaNamespace); File.Delete(baseDir + k_MainSchemaFileName); foreach (var schema in schemas) { if (schema.Value.schema.TargetNamespace != null) { nsmgr.AddNamespace(schema.Value.namepacePrefix, schema.Value.schema.TargetNamespace); // Import schema into the master schema. XmlSchemaImport import = new XmlSchemaImport(); import.Namespace = schema.Value.schema.TargetNamespace; string schemaLocation = GetFileNameForNamespace(schema.Value.schema.TargetNamespace); File.Delete(baseDir + schemaLocation); import.SchemaLocation = schemaLocation; masterSchema.Includes.Add(import); } else { XmlSchemaInclude include = new XmlSchemaInclude(); string schemaLocation = GetFileNameForNamespace(null); File.Delete(baseDir + schemaLocation); include.SchemaLocation = schemaLocation; masterSchema.Includes.Add(include); } // Import referenced schemas into this XSD foreach (string ns in schema.Value.importNamespaces) { if (ns != schema.Value.schema.TargetNamespace && ns != k_XmlSchemaNamespace) { XmlSchemaImport import = new XmlSchemaImport(); import.Namespace = ns; import.SchemaLocation = GetFileNameForNamespace(ns); schema.Value.schema.Includes.Add(import); } } schemaSet.Add(schema.Value.schema); } schemaSet.Add(masterSchema); schemaSet.Compile(); // Now generate the schema textual data. foreach (XmlSchema compiledSchema in schemaSet.Schemas()) { string schemaName = compiledSchema.TargetNamespace; // Three possible cases: // TargetNamespace == null and Items.Count == 0: the main schema, that include/import all other schema files // TargetNamespace == null and Items.Count != 0: the schema file for the global namespace // TargetNamespace != null: the schema file for TargetNamespace if (schemaName == null && compiledSchema.Items.Count == 0) { schemaName = k_MainSchemaFileName; } else { schemaName = GetFileNameForNamespace(compiledSchema.TargetNamespace); } yield return(baseDir + schemaName); StringWriter strWriter = new UTF8StringWriter(); compiledSchema.Write(strWriter, nsmgr); yield return(strWriter.ToString()); } }
public void ImportFactoriesFromSource(BuilderLibraryItem sourceCategory) { var deferredFactories = new List <IUxmlFactory>(); var processingData = new FactoryProcessingHelper(); var emptyNamespaceControls = new List <TreeViewItem>(); foreach (var factories in VisualElementFactoryRegistry.factories) { if (factories.Value.Count == 0) { continue; } var factory = factories.Value[0]; if (!ProcessFactory(factory, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing. deferredFactories.Add(factory); } } List <IUxmlFactory> deferredFactoriesCopy; do { deferredFactoriesCopy = new List <IUxmlFactory>(deferredFactories); foreach (var factory in deferredFactoriesCopy) { deferredFactories.Remove(factory); if (!ProcessFactory(factory, processingData)) { // Could not process the factory now, because it depends on a yet unprocessed factory. // Defer its processing again. deferredFactories.Add(factory); } } }while (deferredFactoriesCopy.Count > deferredFactories.Count); if (deferredFactories.Count > 0) { Debug.Log("Some factories could not be processed because their base type is missing."); } var categoryStack = new List <BuilderLibraryItem>(); foreach (var known in processingData.knownTypes.Values) { var split = known.uxmlNamespace.Split('.'); if (split.Length == 0) { continue; } // Avoid adding our own internal factories (like Package Manager templates). if (!Unsupported.IsDeveloperMode() && split.Length > 0 && s_NameSpacesToAvoid.Contains(split[0])) { continue; } // Avoid adding UI Builder's own types, even in internal mode. if (split.Length >= 3 && split[0] == "Unity" && split[1] == "UI" && split[2] == "Builder") { continue; } var asset = new VisualElementAsset(known.uxmlQualifiedName); var slots = new Dictionary <string, VisualElement>(); var overrides = new List <TemplateAsset.AttributeOverride>(); var vta = ScriptableObject.CreateInstance <VisualTreeAsset>(); var context = new CreationContext(slots, overrides, vta, null); Type elementType = null; var factoryType = known.GetType(); while (factoryType != null && elementType == null) { if (factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(UxmlFactory <,>)) { elementType = factoryType.GetGenericArguments()[0]; } else { factoryType = factoryType.BaseType; } } var newItem = BuilderLibraryContent.CreateItem( known.uxmlName, elementType == typeof(TemplateContainer) ? nameof(TemplateContainer) : "CustomCSharpElement", elementType, () => known.Create(asset, context)); newItem.data.hasPreview = true; if (string.IsNullOrEmpty(split[0])) { emptyNamespaceControls.Add(newItem); } else { AddCategoriesToStack(sourceCategory, categoryStack, split); if (categoryStack.Count == 0) { sourceCategory.AddChild(newItem); } else { categoryStack.Last().AddChild(newItem); } } } sourceCategory.AddChildren(emptyNamespaceControls); }