Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }