/** * Loads a design for the given root component. * * <p>This methods assumes that the component class (or a super class) has been marked with an * {@link DesignRoot} annotation and will either use the value from the annotation to locate the * design file, or will fall back to using a design with the same same as the annotated class file * (with an .html extension) * * <p>Any {@link Component} type fields in the root component which are not assigned (i.e. are * null) are mapped to corresponding components in the design. Matching is done based on field * name in the component class and id/local id/caption in the design file. * * <p>The type of the root component must match the root element in the design * * @param rootComponent The root component of the layout * @return The design context used in the load operation * @throws DesignException If the design could not be loaded */ public static DesignContext read(Component rootComponent) throws DesignException { // Try to find an @DesignRoot annotation on the class or any parent // class Class<? extends Component> annotatedClass = findClassWithAnnotation(rootComponent.getClass(), DesignRoot.class); if (annotatedClass == null) { throw new IllegalArgumentException( "The class " + rootComponent.getClass().getName() + " or any of its superclasses do not have an @DesignRoot annotation"); } DesignRoot designAnnotation = annotatedClass.getAnnotation(DesignRoot.class); String filename = designAnnotation.value(); if (filename.equals("")) { // No value, assume the html file is named as the class filename = annotatedClass.getSimpleName() + ".html"; } InputStream stream = annotatedClass.getResourceAsStream(filename); if (stream == null) { throw new DesignException( "Unable to find design file " + filename + " in " + annotatedClass.getPackage().getName()); } Document doc = parse(stream); DesignContext context = designToComponentTree(doc, rootComponent, annotatedClass); return context; }
/** * Loads a design from the given file name using the given root component. * * <p>Any {@link Component} type fields in the root component which are not assigned (i.e. are * null) are mapped to corresponding components in the design. Matching is done based on field * name in the component class and id/local id/caption in the design file. * * <p>The type of the root component must match the root element in the design. * * @param filename The file name to load. Loaded from the same package as the root component * @param rootComponent The root component of the layout * @return The design context used in the load operation * @throws DesignException If the design could not be loaded */ public static DesignContext read(String filename, Component rootComponent) throws DesignException { InputStream stream = rootComponent.getClass().getResourceAsStream(filename); if (stream == null) { throw new DesignException( "File " + filename + " was not found in the package " + rootComponent.getClass().getPackage().getName()); } return read(stream, rootComponent); }
/** * 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. Any 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) { if (componentRoot == null) { return designToComponentTree(doc, null, null); } else { return designToComponentTree(doc, componentRoot, componentRoot.getClass()); } }
private void bindEventHandler( Component componentRoot, Object controller, Method method, UiHandler eventListener) { String componentId = eventListener.value(); Component component = Clara.findComponentById(componentRoot, componentId); if (component == null) { throw new BinderException("No component found for id: " + componentId + "."); } Class<?> eventType = (method.getParameterTypes().length > 0 ? method.getParameterTypes()[0] : null); if (eventType == null) { throw new BinderException("Couldn't figure out event type for method " + method + "."); } Method addListenerMethod = getAddListenerMethod(component.getClass(), eventType); if (addListenerMethod != null) { try { Object listener = createListenerProxy( addListenerMethod.getParameterTypes()[0], eventType, method, controller); addListenerMethod.invoke(component, listener); // TODO exception handling } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
@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; }