TreeTag.java :  » Groupware » ivatagroupware » com » ivata » groupware » web » tag » webgui » tree » Java Open Source

Java Open Source » Groupware » ivatagroupware 
ivatagroupware » com » ivata » groupware » web » tag » webgui » tree » TreeTag.java
/*
 * Copyright (c) 2001 - 2005 ivata limited.
 * All rights reserved.
 * -----------------------------------------------------------------------------
 * ivata groupware may be redistributed under the GNU General Public
 * License as published by the Free Software Foundation;
 * version 2 of the License.
 *
 * These programs are free software; you can redistribute them and/or
 * modify them under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2 of the License.
 *
 * These programs are distributed in the hope that they 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 in the file LICENSE.txt for more
 * details.
 *
 * If you would like a copy of the GNU General Public License write to
 *
 * Free Software Foundation, Inc.
 * 59 Temple Place - Suite 330
 * Boston, MA 02111-1307, USA.
 *
 *
 * To arrange commercial support and licensing, contact ivata at
 *                  http://www.ivata.com/contact.jsp
 * -----------------------------------------------------------------------------
 * $Log: TreeTag.java,v $
 * Revision 1.3  2005/10/11 18:51:38  colinmacleod
 * Fixed some checkstyle and javadoc issues.
 *
 * Revision 1.2  2005/10/02 14:08:57  colinmacleod
 * Added/improved log4j logging.
 *
 * Revision 1.1  2005/09/29 13:44:03  colinmacleod
 * Moved to core subproject.
 *
 * Revision 1.4  2005/09/14 14:51:43  colinmacleod
 * Removed unused local and class variables.
 * Added serialVersionUID.
 *
 * Revision 1.3  2005/04/10 18:47:36  colinmacleod
 * Changed i tag to em and b tag to strong.
 *
 * Revision 1.2  2005/04/09 17:19:10  colinmacleod
 * Changed copyright text to GPL v2 explicitly.
 *
 * Revision 1.1.1.1  2005/03/10 17:50:36  colinmacleod
 * Restructured ivata op around Hibernate/PicoContainer.
 * Renamed ivata groupware.
 *
 * Revision 1.2  2004/11/03 16:10:12  colinmacleod
 * Changed todo comments to TODO: all caps.
 *
 * Revision 1.1  2004/09/30 15:16:03  colinmacleod
 * Split off addressbook elements into security subproject.
 *
 * Revision 1.3  2004/07/13 19:41:15  colinmacleod
 * Moved project to POJOs from EJBs.
 * Applied PicoContainer to services layer (replacing session EJBs).
 * Applied Hibernate to persistence layer (replacing entity EJBs).
 *
 * Revision 1.2  2004/03/21 21:16:18  colinmacleod
 * Shortened name to ivata op.
 *
 * Revision 1.1.1.1  2004/01/27 20:57:58  colinmacleod
 * Moved ivata openportal to SourceForge..
 *
 * Revision 1.2  2003/10/17 12:36:13  jano
 * fixing problems with building
 * converting intranet -> portal
 * Eclipse building
 *
 * Revision 1.1.1.1  2003/10/13 20:50:14  colin
 * Restructured portal into subprojects
 *
 * Revision 1.1  2003/02/24 19:33:33  colin
 * moved to jsp
 *
 * Revision 1.10  2003/02/04 17:43:51  colin
 * copyright notice
 *
 * Revision 1.9  2003/02/01 12:48:11  colin
 * improved error handling
 *
 * Revision 1.8  2003/01/28 12:57:59  colin
 * made TreeTag a subclass of ControlTag (rather than WebGuiTag)
 *
 * Revision 1.7  2003/01/24 19:31:19  peter
 * the renderer initialise method was changed...
 *
 * Revision 1.6  2002/09/16 14:34:20  jano
 * added new field formName
 *
 * Revision 1.5  2002/08/28 12:54:12  jano
 * method createChildren changed
 *
 * Revision 1.4  2002/08/11 11:57:12  colin
 * Structural changes to make the design more flexible, for implementing
 * comment trees.
 *
 * Revision 1.3  2002/06/21 12:11:13  colin
 * restructured com.ivata.groupware.web and split into separate
 * subcategories
 *
 * Revision 1.2  2002/06/13 15:45:15  peter
 * brought over to peter, fixed bugs in webgui property-settings
 *
 * Revision 1.1  2002/06/13 07:44:07  colin
 * first version of rose model: code tidied up/added javadoc
 *
 * Revision 1.5  2002/02/03 15:24:08  colin
 * changed classname for User to PersonUser
 *
 * Revision 1.4  2002/02/02 21:23:01  colin
 * major restructuring to make the Settings class more generic
 * all default settings are now taken from the database rather than
 * being hard coded in the settings class
 * settings are stored in a HashMap in settings
 *
 * Revision 1.3  2002/01/27 19:55:48  colin
 * updated the themes by removing the multiple section tags and
 * replacing them with one tag and a Properties instance in
 * com.ivata.groupware.web.theme.Theme
 *
 * Revision 1.2  2002/01/24 13:19:40  colin
 * consolidated hanlding of theme and properties tags acoss webgui tag
 * library
 *
 * Revision 1.1  2002/01/20 19:28:25  colin
 * added tab and tree tags
 * implemented address book functionality
 * -----------------------------------------------------------------------------
 */
package com.ivata.groupware.web.tag.webgui.tree;

import java.io.IOException;
import java.util.Properties;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.swing.tree.TreeModel;

import org.apache.log4j.Logger;

import com.ivata.groupware.web.tree.DefaultTreeNodeRenderer;
import com.ivata.groupware.web.tree.TreeNode;
import com.ivata.groupware.web.tree.TreeNodeRenderer;
import com.ivata.mask.util.CollectionHandling;
import com.ivata.mask.web.tag.webgui.ControlTag;


/**
 * <p>Create a tree from a {@link javax.swing.tree.TreeModel TreeModel}.</p>
 * <p>This tree can be displayed is displayed as an HTML table with links on
 * each
 * node.</p>
 * <p><strong>Tag attributes:</strong><br/>
 * <table cellpadding='2' cellspacing='5' border='0' align='center'
 * width='85%'>
 *   <tr class='TableHeadingColor'>
 *     <th>attribute</th>
 *     <th>reqd.</th>
 *     <th>param. class</th>
 *     <th width='100%'>description</th>
 *   </tr>
 *   <tr class='TableRowColor'>
 *     <td>defaultOpen</td>
 *     <td>true</td>
 *     <td>boolean</td>
 *     <td>Set to <code>true</code> if you want tree nodes to be open by
 * default. Otherwise they will be closed.</td>
 *   </tr>
 *   <tr class='TableRowColor'>
 *     <td>model</td>
 *     <td>true</td>
 *     <td>{@link javax.swing.tree.TreeModel javax.swing.tree.TreeModel}</td>
 *     <td>This model contains the data source for the tree. To use any
 * datasource
 * with this tree control, you should first create a class which implements
 * {@link javax.swing.tree,TreeModel TreeModel}.</td>
 *   </tr>
 *   <tr class='TableRowColor'>
 *     <td>renderer</td>
 *     <td>false</td>
 *     <td>{@link com.ivata.groupware.web.tree.TreeNodeRenderer
 * com.ivata.groupware.web.tree.TreeNodeRenderer}</td>
 *     <td>This object controls the appearance of each node in the tree,
 * usually by parsing sections from the {@link
 * com.ivata.groupware.web.theme.Theme
 * Theme}.<br/>
 * If you do not use this attribute, an instance of {@link
 * com.ivata.groupware.web.DefaultTreeNodeRenderer
 * DefaultTreeNodeRenderer} is created and applied.</td>
 *   </tr>
 *   <tr class='TableRowColor'>
 *     <td>treeName</td>
 *     <td>true</td>
 *     <td><code>String</code></td>
 *     <td>Specifies a unique identifier for this tree, which is used to store
 * the state of each foler (open/closed).</td>
 *   </tr>
 *   <tr class='TableRowColor'>
 *     <td>userName</td>
 *     <td>true</td>
 *     <td><code>String</code></td>
 *     <td>Name of the user for whom to draw the tree. The state of each node is
 * stored for this user and the appearance in recalled the next time the tree is
 * drawn.</td>
 *   </tr>
 * </table>
 * </p>
 *
 * @since   2001-12-15
 * @author Colin MacLeod
 * <a href='mailto:colin.macleod@ivata.com'>colin.macleod@ivata.com</a>
 * @version $Revision: 1.3 $
 */
public class TreeTag extends ControlTag {
    /**
     * <p>This is the special property used to identify the location
     * of the children in the open tag.</p>
     *
     * <p><strong>Note</strong> that this has to be specified exactly, with
     * <u>no spaces</u>.</p>
     */
    static final String CHILDREN_PROPERTY = "treeChildren";

    /**
     * Logger for this class.
     */
    private static final Logger logger = Logger.getLogger(TreeTag.class);
    /**
     * Serialization version (for <code>Serializable</code> interface).
     */
    private static final long serialVersionUID = 1L;
    /**
     * <p>Specifies the id of a folder you wish to open.</p>
     */
    private Integer closeFolder = null;
    /**
     * <p>Decides whether folders should be open or closed by default.</p>
     */
    private boolean defaultOpen = false;
    /**
     * <p>if you set up name of form it will submit this form when you
     * open or close folder, otherwise it will make link to same page with
     * parameters.</p>
     */
    private String formName = null;
    /**
     * <p>Property declaration for tag attribute: model.</p>
     */
    private TreeModel model = null;
    /**
     * <p>Specifies the id of a folder you wish to open.</p>
     */
    private Integer openFolder = null;
    /**
     * <p>This renderer actually draws each node of the tree. If you do
     * not set a
     * renderer, then a <code>DefaultTreeNodeRenderer</code> is created
     * and
     * applied.</p>
     */
    private TreeNodeRenderer renderer;
    /**
     * <p>Property declaration for tag attribute: treeName.</p>
     */
    private String treeName = null;

    /**
     * <p>Default constructor.</p>

     */
    public TreeTag() {
        super();
    }

    /**
     * <p>This is the method which performs the clever stuff and actually
     * creates the tree by recursing on itself, for a table mode
     * tree.</p>
     *
     * @param parent the node for which to display all the children.
     * @param level the depth of this node within the tree, with 0 being
     * root.
     * @return the parsed HTML tree as
     * @throws JspException if there is any <code>IOException</code>.
     */
    private String createChildren(final Object parent,
            final int level) throws JspException {
        if (logger.isDebugEnabled()) {
            logger.debug("createChildren(Object parent = " + parent
                    + ", int level = " + level + ") - start");
        }

        String returnString = "";
        int totalNodes = model.getChildCount(parent);

        for (int nodeNumber = 0; nodeNumber < totalNodes; ++nodeNumber) {
            // make a fresh copy of the properties for each node
            Properties nodeProperties = CollectionHandling.splice(
                    getProperties(), new Properties());
            TreeNode node = (TreeNode) model.getChild(parent, nodeNumber);
            // find out if this folder is open or closed
            Boolean isOpenObject = Boolean.TRUE;
            boolean isOpen;

            // if the folder state is still not set, default
            if (isOpenObject == null) {
                isOpen = defaultOpen;
            } else {
                // use the last setting from the user
                isOpen = isOpenObject.booleanValue();
            }
            // if this node has children and is open and is not leaf, then we
            // have to parse the children first so we can set the property for
            // the children
            if ((model.getChildCount(node) > 0)
                    && isOpen
                    && !model.isLeaf(node)) {
                nodeProperties.setProperty(CHILDREN_PROPERTY,
                        createChildren(node,
                        level + 1));
            }
            // now we just use the renderer and return whatever that gives us
            try {
                returnString += renderer.render(model, node, isOpen,
                            level,
                            (nodeNumber == (totalNodes - 1)),
                            getTheme(),
                            nodeProperties);
            } catch (JspException e) {
                logger.error("createChildren(Object, int)", e);

                // catch it to throw it again :-)
                throw e;
            } catch (Exception e) {
                logger.error("createChildren(Object, int)", e);

                throw new JspException(e);
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("createChildren(Object, int) - end - return value = "
                    + returnString);
        }
        return returnString;
    }

    /**
     * <p>This method is called when the JSP engine encounters the start
     * tag,
     * after the attributes are processed.<p>
     *
     * <p>Scripting variables (if any) have their values set here.</p>
     *
     * @return <code>SKIP_BODY</code> if this tag has no body or it
     * should be skipped, otherwise <code>EVAL_BODY_BUFFERED</code>
     * @throws JspException if there is an error retrieving the
     * navigation
     * object.
     * @throws JspException if there is no settings object in the
     * session.
     * @throws JspException if there is an error wrting to
     * <code>out.print(
     * )</code>
     */
    public int doStartTag() throws JspException {
        if (logger.isDebugEnabled()) {
            logger.debug("doStartTag() - start");
        }

        super.doStartTag();
        try {
            // now do we have a valid renderer specified? if not, use the
            // default
            if (renderer == null) {
                renderer = new DefaultTreeNodeRenderer();
            }
            renderer.setTreeTag(this);
            JspWriter out = pageContext.getOut();

            renderer.initialize(pageContext.getSession(),
                (javax.servlet.http.HttpServletRequest)
                pageContext.getRequest(),
                out, pageContext);
            // create the full tree ( null parent )
            out.println(createChildren(model.getRoot(), 0));
            renderer.finalize(pageContext.getSession(),
                (javax.servlet.http.HttpServletRequest)
                pageContext.getRequest(),
                out);
        } catch (IOException ioException) {
            logger.error("doStartTag()", ioException);

            throw new JspException(
            "Error in TreeTag: IOException whilst printing select: "
            + ioException.getMessage(),
            ioException);
        } catch (Exception e) {
            logger.error("doStartTag()", e);

            throw new JspException(e);
        }
        // this tag has no body

        if (logger.isDebugEnabled()) {
            logger.debug("doStartTag() - end - return value = " + SKIP_BODY);
        }
        return SKIP_BODY;
    }

    /**
     * <p>Specifies the id of a folder you wish to close.</p>
     *
     * @return the current value of the folder which will be closed, or
     * <code>null</code> if no folder will be closed.
     */
    public final Integer getCloseFolder() {
        if (logger.isDebugEnabled()) {
            logger.debug("getCloseFolder() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getCloseFolder() - end - return value = "
                    + closeFolder);
        }
        return closeFolder;
    }

    /**
     * <p>Decides whether folders should be open or closed by default.</p>
     *
     * @return <code>true</code> if folders should be opened by default,
     * otherwise <code>false</code>.
     */
    public final boolean getDefaultOpen() {
        if (logger.isDebugEnabled()) {
            logger.debug("getDefaultOpen() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getDefaultOpen() - end - return value = "
                    + defaultOpen);
        }
        return defaultOpen;
    }

    /**
     * <p>Get the name of form which will submit when you open or close
     * folder.</p>
     *
     * @return <code>String</code> name of form
     */
    public final String getFormName() {
        if (logger.isDebugEnabled()) {
            logger.debug("getFormName() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getFormName() - end - return value = "
                    + this.formName);
        }
        return this.formName;
    }

    /**
     * <p>Get the value supplied to the attribute 'model'.</p>
     *
     * <p>This model contains the data source for the tree. To use any
     * datasource
     * with this tree control, you should first create a class which
     * implements
     * {@link javax.swing.tree,TreeModel TreeModel}.</p>
     *
     * @return the value supplied to the tag attribute 'model'.
     *
     */
    public final TreeModel getModel() {
        if (logger.isDebugEnabled()) {
            logger.debug("getModel() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getModel() - end - return value = " + model);
        }
        return model;
    }

    /**
     * <p>Specifies the id of a folder you wish to open.</p>
     *
     * @return the current value of the folder which will be opened, or
     * <code>null</code> if no folder will be opened.
     */
    public final Integer getOpenFolder() {
        if (logger.isDebugEnabled()) {
            logger.debug("getOpenFolder() - start");
        }

        if (logger.isDebugEnabled()) {
            logger
                    .debug("getOpenFolder() - end - return value = "
                            + openFolder);
        }
        return openFolder;
    }

    /**
     * <p>Get the value supplied to the attribute 'renderer'.</p>
     *
     * <p>This object controls the appearance of each node in the tree,
     * usually
     * by
     * parsing sections from the {@link
     * com.ivata.groupware.web.theme.Theme
     * Theme}.<br/>
     * If you do not use this attribute, an instance of {@link
     * com.ivata.groupware.web.DefaultTreeNodeRenderer
     * DefaultTreeNodeRenderer} is created and applied.</p>
     *
     * @return the value supplied to the tag attribute 'renderer'.
     *
     */
    public final TreeNodeRenderer getRenderer() {
        if (logger.isDebugEnabled()) {
            logger.debug("getRenderer() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getRenderer() - end - return value = " + renderer);
        }
        return renderer;
    }

    /**
     * <p>Get the value supplied to the attribute 'treeName'.</p>
     *
     * <p>This attribute specifies a unique identifier for this tree,
     * which is
     * used to store the state of each foler (open/closed).</p>
     *
     * @return the value supplied to the tag attribute 'treeName'.
     *
     */
    public final String getTreeName() {
        if (logger.isDebugEnabled()) {
            logger.debug("getTreeName() - start");
        }

        if (logger.isDebugEnabled()) {
            logger.debug("getTreeName() - end - return value = " + treeName);
        }
        return treeName;
    }

    /**
     * <p>Specifies the id of a folder you wish to close.</p>
     *
     * @param closeFolderParam the new value of the folder you wish to close.
     * Not setting or setting to <code>null</code> results in no folder being
     * closed.
     */
    public final void setCloseFolder(final Integer closeFolderParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setCloseFolder(Integer closeFolder = "
                    + closeFolderParam
                    + ") - start");
        }

        this.closeFolder = closeFolderParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setCloseFolder(Integer) - end");
        }
    }

    /**
     * <p>Decides whether folders should be open or closed by default.</p>
     *
     * @param defaultOpenParam set to <code>true</code> if folders should be
     * opened by default, otherwise <code>false</code>.
     */
    public final void setDefaultOpen(final boolean defaultOpenParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setDefaultOpen(boolean defaultOpen = "
                    + defaultOpenParam
                    + ") - start");
        }

        this.defaultOpen = defaultOpenParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setDefaultOpen(boolean) - end");
        }
    }

    /**
     * <p>Set the name of form submit when you open or close a folder.</p>
     *
     * @param formNameParam The name of form submit when you open or close a
     * folder.
     */
    public final void setFormName(final String formNameParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setFormName(String formName = " + formNameParam
                    + ") - start");
        }

        this.formName = formNameParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setFormName(String) - end");
        }
    }

    /**
     * <p>Set the value supplied to the attribute 'model'.</p>
     *
     * <p>This model contains the data source for the tree. To use any
     * datasource
     * with this tree control, you should first create a class which
     * implements
     * {@link javax.swing.tree,TreeModel TreeModel}.</p>
     *
     * @param modelParam the new value supplied to the tag attribute 'model'.
     *
     */
    public final void setModel(final TreeModel modelParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setModel(TreeModel model = "
                    + modelParam + ") - start");
        }

        this.model = modelParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setModel(TreeModel) - end");
        }
    }

    /**
     * <p>Specifies the id of a folder you wish to open.</p>
     *
     * @param openFolderParam the new value of the folder you wish to open. Not
     * setting
     * or setting to <code>null</code> results in no folder being opened.
     */
    public final void setOpenFolder(final Integer openFolderParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setOpenFolder(Integer openFolder = "
                    + openFolderParam
                    + ") - start");
        }

        this.openFolder = openFolderParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setOpenFolder(Integer) - end");
        }
    }

    /**
     * <p>Set the value supplied to the attribute 'renderer'.</p>
     *
     * <p>This object controls the appearance of each node in the tree,
     * usually
     * by
     * parsing sections from the {@link
     * com.ivata.groupware.web.theme.Theme
     * Theme}.<br/>
     * If you do not use this attribute, an instance of {@link
     * com.ivata.groupware.web.DefaultTreeNodeRenderer
     * DefaultTreeNodeRenderer} is created and applied.</p>
     *
     * @param rendererParam the new value supplied to the tag attribute
     * 'renderer'.
     *
     */
    public final void setRenderer(final TreeNodeRenderer rendererParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setRenderer(TreeNodeRenderer renderer = "
                    + rendererParam
                    + ") - start");
        }

        this.renderer = rendererParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setRenderer(TreeNodeRenderer) - end");
        }
    }

    /**
     * <p>Set the value supplied to the attribute 'treeName'.</p>
     *
     * <p>This attribute specifies a unique identifier for this tree,
     * which is
     * used to store the state of each foler (open/closed).</p>
     *
     * @param treeNameParam the new value supplied to the tag attribute
     * 'treeName'.
     *
     */
    public final void setTreeName(final String treeNameParam) {
        if (logger.isDebugEnabled()) {
            logger.debug("setTreeName(String treeName = " + treeNameParam
                    + ") - start");
        }

        this.treeName = treeNameParam;

        if (logger.isDebugEnabled()) {
            logger.debug("setTreeName(String) - end");
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.