com.bluexml.xforms.generator.forms.Renderable.java Source code

Java tutorial

Introduction

Here is the source code for com.bluexml.xforms.generator.forms.Renderable.java

Source

/*
Copyright (C) 2007-2011  BlueXML - www.bluexml.com
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
*/

package com.bluexml.xforms.generator.forms;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Element;

import com.bluexml.xforms.generator.FormGeneratorsManager;
import com.bluexml.xforms.generator.forms.renderable.forms.group.RenderableFormContainer;
import com.bluexml.xforms.generator.forms.rendered.RenderedLine;
import com.bluexml.xforms.generator.forms.rendered.RenderedRepeater;
import com.bluexml.xforms.generator.forms.rendered.RenderedTabContainer;
import com.bluexml.xforms.messages.MsgId;

/**
 * The Class Renderable.<br>
 * Own form meta model representing form elements
 */
public abstract class Renderable {

    /**
     * The Enum PathType<br>
     * Relative or absolute.
     */
    public static enum PathType {

        /** Relative path. */
        relativePath,

        /** Absolute path. */
        absolutePath;
    }

    /** The generation manager. */
    protected XFormsGenerator generationManager;

    /**
     * The Class Path.<br>
     * Gives a path, either absolute or relative
     */
    public static class Path {

        /** The path type. */
        protected PathType pathType;

        /** The path. */
        protected String path;

        /**
         * Instantiates a new path.
         * 
         * @param pathType
         *            the path type
         * @param path
         *            the path
         */
        public Path(PathType pathType, String path) {
            super();
            this.pathType = pathType;
            this.path = path;
        }

    }

    /** The logger. */
    protected static Log logger = LogFactory.getLog(Renderable.class);

    /** Static path : relative without a suffix. */
    protected static Path ROOT_RELATIVE = new Path(PathType.relativePath, "");

    /**
     * Absolute path : root. If a concrete renderable returns this, then its children's binding is
     * independent of their depth relatively to the nesting of renderables.<br/>
     * This has no link with the path in the nodeset.
     */
    protected static Path ROOT_ABSOLUTE = new Path(PathType.absolutePath, "");

    private static FormGeneratorsManager formGenerator;

    /**
     * The children.<br>
     * Renderable elements owned (even if a renderable can have multiple parents)
     */
    private List<Renderable> children;

    private boolean inWorkflowForm;

    /**
     * A style for the surrounding div when this renderable is included as a child in a
     * {@link RenderedLine}
     */
    private String divStyle = null;

    /**
     * Instantiates a new renderable.
     */
    public Renderable() {
        super();
        children = new ArrayList<Renderable>();
    }

    /**
     * Adds a child.
     * 
     * @param renderable
     *            the child
     */
    public void add(Renderable renderable) {
        // if (!(renderable instanceof RenderableFormContainer)) {
        // renderable.setInWorkflowForm(inWorkflowForm);
        // }
        children.add(renderable);
    }

    /**
     * Adds a child at first place.
     * 
     * @param renderable
     *            a child
     */
    public void addFirst(Renderable renderable) {
        if (!(renderable instanceof RenderableFormContainer)) {
            renderable.setInWorkflowForm(inWorkflowForm);
        }
        children.add(0, renderable);
    }

    /**
     * Gets the children size.
     * 
     * @return the children size
     */
    public int getChildrenSize() {
        return children.size();
    }

    /**
     * Indicates if tabs have to be shown.<br>
     * Done as DOJO tabs used in Chiba 2 can not be added inside a repeater
     * 
     * @param renderedParents
     *            the rendered parents
     * 
     * @return true, if tabs should be shown
     */
    protected boolean doShowTab(Stack<Rendered> renderedParents) {
        Rendered parent = renderedParents.peek();
        // if a parent is a tab container and tabs are not shown for it,
        // do no show tab too
        if (parent instanceof RenderedTabContainer) {
            if (!((RenderedTabContainer) parent).isShowTabs()) {
                return false;
            }
        }
        // search for a repeater
        for (Rendered rendered : renderedParents) {
            if (rendered instanceof RenderedRepeater) {
                return false;
            }
        }
        return true;
    }

    /**
     * Gets the data path of rendered element.<br />
     * Rendered will be initialized with this path
     * 
     * @param parents
     *            the parents
     * @param renderedParents
     *            the rendered parents
     * @param parentPath
     *            the parent path
     * 
     * @return the path
     */
    public abstract Path getPath(String parentPath, Stack<Renderable> parents, Stack<Rendered> renderedParents);

    /**
     * Recursive render.<br>
     * Initiate rendering
     * 
     * @return the rendered
     */
    public Rendered recursiveRender() {
        logger.debug("-------------------------------------------------");
        logger.debug("RENDERING " + this.toString());
        logger.debug("-------------------------------------------------");
        return recursiveRender("", new Stack<Renderable>(), new Stack<Rendered>(), false);
    }

    /**
     * Recursive render.
     * 
     * @param parentPath
     *            the parent path
     * @param parents
     *            the parents
     * @param renderedParents
     *            the rendered parents
     * @param isInIMultRepeater
     *            TODO
     * @return the rendered
     */
    private Rendered recursiveRender(String parentPath, Stack<Renderable> parents, Stack<Rendered> renderedParents,
            boolean isInIMultRepeater) {
        boolean previous = XFormsGenerator.isRenderingWorkflow();
        // logger.debug(this.toString() );

        // retrieve path for this renderable in this context
        Path path = getPath(parentPath, parents, renderedParents);
        // translate Path object into an absolute path
        String sPath = null;
        if (path.pathType == PathType.absolutePath) {
            sPath = path.path;
        } else {
            sPath = parentPath + path.path;
        }

        // if (StringUtils.trimToNull(sPath) != null) {
        // System.out.println("non empty path");
        // }
        // real render
        Rendered rendered = render(sPath, parents, renderedParents, isInIMultRepeater);

        // recursive render
        parents.push(this);
        boolean childIsInIMultiple = isInIMultRepeater || isInlineMultipleRepeater(); // #1310

        if (this instanceof RenderableFormContainer) {
            XFormsGenerator.setRenderingWorkflow(isInWorkflowForm());
        }
        renderedParents.push(rendered);
        for (Renderable child : children) {
            if (child == null) {
                throw new RuntimeException("A null child was found. You probably forgot to reference a form.");
            }
            if (child.shouldRender(parents)) {
                Rendered renderedChild = child.recursiveRender(sPath, parents, renderedParents, childIsInIMultiple);
                rendered.addRendered(renderedChild, child);
            }
        }
        //
        if (this instanceof RenderableFormContainer) {
            XFormsGenerator.setRenderingWorkflow(previous);
        }

        renderedParents.pop();
        rendered.renderEnd();
        renderEnd(rendered);

        parents.pop();

        return rendered;
    }

    /**
     * Abstract method aiming to render this instance.
     * 
     * @param path
     *            the path
     * @param parents
     *            the parents
     * @param renderedParents
     *            the rendered parents
     * @param isInIMultRepeater
     *            TODO
     * @return the rendered
     */
    public abstract Rendered render(String path, Stack<Renderable> parents, Stack<Rendered> renderedParents,
            boolean isInIMultRepeater);

    /**
     * Called when render is over.
     * 
     * @param rendered
     *            the rendered
     */
    public void renderEnd(@SuppressWarnings("unused") Rendered rendered) {
        // nothing by default
    }

    /**
     * Indicates if the element should be rendered in that context.
     * 
     * @param parents
     *            the parents
     * 
     * @return true, if successful
     */
    protected boolean shouldRender(@SuppressWarnings("unused") Stack<Renderable> parents) {
        return true;
    }

    /**
     * Gets the root path.<br>
     * Retrieves the path from where we can access directly to the data.<br>
     * This is used for association class or anywhere there's a repeater.
     * 
     * @param renderedParents
     *            the rendered parents
     * 
     * @return the root path (empty string if no repeater are found among parents)
     */
    protected String getRootPath(Stack<Rendered> renderedParents) {
        StringBuffer result = new StringBuffer("");
        for (Rendered rendered : renderedParents) {
            if (rendered instanceof RenderedRepeater) {
                RenderedRepeater repeated = (RenderedRepeater) rendered;
                String repeaterNodeSet = repeated.getNodeSet();
                repeaterNodeSet = StringUtils.left(repeaterNodeSet, repeaterNodeSet.lastIndexOf("["));
                repeaterNodeSet = repeaterNodeSet + "[index('" + repeated.getRepeatId() + "')]";
                result.append(repeaterNodeSet + "/");
            }
        }
        return result.toString();
    }

    /**
     * Renders the element as nested into a div if the "appearance" property is set. The string
     * value of the property is the CSS class of the div.
     * 
     * @param rendered
     *            the XML element of this field. WILL BE MODIFIED IF A STYLE IS DEFINED.
     */
    protected void applyStyle(Rendered rendered, String style) {
        if (StringUtils.trimToNull(style) != null) {
            Element divStyle = XFormsGenerator.createElement("div", XFormsGenerator.NAMESPACE_XHTML);
            Element nestedElement = rendered.getXformsElement();
            divStyle.setAttribute("class", style);
            divStyle.addContent(nestedElement);

            rendered.setXformsElement(divStyle);
        }
    }

    protected String getDynEnumContextString(String id) {
        return MsgId.INT_GEN_DYN_ENUM_PREFIX + id + MsgId.INT_GEN_DYN_ENUM_CONTEXT;
    }

    protected String getDynEnumParentString(String id) {
        return MsgId.INT_GEN_DYN_ENUM_PREFIX + id + MsgId.INT_GEN_DYN_ENUM_PARENT;
    }

    /**
     * @param inWorkflowForm
     *            the inWorkflowForm to set
     */
    public void setInWorkflowForm(boolean inWorkflowForm) {
        this.inWorkflowForm = inWorkflowForm;
    }

    /**
     * @return the inWorkflowForm
     */
    public boolean isInWorkflowForm() {
        return inWorkflowForm;
    }

    /**
     * @return the formGenerator
     */
    public static FormGeneratorsManager getFormGenerator() {
        return formGenerator;
    }

    /**
     * @param formGenerator
     *            the formGenerator to set
     */
    public static void setFormGenerator(FormGeneratorsManager formGenerator) {
        Renderable.formGenerator = formGenerator;
    }

    /**
     * Tells whether this object is an inline multiple repeater. Needed to avoid having all repeated
     * inline forms to point to the same nodes of the form's XML instance.
     * 
     * @return
     */
    public boolean isInlineMultipleRepeater() {
        return false;
    }

    /**
     * @param divStyle
     *            the divStyle to set
     */
    protected void setDivStyle(String divStyle) {
        this.divStyle = divStyle;
    }

    /**
     * @return the divStyle
     */
    public String getDivStyle() {
        return divStyle;
    }

}