@Override public String componentToTag(Component component, DesignContext context) { Class<?> componentClass = component.getClass(); String packageName = componentClass.getPackage().getName(); String prefix = context.getPackagePrefix(packageName); if (prefix == null) { prefix = packageName.replace('.', '_'); context.addPackagePrefix(prefix, packageName); } prefix = prefix + "-"; String className = classNameToElementName(componentClass.getSimpleName()); String tagName = prefix + className; return tagName; }
/** * Generates an html tree representation of the component hierarchy having the root * designContext.getRootComponent(). The hierarchy is stored under <body> in the tree. The * generated tree represents a valid html document. * * @param designContext a DesignContext object specifying the root component * (designContext.getRootComponent()) of the hierarchy * @return an html tree representation of the component hierarchy */ private static Document createHtml(DesignContext designContext) { // Create the html tree skeleton. Document doc = new Document(""); DocumentType docType = new DocumentType("html", "", "", ""); doc.appendChild(docType); Element html = doc.createElement("html"); doc.appendChild(html); html.appendChild(doc.createElement("head")); Element body = doc.createElement("body"); html.appendChild(body); // Append the design under <body> in the html tree. createNode // creates the entire component hierarchy rooted at the // given root node. Component root = designContext.getRootComponent(); if (root != null) { Node rootNode = designContext.createElement(root); body.appendChild(rootNode); } designContext.writePackageMappings(doc); return doc; }
/** * Constructs a component hierarchy from the design specified as an html tree. * * <p>If a component root is given, the component instances created during reading the design are * assigned to its member fields based on their id, local id, and caption * * @param doc the html tree * @param componentRoot optional component root instance. The type must match the type of the root * element in the design. * @param classWithFields a class (componentRoot class or a super class) with some member fields. * The member fields whose type is assignable from {@link Component} are bound to fields in * the design based on id/local id/caption */ private static DesignContext designToComponentTree( Document doc, Component componentRoot, Class<?> classWithFields) { DesignContext designContext = new DesignContext(doc); designContext.readPackageMappings(doc); // No special handling for a document without a body element - should be // taken care of by jsoup. Element root = doc.body(); Elements children = root.children(); if (children.size() > 1) { throw new DesignException( "The first level of a component hierarchy should contain at most one root component, but found " + children.size() + "."); } Element element = children.size() == 0 ? null : children.first(); if (componentRoot != null) { if (element == null) { throw new DesignException( "The root element cannot be null when the specified root Component is" + " not null."); } // user has specified root instance that may have member fields that // should be bound final FieldBinder binder; try { binder = new FieldBinder(componentRoot, classWithFields); } catch (IntrospectionException e) { throw new DesignException("Could not bind fields of the root component", e); } // create listener for component creations that binds the created // components to the componentRoot instance fields ComponentCreationListener creationListener = new ComponentCreationListener() { @Override public void componentCreated(ComponentCreatedEvent event) { binder.bindField(event.getComponent(), event.getLocalId()); } }; designContext.addComponentCreationListener(creationListener); // create subtree designContext.readDesign(element, componentRoot); // make sure that all the member fields are bound Collection<String> unboundFields = binder.getUnboundFields(); if (!unboundFields.isEmpty()) { throw new DesignException("Found unbound fields from component root " + unboundFields); } // no need to listen anymore designContext.removeComponentCreationListener(creationListener); } else { // createChild creates the entire component hierarchy componentRoot = element == null ? null : designContext.readDesign(element); } designContext.setRootComponent(componentRoot); return designContext; }
@Override public Component tagToComponent( String tagName, ComponentFactory componentFactory, DesignContext context) { // Extract the package and class names. // Otherwise, get the full class name using the prefix to package // mapping. Example: "v-vertical-layout" -> // "com.vaadin.ui.VerticalLayout" String[] parts = tagName.split("-", 2); if (parts.length < 2) { throw new DesignException("The tagname '" + tagName + "' is invalid: missing prefix."); } String prefixName = parts[0]; String packageName = context.getPackage(prefixName); if (packageName == null) { throw new DesignException("Unknown tag: " + tagName); } String[] classNameParts = parts[1].split("-"); String className = ""; for (String classNamePart : classNameParts) { // Split will ignore trailing and multiple dashes but that // should be // ok // <v-button--> will be resolved to <v-button> // <v--button> will be resolved to <v-button> className += SharedUtil.capitalize(classNamePart); } String qualifiedClassName = packageName + "." + className; Component component = componentFactory.createComponent(qualifiedClassName, context); if (component == null) { throw new DesignException( "Got unexpected null component from " + componentFactory.getClass().getName() + " for class " + qualifiedClassName); } return component; }
/** * Writes the given component tree in design format to the given output stream. * * @param component the root component of the component tree, null can be used for generating an * empty design * @param outputStream the output stream to write the design to. The design is always written as * UTF-8 * @throws IOException */ public static void write(Component component, OutputStream outputStream) throws IOException { DesignContext dc = new DesignContext(); dc.setRootComponent(component); write(dc, outputStream); }
/** * Loads a design from the given input stream * * @param design The stream to read the design from * @return The root component of the design */ public static Component read(InputStream design) { DesignContext context = read(design, null); return context.getRootComponent(); }