You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ri...@apache.org on 2005/10/19 07:11:15 UTC

svn commit: r326395 [2/3] - in /beehive/trunk/netui: src/tags-html/org/apache/beehive/netui/tags/ src/tags-html/org/apache/beehive/netui/tags/rendering/ src/tags-html/org/apache/beehive/netui/tags/tree/ src/util/org/apache/beehive/netui/util/config/bea...

Modified: beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRenderer.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRenderer.java?rev=326395&r1=326394&r2=326395&view=diff
==============================================================================
--- beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRenderer.java (original)
+++ beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRenderer.java Tue Oct 18 22:10:36 2005
@@ -1,607 +1,898 @@
-/*
- * Copyright 2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * $Header:$
- */
-package org.apache.beehive.netui.tags.tree;
-
-import org.apache.beehive.netui.util.internal.InternalStringBuilder;
-
-import org.apache.beehive.netui.core.URLCodec;
-import org.apache.beehive.netui.pageflow.PageFlowUtils;
-import org.apache.beehive.netui.pageflow.internal.AdapterManager;
-import org.apache.beehive.netui.pageflow.internal.InternalUtils;
-import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
-import org.apache.beehive.netui.tags.HtmlUtils;
-import org.apache.beehive.netui.tags.html.HtmlConstants;
-import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
-import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
-import org.apache.beehive.netui.tags.rendering.*;
-import org.apache.beehive.netui.util.Bundle;
-
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.jsp.JspException;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-
-abstract public class TreeRenderer implements HtmlConstants
-{
-    private TagRenderingBase _imageRenderer;
-    private TagRenderingBase _anchorRenderer;
-    private TagRenderingBase _divRenderer;
-    private TagRenderingBase _spanRenderer;
-
-    private TreeRenderState _trs;
-
-    private ImageTag.State _imgState = new ImageTag.State();
-    private AnchorTag.State _anchorState = new AnchorTag.State();
-    private DivTag.State _divState = new DivTag.State();
-    private SpanTag.State _spanState = new SpanTag.State();
-
-    private ServletContext _servletContext;
-    private HttpServletRequest _req;
-    private HttpServletResponse _res;
-
-    TreeRenderer(TreeRenderState trs, HttpServletRequest request,
-                 HttpServletResponse response, ServletContext servletContext)
-    {
-        _trs = trs;
-        _imageRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.IMAGE_TAG, request);
-        _anchorRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.ANCHOR_TAG, request);
-        _divRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.DIV_TAG, request);
-        _spanRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.SPAN_TAG, request);
-        _servletContext = servletContext;
-        _req = request;
-        _res = response;
-    }
-
-    abstract protected void registerTagError(String message, Throwable e)
-            throws JspException;
-
-    abstract protected String renderTagId(HttpServletRequest request, String tagId, AbstractHtmlState state);
-
-    protected void renderBeforeNode(AbstractRenderAppender writer, TreeElement node)
-    {
-    }
-
-    protected void renderAfterNode(AbstractRenderAppender writer, TreeElement node)
-    {
-    }
-
-    /**
-     * This is a recursive method which generates the markup for the tree.
-     * @param sb
-     * @param node
-     * @param level
-     * @param attrs
-     * @param state
-     * @throws javax.servlet.jsp.JspException
-     */
-    protected void render(InternalStringBuilder sb, TreeElement node, int level, AttributeRenderer attrs,
-                          InheritableState state)
-            throws JspException
-    {
-        // assert the values...
-        assert(sb != null);
-        assert(node != null);
-
-        String encoding = _res.getCharacterEncoding();
-        String nodeName = node.getName();
-
-        assert(nodeName != null);
-
-        // HACK to take into account special characters like = and &
-        // in the node name, could remove this code if encode URL
-        // and later request.getParameter() could deal with = and &
-        // character in parameter values.
-        String encodedNodeName = null;
-        try {
-            encodedNodeName = URLCodec.encode(nodeName, encoding);
-            assert(encodedNodeName != null);
-        }
-        catch (IOException e) {
-            // report the exception and return.
-            String s = Bundle.getString("Tags_TreeEncodingError", null);
-            registerTagError(s, e);
-            return;
-        }
-
-        // add any attributes to the renderer
-        AttributeRenderer.RemoveInfo removes = attrs.addElement(node);
-
-        // get the renderers for this tree...
-        InternalStringBuilder img = new InternalStringBuilder(32);
-
-
-        // Render the beginning of this node
-        _divState.clear();
-        String tagId = node.getTagId();
-        String script = null;
-        if (tagId != null) {
-            script = renderTagId(_req, tagId, _divState);
-        }
-        attrs.renderDiv(_divState, node);
-        if (_trs.runAtClient) {
-            _divState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_LEVEL, Integer.toString(level));
-        }
-        sb.append("   ");
-        StringBuilderRenderAppender writer = new StringBuilderRenderAppender(sb);
-        renderBeforeNode(writer, node);
-        _divRenderer.doStartTag(writer, _divState);
-        sb.append("\n");
-        if (script != null)
-            sb.append(script);
-
-        // In devMode we will verify the structure of the tree.  This will not run in
-        // production mode.
-        ServletContext servletContext = InternalUtils.getServletContext(_req);
-        boolean devMode = !AdapterManager.getServletContainerAdapter(servletContext).isInProductionMode();
-        if (devMode) {
-            boolean error = false;
-            InternalStringBuilder errorText = new InternalStringBuilder(64);
-            if (node.getName() == null) {
-                errorText.append("name");
-                error = true;
-            }
-            if (node.getParent() == null) {
-                if (error)
-                    errorText.append(", ");
-                errorText.append("parent");
-            }
-
-            if (error)
-                registerTagError(Bundle.getString("Tags_TreeStructureError", errorText.toString()), null);
-        }
-
-        // check for tree override properties, the second
-        // case here is because the root runs through this an by definitions
-        // has InheritableState == state
-        InheritableState is = node.getInheritableState();
-        if (is != null && is != state) {
-            is.setParent(state);
-            state = is;
-        }
-
-        // Create the appropriate number of indents
-        // These are either the spacer.gif if the parent is the last in the line or the
-        // vertical line gif if the parent is not the last child.
-        _imgState.clear();
-        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, WIDTH, "16px");
-        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
-        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, "", false);
-        for (int i = 0; i < level; i++) {
-            int levels = level - i;
-            TreeElement parent = node;
-            for (int j = 1; j <= levels; j++)
-                parent = parent.getParent();
-
-            img.setLength(0);
-            img.append(state.getImageRoot());
-            img.append('/');
-            if (parent.isLast()) {
-                img.append(state.getImageSpacer());
-                _imgState.style = null;
-            }
-            else {
-                img.append(state.getVerticalLineImage());
-                _imgState.style = "vertical-align:bottom;";
-            }
-            sb.append("      ");
-            _imgState.src = img.toString();
-            _imageRenderer.doStartTag(writer, _imgState);
-            _imageRenderer.doEndTag(writer);
-            sb.append("\n");
-        }
-
-        // boolean flag that will indicate if there is an open anchor created
-        boolean closeAnchor = false;
-        if (!_trs.runAtClient)
-            closeAnchor = renderExpansionAnchor(sb, _anchorRenderer, node, nodeName, state);
-        else {
-            // Render client expansion and initialize the tree JavaScript support
-            closeAnchor = renderClientExpansionAnchor(sb, _anchorRenderer, node, encodedNodeName, state);
-        }
-
-        // place the image into the anchor....
-        // The type of the image depends upon the position and the type of the node.
-        String alt = "";
-        img.setLength(0);
-        img.append(state.getImageRoot());
-        img.append('/');
-        if (node.isLeaf()) {                        // leaf node either last or middle
-            if (node.isLast())
-                img.append(state.getLastLineJoinImage());
-            else
-                img.append(state.getLineJoinImage());
-        }
-        else if (node.isExpanded()) {               // interior node that is expanded
-            alt = Bundle.getString("Tags_TreeAltTextCollapse", null);
-            String rImg = null;
-            if (node.getParent() == null && node instanceof ITreeRootElement) {
-                rImg = ((ITreeRootElement) node).getRootNodeExpandedImage();
-                if (rImg != null) {
-                    img.append(rImg);
-                }
-            }
-            if (rImg == null) {
-                if (node.isLast())
-                    img.append(state.getLastNodeExpandedImage());
-                else
-                    img.append(state.getNodeExpandedImage());
-            }
-        }
-        else {                                      // interior not expanded
-            alt = Bundle.getString("Tags_TreeAltTextExpand", null);
-            String rImg = null;
-            if (node.getParent() == null && node instanceof ITreeRootElement) {
-                rImg = ((ITreeRootElement) node).getRootNodeCollapsedImage();
-                if (rImg != null) {
-                    img.append(rImg);
-                }
-            }
-            if (rImg == null) {
-                if (node.isLast())
-                    img.append(state.getLastNodeCollapsedImage());
-                else
-                    img.append(state.getNodeCollapsedImage());
-            }
-        }
-
-        // write out the image which occurs next to the icon
-        if (!closeAnchor)
-            sb.append("      ");
-
-        _imgState.clear();
-        _imgState.src = img.toString();
-        _imgState.style = "vertical-align:bottom;";
-        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
-        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt, false);
-
-        _imageRenderer.doStartTag(writer, _imgState);
-        _imageRenderer.doEndTag(writer);
-
-        // close the anchor if one was openned...
-        if (closeAnchor)
-            _anchorRenderer.doEndTag(writer);
-        sb.append("\n");
-
-        // Calculate the selection link for this node, if the node is disabled, we can skip
-        // this because a disabled node may not be selected.
-        String selectionLink = null;
-        if (!node.isDisabled()) {
-
-            // The action on the node overrides all.  Otherwise, check to see if there
-            // is either an href or clientAction.  If neither is set, then we inherit the
-            // action defined on the trees inheritable state.
-            String action = node.getAction();
-            if (action == null) {
-                selectionLink = node.getHref();
-                if (selectionLink == null && node.getClientAction() != null)
-                    selectionLink = "";
-                if (selectionLink == null)
-                    action = state.getSelectionAction();
-            }
-
-            // create the selection link
-            if (action != null && selectionLink == null) {
-
-                HashMap params = null;
-                boolean remove = false;
-                params = node.getParams();
-                if (params == null) {
-                    params = new HashMap();
-                    remove = true;
-                }
-                params.put(TreeElement.SELECTED_NODE, nodeName);
-                if (_trs.tagId != null) {
-                    params.put(TreeElement.TREE_ID, _trs.tagId);
-                }
-
-                // Add the jpf ScopeID param if necessary.
-                String scope = node.getScope();
-                if (scope != null) {
-                    params.put(ScopedServletUtils.SCOPE_ID_PARAM, scope);
-                }
-
-                String uri = null;
-                try {
-                    boolean xml = TagRenderingBase.Factory.isXHTML(_req);
-                    uri = PageFlowUtils.getRewrittenActionURI(_servletContext, _req, _res, action, params, null, xml);
-                }
-                catch (URISyntaxException e) {
-                    // report the error...
-                    String s = Bundle.getString("Tags_Tree_Node_URLException",
-                            new Object[]{action, e.getMessage()});
-                    registerTagError(s, e);
-                }
-
-                if (remove) {
-                    params.remove(TreeElement.SELECTED_NODE);
-                    if (_trs.tagId != null) {
-                        params.remove(TreeElement.TREE_ID);
-                    }
-
-                    if (scope != null) {
-                        params.remove(ScopedServletUtils.SCOPE_ID_PARAM);
-                    }
-                }
-
-                if (uri != null) {
-                    selectionLink = _res.encodeURL(uri);
-                }
-            }
-        }
-
-        TagRenderingBase endRender = null;
-        // if there is a selection link we need to put an anchor out.
-        if (selectionLink != null) {
-            _anchorState.clear();
-            _anchorState.href = selectionLink;
-            String target = node.getTarget();
-            if (target == null) {
-                target = state.getSelectionTarget();
-            }
-            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TARGET, target);
-            String title = node.getTitle();
-            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TITLE, title);
-
-            // set the selection styles
-            if (node.isSelected()) {
-                _anchorState.style = _trs.selectedStyle;
-                _anchorState.styleClass = _trs.selectedStyleClass;
-            }
-            else {
-                _anchorState.style = _trs.unselectedStyle;
-                _anchorState.styleClass = _trs.unselectedStyleClass;
-            }
-            if (_anchorState.style == null && _anchorState.styleClass == null) {
-                _anchorState.style = "text-decoration: none";
-            }
-
-            // render any attributes applied to the HTML
-            attrs.renderSelectionLink(_anchorState, node);
-
-            // render the runAtClient attributes
-            if (_trs.runAtClient) {
-                String action = node.getClientAction();
-                if (action != null) {
-                    action = HtmlUtils.escapeEscapes(action);
-                    action = ScriptRequestState.getString("netuiAction", new Object[]{action});
-                }
-                _anchorState.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, action);
-                // Jira 299
-                //_anchorState.onClick = action;
-            }
-
-            // actually render the anchor.
-            sb.append("      ");
-            _anchorRenderer.doStartTag(writer, _anchorState);
-            endRender = _anchorRenderer;
-        }
-        else {
-            // This node doesn's support selection.  This means we consider it disabled.  We will
-            // put a span around it and set the style/class to indicate that it is disabled.
-            _spanState.clear();
-            _spanState.styleClass = _trs.disabledStyleClass;
-            _spanState.style = _trs.disabledStyle;
-            sb.append("      ");
-            _spanRenderer.doStartTag(writer, _spanState);
-            endRender = _spanRenderer;
-        }
-        sb.append("&nbsp;");
-
-        // Render the icon for this node, there will always unless the tree turns off default
-        // icons by setting the useDefaultIcons attribute to false.
-        String icon = node.getIcon();
-        if (icon == null) {
-            icon = state.getIconRoot() + "/" + state.getItemIcon();
-        }
-        else {
-            icon = state.getIconRoot() + "/" + icon;
-        }
-
-        // write out the icon
-        String label = node.getLabel();
-        if (icon != null) {
-            _imgState.clear();
-            _imgState.src = icon;
-            _imgState.style = "vertical-align:text-top";
-            alt = null;
-            if (label != null && node.isLabelLegalAsAlt())
-                alt = label;
-            else
-                alt = node.getTitle();
-            if (alt == null)
-                alt = Bundle.getString("Tags_TreeAltText", null);
-            _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt, false);
-            _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
-
-            // set the inheritted attributes
-            attrs.renderIconImage(_imgState, node);
-            _imageRenderer.doStartTag(writer, _imgState);
-            _imageRenderer.doEndTag(writer);
-            sb.append("&nbsp;");
-        }
-
-        // Render the label for this node (if any)
-        if (label != null) {
-            if (_trs.escapeContent) {
-                InternalStringBuilder s = new InternalStringBuilder(label.length() + 16);
-                StringBuilderRenderAppender sbAppend = new StringBuilderRenderAppender(sb);
-                HtmlUtils.filter(label, sbAppend);
-                label = s.toString();
-            }
-            sb.append(label);
-            sb.append("&nbsp;");
-        }
-        endRender.doEndTag(writer);
-
-        // if there is content then we should render that here...
-        String ctnt = node.getContent();
-        if (ctnt != null) {
-            if (_trs.escapeContent) {
-                InternalStringBuilder s = new InternalStringBuilder(ctnt.length() + 16);
-                StringBuilderRenderAppender sbAppend = new StringBuilderRenderAppender(sb);
-                HtmlUtils.filter(ctnt, sbAppend);
-                ctnt = s.toString();
-            }
-            sb.append("\n      ");
-            sb.append(ctnt);
-        }
-
-        // Render the end of this node
-        sb.append("\n   ");
-        _divRenderer.doEndTag(writer);
-        sb.append("\n");
-        renderAfterNode(writer, node);
-
-        // now remove all of the attributes scoped with this...
-
-        attrs.removeElementScoped(node, removes);
-        // Render the children of this node
-        // If the node is expanded we render it
-        //    If we are runAtClient and the node is Not expandOnServer then render it
-        if (node.isExpanded() || (_trs.runAtClient && !node.isExpandOnServer())) {
-            TreeElement children[] = node.getChildren();
-            int newLevel = level + 1;
-            for (int i = 0; i < children.length; i++) {
-                render(sb, children[i], newLevel, attrs, state);
-            }
-        }
-        attrs.removeElement(node, removes);
-    }
-
-    private boolean renderExpansionAnchor(InternalStringBuilder sb, TagRenderingBase anchorRenderer,
-                                          TreeElement node, String nodeName, InheritableState state)
-            throws JspException
-    {
-        // Render the tree state image for this node
-        String action = state.getExpansionAction();
-        if (action == null) {
-            action = state.getSelectionAction();
-        }
-        boolean isAction = PageFlowTagUtils.isAction(_req, action);
-        if (!isAction) {
-            registerTagError(Bundle.getString("Tags_BadAction", action), null);
-            return false;
-        }
-
-        // encode the tree parameters into the action.
-        HashMap params = new HashMap();
-        params.put(TreeElement.EXPAND_NODE, nodeName);
-        assert (_trs.tagId != null);
-        params.put(TreeElement.TREE_ID, _trs.tagId);
-        String uri = null;
-        try {
-            boolean xml = TagRenderingBase.Factory.isXHTML(_req);
-            uri = PageFlowUtils.getRewrittenActionURI(_servletContext, _req, _res, action, params, null, xml);
-        }
-        catch (URISyntaxException e) {
-            // report the error...
-            String s = Bundle.getString("Tags_Tree_Node_URLException",
-                    new Object[]{action, e.getMessage()});
-            registerTagError(s, e);
-        }
-
-        boolean ret = false;
-        if ((uri != null) && !node.isLeaf()) {
-            _anchorState.clear();
-            _anchorState.href = _res.encodeURL(uri);
-            sb.append("      ");
-            StringBuilderRenderAppender writer = new StringBuilderRenderAppender(sb);
-            anchorRenderer.doStartTag(writer, _anchorState);
-            ret = true;
-        }
-        return ret;
-    }
-
-    /**
-     * @param sb
-     * @param node
-     * @param encodedNodeName
-     * @return
-     */
-    private boolean renderClientExpansionAnchor(InternalStringBuilder sb, TagRenderingBase anchorRenderer,
-                                                TreeElement node, String encodedNodeName,
-                                                InheritableState state)
-    {
-        boolean imgOverride = (state != state.getParent() && state.getParent() != null) ||
-                (node.getParent() == null);
-
-        if (!node.isLeaf()) {
-            boolean expanded = node.isExpanded();
-            _anchorState.clear();
-            _anchorState.href = "";
-            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR,
-                    (expanded ? TreeElement.TREE_EXPAND_STATE : TreeElement.TREE_COLLAPSE_STATE));
-            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR_INIT, "true");
-            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR_ID, encodedNodeName);
-            if (node.isLast()) {
-                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_NODE_LAST, "true");
-            }
-
-            // Does this node have it's images being overridden?
-            if (imgOverride) {
-                if (node.getParent() == null) {
-                    String rootImg = ((ITreeRootElement) node).getRootNodeCollapsedImage();
-                    if (rootImg != null)
-                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
-                                state.getImageRoot() + "/" + rootImg);
-                    else
-                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
-                                state.getImageRoot() + "/" + state.getLastNodeCollapsedImage());
-                    rootImg = ((ITreeRootElement) node).getRootNodeExpandedImage();
-                    if (rootImg != null)
-                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
-                                state.getImageRoot() + "/" + rootImg);
-                    else
-                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
-                                state.getImageRoot() + "/" + state.getLastNodeExpandedImage());
-                }
-                else if (node.isLast()) {
-                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
-                            state.getImageRoot() + "/" + state.getLastNodeCollapsedImage());
-                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
-                            state.getImageRoot() + "/" + state.getLastNodeExpandedImage());
-                }
-                else {
-                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
-                            state.getImageRoot() + "/" + state.getNodeCollapsedImage());
-                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
-                            state.getImageRoot() + "/" + state.getNodeExpandedImage());
-                }
-            }
-
-            if (node.isExpandOnServer() && !node.isExpanded()) {
-                String path = _req.getServletPath();
-                int idx = path.lastIndexOf('/');
-                if (idx != -1) {
-                    path = path.substring(1, idx);
-                }
-                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND, "true");
-                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_PATH, path);
-            }
-
-            sb.append("      ");
-            StringBuilderRenderAppender writer = new StringBuilderRenderAppender(sb);
-            anchorRenderer.doStartTag(writer, _anchorState);
-            return true;
-        }
-        return false;
-    }
-}
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.netui.tags.tree;
+
+import org.apache.beehive.netui.util.internal.InternalStringBuilder;
+
+import org.apache.beehive.netui.core.URLCodec;
+import org.apache.beehive.netui.pageflow.PageFlowUtils;
+import org.apache.beehive.netui.pageflow.internal.AdapterManager;
+import org.apache.beehive.netui.pageflow.internal.InternalUtils;
+import org.apache.beehive.netui.pageflow.scoping.ScopedServletUtils;
+import org.apache.beehive.netui.tags.HtmlUtils;
+import org.apache.beehive.netui.tags.html.HtmlConstants;
+import org.apache.beehive.netui.tags.internal.PageFlowTagUtils;
+import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
+import org.apache.beehive.netui.tags.rendering.*;
+import org.apache.beehive.netui.util.Bundle;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+
+/**
+ * This class renders the HTML markup for the NetUI Tree. The {@link #render} method
+ * recursively renders child nodes of the tree if they're expanded.
+ */
+public class TreeRenderer implements HtmlConstants
+{
+    protected static final String FORMAT_INDENT = "      ";
+    protected static final String FORMAT_NBSP = "&nbsp;";
+    protected static final String FORMAT_NEWLINE = "\n";
+
+    private TagRenderingBase _imageRenderer;
+    private TagRenderingBase _anchorRenderer;
+    private TagRenderingBase _divRenderer;
+    private TagRenderingBase _spanRenderer;
+
+    private ImageTag.State _imgState = new ImageTag.State();
+    private AnchorTag.State _anchorState = new AnchorTag.State();
+    private DivTag.State _divState = new DivTag.State();
+    private SpanTag.State _spanState = new SpanTag.State();
+
+    protected TreeRenderState _trs;
+
+    protected ServletContext _servletContext;
+    protected HttpServletRequest _req;
+    protected HttpServletResponse _res;
+
+    private TreeRenderSupport _treeRenderSupport;
+
+    public void init(TreeRenderState trs, HttpServletRequest request,
+                     HttpServletResponse response, ServletContext servletContext)
+    {
+        _trs = trs;
+        _imageRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.IMAGE_TAG, request);
+        _anchorRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.ANCHOR_TAG, request);
+        _divRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.DIV_TAG, request);
+        _spanRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.SPAN_TAG, request);
+        _servletContext = servletContext;
+        _req = request;
+        _res = response;
+    }
+
+    /**
+     * This method is set by the NetUI internals to defined an object that
+     * handles issues specific to rendering a tree for certain paths of
+     * execution in NetUI.
+     * @param treeRenderSupport the class to handle NetUI specific issues while
+     *        rendering the tree.
+     */
+    protected void setTreeRenderSupport(TreeRenderSupport treeRenderSupport)
+    {
+        _treeRenderSupport = treeRenderSupport;
+    }
+
+    protected TreeRenderSupport getTreeRenderSupport()
+    {
+        return _treeRenderSupport;
+    }
+
+    protected void registerTagError(String message, Throwable e)
+            throws JspException
+    {
+        _treeRenderSupport.registerTagError(message, e);
+    }
+
+    protected String renderTagId(HttpServletRequest request, String tagId, AbstractHtmlState state)
+    {
+        return _treeRenderSupport.renderTagId(request, tagId, state);
+    }
+
+    protected void renderBeforeNode(AbstractRenderAppender writer, TreeElement node)
+    {
+        _treeRenderSupport.renderBeforeNode(writer, node);
+    }
+
+    protected void renderAfterNode(AbstractRenderAppender writer, TreeElement node)
+    {
+        _treeRenderSupport.renderAfterNode(writer, node);
+    }
+
+    /**
+     * This is a recursive method which generates the markup for the tree.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     * @param level the level or depth of the node within the tree
+     * @param attrs renderer for supported attributes
+     * @param state the set of tree properties that are used to render the tree markup
+     * @throws javax.servlet.jsp.JspException
+     */
+    public void render(AbstractRenderAppender writer, TreeElement node, int level,
+                       AttributeRenderer attrs, InheritableState state)
+            throws JspException
+    {
+        // assert the values...
+        assert(writer != null);
+        assert(node != null);
+
+        String nodeName = node.getName();
+        assert(nodeName != null);
+
+        // add any attributes to the renderer
+        AttributeRenderer.RemoveInfo removes = attrs.addElement(node);
+
+        // Render the beginning of this node
+        _divState.clear();
+        String tagId = node.getTagId();
+        String script = null;
+        if (tagId != null) {
+            script = renderTagId(_req, tagId, _divState);
+        }
+        attrs.renderDiv(_divState, node);
+        if (_trs.runAtClient) {
+            _divState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_LEVEL, Integer.toString(level));
+        }
+        writer.append("   ");
+        renderBeforeNode(writer, node);
+        _divRenderer.doStartTag(writer, _divState);
+        writer.append("\n");
+        if (script != null)
+            writer.append(script);
+
+        // In devMode we will verify the structure of the tree.  This will not run in
+        // production mode.
+        ServletContext servletContext = InternalUtils.getServletContext(_req);
+        boolean devMode = !AdapterManager.getServletContainerAdapter(servletContext).isInProductionMode();
+        if (devMode) {
+            boolean error = false;
+            InternalStringBuilder errorText = new InternalStringBuilder(64);
+            if (node.getName() == null) {
+                errorText.append("name");
+                error = true;
+            }
+            if (node.getParent() == null) {
+                if (error)
+                    errorText.append(", ");
+                errorText.append("parent");
+            }
+
+            if (error)
+                registerTagError(Bundle.getString("Tags_TreeStructureError", errorText.toString()), null);
+        }
+
+        // check for tree override properties, the second
+        // case here is because the root runs through this an by definitions
+        // has InheritableState == state
+        InheritableState is = node.getInheritableState();
+        if (is != null && is != state) {
+            is.setParent(state);
+            state = is;
+        }
+
+        // write out the images that create the leading indentation for the given node
+        renderIndentation(writer, node, level, state);
+
+        // write out the image which occurs next to the node icon
+        renderConnectionImage(writer, node, nodeName, state);
+
+        // If needed, render the selection link around the icon for this node.
+        // Note that the tag rendered here needs to be closed after the actual
+        // icon and label are rendered.
+        TagRenderingBase endRender = renderSelectionLink(writer, node, nodeName, attrs, state);
+
+        // render the actual icon for this node
+        renderItemIcon(writer, node, attrs, state);
+
+        // render the label for this node (if any)
+        renderLabel(writer, node);
+
+        // now, close the selection link (or span) tag
+        if (endRender != null) {
+            endRender.doEndTag(writer);
+        }
+        renderSelectionLinkSuffix(writer, node);
+
+        // if there is content then we should render that here...
+        renderContent(writer, node);
+
+        // render the end of this node
+        writer.append("\n   ");
+        _divRenderer.doEndTag(writer);
+        writer.append("\n");
+        renderAfterNode(writer, node);
+
+        // now remove all of the attributes scoped with this...
+        attrs.removeElementScoped(node, removes);
+
+        // Render the children of this node
+        // If the node is expanded we render it
+        //    If we are runAtClient and the node is Not expandOnServer then render it
+        if (node.isExpanded() || (_trs.runAtClient && !node.isExpandOnServer())) {
+            TreeElement children[] = node.getChildren();
+            int newLevel = level + 1;
+            for (int i = 0; i < children.length; i++) {
+                render(writer, children[i], newLevel, attrs, state);
+            }
+        }
+        attrs.removeElement(node, removes);
+    }
+
+    /**
+     * Write out the images that create the leading indentation for the given node.
+     * @param writer the appender where the node indentation images are appended
+     * @param node the node to render
+     * @param level the level or depth of the node within the tree
+     * @param state the set of tree properties that are used to render the tree markup
+     */
+    protected void renderIndentation(AbstractRenderAppender writer, TreeElement node, int level, InheritableState state)
+    {
+        InternalStringBuilder img = new InternalStringBuilder(32);
+
+        // Create the appropriate number of indents
+        // These are either the spacer.gif if the parent is the last in the line or the
+        // vertical line gif if the parent is not the last child.
+        _imgState.clear();
+        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, WIDTH, "16px");
+        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
+        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, "", false);
+        for (int i = 0; i < level; i++) {
+            int levels = level - i;
+            TreeElement parent = node;
+            for (int j = 1; j <= levels; j++) {
+                parent = parent.getParent();
+            }
+
+            img.setLength(0);
+            img.append(state.getImageRoot());
+            img.append('/');
+            if (parent.isLast()) {
+                renderSpacerPrefix(writer, node);
+                img.append(state.getImageSpacer());
+                _imgState.style = null;
+            }
+            else {
+                renderVerticalLinePrefix(writer, node);
+                img.append(state.getVerticalLineImage());
+                _imgState.style = "vertical-align:bottom;";
+            }
+            _imgState.src = img.toString();
+            _imageRenderer.doStartTag(writer, _imgState);
+            _imageRenderer.doEndTag(writer);
+            if (parent.isLast()) {
+                renderSpacerSuffix(writer, node);
+            }
+            else {
+                renderVerticalLineSuffix(writer, node);
+            }
+        }
+    }
+
+    /**
+     * Write out the image which occurs next to the node icon. This is
+     * usually some kind of connecting line, expand, or collapse image. 
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     * @param nodeName the unique name of the node
+     * @param state the set of tree properties that are used to render the tree markup
+     * @throws JspException
+     */
+    protected void renderConnectionImage(AbstractRenderAppender writer, TreeElement node, String nodeName, InheritableState state)
+            throws JspException
+    {
+        InternalStringBuilder img = new InternalStringBuilder(32);
+
+        // HACK to take into account special characters like = and &
+        // in the node name, could remove this code if encode URL
+        // and later request.getParameter() could deal with = and &
+        // character in parameter values.
+        String encodedNodeName = null;
+        try {
+            encodedNodeName = URLCodec.encode(nodeName, _res.getCharacterEncoding());
+            assert(encodedNodeName != null);
+        }
+        catch (IOException e) {
+            // report the exception and return.
+            String s = Bundle.getString("Tags_TreeEncodingError", null);
+            registerTagError(s, e);
+            return;
+        }
+
+        // boolean flag that will indicate if there is an open anchor created
+        boolean closeAnchor = false;
+        if (!_trs.runAtClient) {
+            closeAnchor = renderExpansionAnchor(writer, _anchorRenderer, node, nodeName, state);
+        }
+        else {
+            // Render client expansion and initialize the tree JavaScript support
+            closeAnchor = renderClientExpansionAnchor(writer, _anchorRenderer, node, encodedNodeName, state);
+        }
+
+        // place the image into the anchor....
+        // The type of the image depends upon the position and the type of the node.
+        String alt = "";
+        img.setLength(0);
+        img.append(state.getImageRoot());
+        img.append('/');
+        if (node.isLeaf()) {                        // leaf node either last or middle
+            if (node.isLast())
+                img.append(state.getLastLineJoinImage());
+            else
+                img.append(state.getLineJoinImage());
+        }
+        else if (node.isExpanded()) {               // interior node that is expanded
+            alt = Bundle.getString("Tags_TreeAltTextCollapse", null);
+            String rImg = null;
+            if (node.getParent() == null && node instanceof ITreeRootElement) {
+                rImg = ((ITreeRootElement) node).getRootNodeExpandedImage();
+                if (rImg != null) {
+                    img.append(rImg);
+                }
+            }
+            if (rImg == null) {
+                if (node.isLast())
+                    img.append(state.getLastNodeExpandedImage());
+                else
+                    img.append(state.getNodeExpandedImage());
+            }
+        }
+        else {                                      // interior not expanded
+            alt = Bundle.getString("Tags_TreeAltTextExpand", null);
+            String rImg = null;
+            if (node.getParent() == null && node instanceof ITreeRootElement) {
+                rImg = ((ITreeRootElement) node).getRootNodeCollapsedImage();
+                if (rImg != null) {
+                    img.append(rImg);
+                }
+            }
+            if (rImg == null) {
+                if (node.isLast())
+                    img.append(state.getLastNodeCollapsedImage());
+                else
+                    img.append(state.getNodeCollapsedImage());
+            }
+        }
+
+        if (!closeAnchor) {
+            renderConnectionImagePrefix(writer, node);
+        }
+
+        // write out the image which occurs next to the icon
+        _imgState.clear();
+        _imgState.src = img.toString();
+        _imgState.style = "vertical-align:bottom;";
+        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
+        _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt, false);
+
+        _imageRenderer.doStartTag(writer, _imgState);
+        _imageRenderer.doEndTag(writer);
+
+        // close the anchor if one was openned...
+        if (closeAnchor) {
+            _anchorRenderer.doEndTag(writer);
+        }
+        renderConnectionImageSuffix(writer, node);
+    }
+
+    private boolean renderExpansionAnchor(AbstractRenderAppender writer, TagRenderingBase anchorRenderer,
+                                          TreeElement node, String nodeName, InheritableState state)
+            throws JspException
+    {
+        // Render the tree state image for this node
+        String action = state.getExpansionAction();
+        if (action == null) {
+            action = state.getSelectionAction();
+        }
+        boolean isAction = PageFlowTagUtils.isAction(_req, action);
+        if (!isAction) {
+            registerTagError(Bundle.getString("Tags_BadAction", action), null);
+            return false;
+        }
+
+        // encode the tree parameters into the action.
+        HashMap params = new HashMap();
+        params.put(TreeElement.EXPAND_NODE, nodeName);
+        assert (_trs.tagId != null);
+        params.put(TreeElement.TREE_ID, _trs.tagId);
+        String uri = null;
+        try {
+            boolean xml = TagRenderingBase.Factory.isXHTML(_req);
+            uri = PageFlowUtils.getRewrittenActionURI(_servletContext, _req, _res, action, params, null, xml);
+        }
+        catch (URISyntaxException e) {
+            // report the error...
+            String s = Bundle.getString("Tags_Tree_Node_URLException",
+                    new Object[]{action, e.getMessage()});
+            registerTagError(s, e);
+        }
+
+        boolean ret = false;
+        if ((uri != null) && !node.isLeaf()) {
+            _anchorState.clear();
+            _anchorState.href = _res.encodeURL(uri);
+            renderConnectionImagePrefix(writer, node);
+            anchorRenderer.doStartTag(writer, _anchorState);
+            ret = true;
+        }
+        return ret;
+    }
+
+    private boolean renderClientExpansionAnchor(AbstractRenderAppender writer, TagRenderingBase anchorRenderer,
+                                                TreeElement node, String encodedNodeName,
+                                                InheritableState state)
+    {
+        boolean imgOverride = (state != state.getParent() && state.getParent() != null) ||
+                (node.getParent() == null);
+
+        if (!node.isLeaf()) {
+            boolean expanded = node.isExpanded();
+            _anchorState.clear();
+            _anchorState.href = "";
+            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR,
+                    (expanded ? TreeElement.TREE_EXPAND_STATE : TreeElement.TREE_COLLAPSE_STATE));
+            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR_INIT, "true");
+            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_ANCHOR_ID, encodedNodeName);
+            if (node.isLast()) {
+                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_NODE_LAST, "true");
+            }
+
+            // Does this node have it's images being overridden?
+            if (imgOverride) {
+                if (node.getParent() == null) {
+                    String rootImg = ((ITreeRootElement) node).getRootNodeCollapsedImage();
+                    if (rootImg != null)
+                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
+                                state.getImageRoot() + "/" + rootImg);
+                    else
+                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
+                                state.getImageRoot() + "/" + state.getLastNodeCollapsedImage());
+                    rootImg = ((ITreeRootElement) node).getRootNodeExpandedImage();
+                    if (rootImg != null)
+                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
+                                state.getImageRoot() + "/" + rootImg);
+                    else
+                        _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
+                                state.getImageRoot() + "/" + state.getLastNodeExpandedImage());
+                }
+                else if (node.isLast()) {
+                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
+                            state.getImageRoot() + "/" + state.getLastNodeCollapsedImage());
+                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
+                            state.getImageRoot() + "/" + state.getLastNodeExpandedImage());
+                }
+                else {
+                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_COLLAPSE_IMAGE,
+                            state.getImageRoot() + "/" + state.getNodeCollapsedImage());
+                    _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_IMAGE,
+                            state.getImageRoot() + "/" + state.getNodeExpandedImage());
+                }
+            }
+
+            if (node.isExpandOnServer() && !node.isExpanded()) {
+                String path = _req.getServletPath();
+                int idx = path.lastIndexOf('/');
+                if (idx != -1) {
+                    path = path.substring(1, idx);
+                }
+                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND, "true");
+                _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TreeElement.TREE_EXPAND_PATH, path);
+            }
+
+            renderConnectionImagePrefix(writer, node);
+            anchorRenderer.doStartTag(writer, _anchorState);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * If needed, render the selection link around the icon for this node.
+     * Note that the tag rendered here needs to be closed after the actual
+     * icon and label are rendered.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     * @param nodeName the unique name of the node
+     * @param attrs renderer for supported attributes
+     * @param state the set of tree properties that are used to render the tree markup
+     * @return the selection link (or span) tag renderer to close after the item
+     *         icon and label rendered
+     * @throws JspException
+     */
+    protected TagRenderingBase renderSelectionLink(AbstractRenderAppender writer,
+                                                   TreeElement node, String nodeName,
+                                                   AttributeRenderer attrs,
+                                                   InheritableState state)
+            throws JspException
+    {
+        // calculate the selection link for this node
+        String selectionLink = getSelectionlink(node, nodeName, state);
+
+        TagRenderingBase endRender = null;
+        // if there is a selection link we need to put an anchor out.
+        if (selectionLink != null) {
+            _anchorState.clear();
+            _anchorState.href = selectionLink;
+            String target = node.getTarget();
+            if (target == null) {
+                target = state.getSelectionTarget();
+            }
+            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TARGET, target);
+            String title = node.getTitle();
+            _anchorState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, TITLE, title);
+
+            // set the selection styles
+            if (node.isSelected()) {
+                _anchorState.style = _trs.selectedStyle;
+                _anchorState.styleClass = _trs.selectedStyleClass;
+            }
+            else {
+                _anchorState.style = _trs.unselectedStyle;
+                _anchorState.styleClass = _trs.unselectedStyleClass;
+            }
+            if (_anchorState.style == null && _anchorState.styleClass == null) {
+                _anchorState.style = "text-decoration: none";
+            }
+
+            // render any attributes applied to the HTML
+            attrs.renderSelectionLink(_anchorState, node);
+
+            // render the runAtClient attributes
+            if (_trs.runAtClient) {
+                String action = node.getClientAction();
+                if (action != null) {
+                    action = HtmlUtils.escapeEscapes(action);
+                    action = ScriptRequestState.getString("netuiAction", new Object[]{action});
+                }
+                _anchorState.registerAttribute(AbstractHtmlState.ATTR_JAVASCRIPT, ONCLICK, action);
+                // Jira 299
+                //_anchorState.onClick = action;
+            }
+
+            // actually render the anchor.
+            renderSelectionLinkPrefix(writer, node);
+            _anchorRenderer.doStartTag(writer, _anchorState);
+            endRender = _anchorRenderer;
+        }
+        else {
+            // This node doesn's support selection.  This means we consider it disabled.  We will
+            // put a span around it and set the style/class to indicate that it is disabled.
+            _spanState.clear();
+            _spanState.styleClass = _trs.disabledStyleClass;
+            _spanState.style = _trs.disabledStyle;
+            renderSelectionLinkPrefix(writer, node);
+            _spanRenderer.doStartTag(writer, _spanState);
+            endRender = _spanRenderer;
+        }
+
+        return endRender;
+    }
+
+    /**
+     * Calculate the selection link for this node, if the node is disabled, we can skip
+     * this because a disabled node may not be selected.
+     * @param node the node to render
+     * @param nodeName the unique name of the node
+     * @param state the set of tree properties that are used to render the tree markup
+     * @return the URL for the selection link
+     * @throws JspException
+     */
+    protected String getSelectionlink(TreeElement node, String nodeName, InheritableState state)
+            throws JspException
+    {
+        String selectionLink = null;
+
+        if (!node.isDisabled()) {
+
+            // The action on the node overrides all.  Otherwise, check to see if there
+            // is either an href or clientAction.  If neither is set, then we inherit the
+            // action defined on the trees inheritable state.
+            String action = node.getAction();
+            if (action == null) {
+                selectionLink = node.getHref();
+                if (selectionLink == null && node.getClientAction() != null) {
+                    selectionLink = "";
+                }
+                if (selectionLink == null) {
+                    action = state.getSelectionAction();
+                }
+            }
+
+            // create the selection link
+            if (action != null && selectionLink == null) {
+                HashMap params = null;
+                boolean remove = false;
+                params = node.getParams();
+                if (params == null) {
+                    params = new HashMap();
+                    remove = true;
+                }
+                params.put(TreeElement.SELECTED_NODE, nodeName);
+                if (_trs.tagId != null) {
+                    params.put(TreeElement.TREE_ID, _trs.tagId);
+                }
+
+                // Add the jpf ScopeID param if necessary.
+                String scope = node.getScope();
+                if (scope != null) {
+                    params.put(ScopedServletUtils.SCOPE_ID_PARAM, scope);
+                }
+
+                String uri = null;
+                try {
+                    boolean xml = TagRenderingBase.Factory.isXHTML(_req);
+                    uri = PageFlowUtils.getRewrittenActionURI(_servletContext, _req, _res, action, params, null, xml);
+                }
+                catch (URISyntaxException e) {
+                    // report the error...
+                    String s = Bundle.getString("Tags_Tree_Node_URLException",
+                            new Object[]{action, e.getMessage()});
+                    registerTagError(s, e);
+                }
+
+                if (remove) {
+                    params.remove(TreeElement.SELECTED_NODE);
+                    if (_trs.tagId != null) {
+                        params.remove(TreeElement.TREE_ID);
+                    }
+
+                    if (scope != null) {
+                        params.remove(ScopedServletUtils.SCOPE_ID_PARAM);
+                    }
+                }
+
+                if (uri != null) {
+                    selectionLink = _res.encodeURL(uri);
+                }
+            }
+        }
+        return selectionLink;
+    }
+
+    /**
+     * Render the icon for this node.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     * @param attrs renderer for supported attributes
+     * @param state the set of tree properties that are used to render the tree markup
+     */
+    protected void renderItemIcon(AbstractRenderAppender writer,
+                                  TreeElement node,
+                                  AttributeRenderer attrs,
+                                  InheritableState state)
+    {
+        renderItemIconPrefix(writer, node);
+
+        // There should always be one unless the tree turns off default
+        // icons by setting the useDefaultIcons attribute to false.
+        String icon = node.getIcon();
+        if (icon == null) {
+            icon = state.getIconRoot() + "/" + state.getItemIcon();
+        }
+        else {
+            icon = state.getIconRoot() + "/" + icon;
+        }
+
+        // write out the icon
+        if (icon != null) {
+            _imgState.clear();
+            _imgState.src = icon;
+            _imgState.style = "vertical-align:text-top";
+            String alt = null;
+            String label = node.getLabel();
+            if (label != null && node.isLabelLegalAsAlt())
+                alt = label;
+            else
+                alt = node.getTitle();
+            if (alt == null)
+                alt = Bundle.getString("Tags_TreeAltText", null);
+            _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, ALT, alt, false);
+            _imgState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, BORDER, "0");
+
+            // set the inheritted attributes
+            attrs.renderIconImage(_imgState, node);
+            _imageRenderer.doStartTag(writer, _imgState);
+            _imageRenderer.doEndTag(writer);
+            renderItemIconSuffix(writer, node);
+        }
+    }
+
+    /**
+     * Render the label for this node (if any).
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderLabel(AbstractRenderAppender writer, TreeElement node)
+    {
+        String label = node.getLabel();
+        if (label != null) {
+            renderLabelPrefix(writer, node);
+            if (_trs.escapeContent) {
+                HtmlUtils.filter(label, writer);
+            }
+            else {
+                writer.append(label);
+            }
+            renderLabelSuffix(writer, node);
+        }
+    }
+
+    /**
+     * Render the Content for this node (if any).
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderContent(AbstractRenderAppender writer, TreeElement node)
+    {
+        String ctnt = node.getContent();
+        if (ctnt != null) {
+            renderContentPrefix(writer, node);
+            if (_trs.escapeContent) {
+                HtmlUtils.filter(ctnt, writer);
+            }
+            else {
+                writer.append(ctnt);
+            }
+            renderContentSuffix(writer, node);
+        }
+    }
+
+    // Methods that control formatting (beautifying) the node markup. Override these to
+    // manage the white space displayed in the page or to add additional markup.
+
+    /**
+     * Render the formatting before a spacer image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderSpacerPrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_INDENT);
+    }
+
+    /**
+     * Render the formatting after a spacer image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderSpacerSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NEWLINE);
+    }
+
+    /**
+     * Render the formatting before a vertical line image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderVerticalLinePrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_INDENT);
+    }
+
+    /**
+     * Render the formatting following a vertical line image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderVerticalLineSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NEWLINE);
+    }
+
+    /**
+     * Render the formatting before the connecting/expand/collapse image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderConnectionImagePrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_INDENT);
+    }
+
+    /**
+     * Render the formatting after the connecting/expand/collapse image.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderConnectionImageSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NEWLINE);
+    }
+
+    /**
+     * Render the formatting before the node selection anchor.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderSelectionLinkPrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_INDENT);
+    }
+
+    /**
+     * Render the formatting after the node selection anchor.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderSelectionLinkSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+    }
+
+    /**
+     * Render the formatting before the node icon.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderItemIconPrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NBSP);
+    }
+
+    /**
+     * Render the formatting after the node icon.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderItemIconSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NBSP);
+    }
+
+    /**
+     * Render the formatting before the node label.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderLabelPrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+    }
+
+    /**
+     * Render the formatting after the node label.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderLabelSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NBSP);
+    }
+
+    /**
+     * Render the formatting before the node content.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderContentPrefix(AbstractRenderAppender writer, TreeElement node)
+    {
+        writer.append(FORMAT_NEWLINE);
+        writer.append(FORMAT_INDENT);
+    }
+
+    /**
+     * Render the formatting after the node content.
+     * @param writer the appender where the tree markup is appended
+     * @param node the node to render
+     */
+    protected void renderContentSuffix(AbstractRenderAppender writer, TreeElement node)
+    {
+    }
+}

Added: beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRendererFactory.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRendererFactory.java?rev=326395&view=auto
==============================================================================
--- beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRendererFactory.java (added)
+++ beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRendererFactory.java Tue Oct 18 22:10:36 2005
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.netui.tags.tree;
+
+import org.apache.beehive.netui.util.internal.DiscoveryUtils;
+import org.apache.beehive.netui.util.logging.Logger;
+
+import java.io.Serializable;
+
+
+/**
+ * Instantiates a TreeRenderer object that can be used to render the
+ * Tree, writing out the formatting and markup for the Tree elements.
+ *
+ * @see org.apache.beehive.netui.tags.tree.TreeRenderer
+ */
+public class TreeRendererFactory implements Serializable
+{
+    private static final Logger _log = Logger.getInstance(TreeRendererFactory.class);
+
+    /* do not construct */
+    private TreeRendererFactory()
+    {
+    }
+
+    /**
+     * Create an instance of a {@link TreeRenderer} object. This method
+     * creates an instance that provides the NetUI predefined default
+     * implementation for tree rendering.
+     *
+     * @return the default tree renderer object.
+     */
+    public static final TreeRenderer getInstance()
+    {
+        return new TreeRenderer();
+    }
+
+    /**
+     * Create an instance of a {@link TreeRenderer} object given a class
+     * name. The given class must extend the {@link TreeRenderer} base class.
+     *
+     * @param className the name of the TreeRenderer class to instantiate
+     * @return the new {@link TreeRenderer} instance
+     */
+    public static final TreeRenderer getInstance(String className)
+    {
+        TreeRenderer renderer = null;
+        if (className != null) {
+            className = className.trim();
+
+            // create an instance of the def template formatter class
+            ClassLoader cl = DiscoveryUtils.getClassLoader();
+            try {
+                Class rendererClass = cl.loadClass(className);
+                if (!TreeRenderer.class.isAssignableFrom(rendererClass)) {
+                    _log.error("The tree renderer class, " + className
+                            + ", does not extend TreeRenderer.");
+                }
+                else {
+                    renderer = (TreeRenderer) rendererClass.newInstance();
+                }
+            }
+            catch ( ClassNotFoundException e ) {
+                _log.error( "Could not find TreeRenderer class " + className, e );
+            }
+            catch (InstantiationException e) {
+                _log.error( "Could not instantiate TreeRenderer class " + className, e );
+            }
+            catch (IllegalAccessException e) {
+                _log.error( "Could not instantiate TreeRenderer class " + className, e );
+            }
+        }
+        return renderer;
+    }
+}

Propchange: beehive/trunk/netui/src/tags-html/org/apache/beehive/netui/tags/tree/TreeRendererFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/bean/JspTagConfig.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/bean/JspTagConfig.java?rev=326395&r1=326394&r2=326395&view=diff
==============================================================================
--- beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/bean/JspTagConfig.java (original)
+++ beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/bean/JspTagConfig.java Tue Oct 18 22:10:36 2005
@@ -24,14 +24,18 @@
 
     private static final DocType DEFAULT_DOC_TYPE = DocType.HTML4_LOOSE_QUIRKS;
     private static final IdJavascript DEFAULT_ID_JAVASCRIPT = IdJavascript.DEFAULT;
+    private static final String DEFAULT_TREE_RENDERER_CLASS =
+        "org.apache.beehive.netui.tags.tree.TreeRenderer";
 
     private DocType _docType;
     private IdJavascript _idJavascript;
     private String _treeImageLocation;
+    private String _treeRendererClass;
 
     public JspTagConfig() {
         _docType = DEFAULT_DOC_TYPE;
         _idJavascript = DEFAULT_ID_JAVASCRIPT;
+        _treeRendererClass = DEFAULT_TREE_RENDERER_CLASS;
     }
 
     public JspTagConfig(DocType docType, IdJavascript idJavascript, String treeImageLocation) {
@@ -46,6 +50,13 @@
         _treeImageLocation = treeImageLocation;
     }
 
+    public JspTagConfig(DocType docType, IdJavascript idJavascript, String treeImageLocation, String treeRendererClass) {
+        this(docType, idJavascript, treeImageLocation);
+
+        if(treeRendererClass != null)
+            _treeRendererClass = treeRendererClass;
+    }
+
     public DocType getDocType() {
         return _docType;
     }
@@ -56,5 +67,9 @@
 
     public String getTreeImageLocation() {
         return _treeImageLocation;
+    }
+
+    public String getTreeRendererClass() {
+        return _treeRendererClass;
     }
 }

Modified: beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/parser/NetUIConfigParser.java
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/parser/NetUIConfigParser.java?rev=326395&r1=326394&r2=326395&view=diff
==============================================================================
--- beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/parser/NetUIConfigParser.java (original)
+++ beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/parser/NetUIConfigParser.java Tue Oct 18 22:10:36 2005
@@ -460,6 +460,7 @@
         DocType docType = null;
         IdJavascript idJavascript = null;
         String treeImageLocation = null;
+        String treeRendererClass = null;
 
         String tmp = null;
         Element elem = DomUtils.getChildElementByName(document.getDocumentElement(), "jsp-tag-config");
@@ -488,8 +489,9 @@
         }
 
         treeImageLocation = DomUtils.getChildElementText(elem, "tree-image-location");
+        treeRendererClass = DomUtils.getChildElementText(elem, "tree-renderer-class");
 
-        return new JspTagConfig(docType, idJavascript, treeImageLocation);
+        return new JspTagConfig(docType, idJavascript, treeImageLocation, treeRendererClass);
     }
 
     private static final PrefixHandlerConfig[] parsePrefixHandlerConfig(Document document) {

Modified: beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/schema/beehive-netui-config.xsd
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/schema/beehive-netui-config.xsd?rev=326395&r1=326394&r2=326395&view=diff
==============================================================================
--- beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/schema/beehive-netui-config.xsd (original)
+++ beehive/trunk/netui/src/util/org/apache/beehive/netui/util/config/schema/beehive-netui-config.xsd Tue Oct 18 22:10:36 2005
@@ -200,6 +200,7 @@
                 </xsd:simpleType>
             </xsd:element>
             <xsd:element name="tree-image-location" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+            <xsd:element name="tree-renderer-class" type="xsd:string" minOccurs="0" maxOccurs="1" default=""/>
         </xsd:sequence>
     </xsd:complexType>
     

Modified: beehive/trunk/netui/test/webapps/drt/coreWeb/miniTests/updateFormFromNested/Controller.jpf
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/webapps/drt/coreWeb/miniTests/updateFormFromNested/Controller.jpf?rev=326395&r1=326394&r2=326395&view=diff
==============================================================================
--- beehive/trunk/netui/test/webapps/drt/coreWeb/miniTests/updateFormFromNested/Controller.jpf (original)
+++ beehive/trunk/netui/test/webapps/drt/coreWeb/miniTests/updateFormFromNested/Controller.jpf Tue Oct 18 22:10:36 2005
@@ -111,35 +111,3 @@
     }
 }
 
-@Jpf.ViewProperties(value = {
-    "<!-- This data is auto-generated. Hand-editing this section is not recommended. -->",
-    "<view-properties>",
-    "<pageflow-object id='pageflow:/miniTests/updateFormFromNested/Controller.jpf'/>",
-    "<pageflow-object id='page:index.jsp'><property name='x' value='360'/><property name='y' value='100'/></pageflow-object>",
-    "<pageflow-object id='page:results.jsp'><property name='x' value='480'/><property name='y' value='240'/></pageflow-object>",
-    "<pageflow-object id='action:submit.do#miniTests.updateFormFromNested.Controller.SubmitForm'><property name='x' value='480'/><property name='y' value='120'/></pageflow-object>",
-    "<pageflow-object id='action:getZip.do#miniTests.updateFormFromNested.Controller.SubmitForm'><property name='x' value='60'/><property name='y' value='40'/></pageflow-object>",
-    "<pageflow-object id='formbean:java.lang.String'/>",
-    "<pageflow-object id='forward:path#success#results.jsp#@action:submit.do#miniTests.updateFormFromNested.Controller.SubmitForm@'/>",
-    "<pageflow-object id='return-to:@forward:returnTo#fail#currentPage#@action:submit.do#miniTests.updateFormFromNested.Controller.SubmitForm@@'><property name='x' value='180'/><property name='y' value='160'/></pageflow-object>",
-    "<pageflow-object id='forward:returnTo#fail#currentPage#@action:submit.do#miniTests.updateFormFromNested.Controller.SubmitForm@'/>",
-    "<pageflow-object id='external-jpf:getZip/GetZip.jpf'><property name='x' value='120'/><property name='y' value='100'/></pageflow-object>",
-    "<pageflow-object id='action:zipCancel.do'><property name='x' value='80'/><property name='y' value='60'/></pageflow-object>",
-    "<pageflow-object id='action-call:@external-jpf:getZip/GetZip.jpf@#@action:zipCancel.do@'/>",
-    "<pageflow-object id='forward:path#getZipFlow#getZip/GetZip.jpf#@action:getZip.do#miniTests.updateFormFromNested.Controller.SubmitForm@'/>",
-    "<pageflow-object id='action-call:@page:index.jsp@#@action:submit.do#miniTests.updateFormFromNested.Controller.SubmitForm@'><property name='elbowsX' value='397,420,420,443'/><property name='elbowsY' value='92,92,101,101'/><property name='fromPort' value='East_1'/><property name='toPort' value='West_0'/></pageflow-object>",
-    "<pageflow-object id='action-call:@page:index.jsp@#@action:getZip.do#miniTests.updateFormFromNested.Controller.SubmitForm@'><property name='elbowsX' value='323,210,210,97'/><property name='elbowsY' value='92,92,43,43'/><property name='fromPort' value='West_1'/><property name='toPort' value='East_2'/></pageflow-object>",
-    "<pageflow-object id='action:begin.do'><property value='80' name='x'/><property value='100' name='y'/></pageflow-object>",
-    "<pageflow-object id='action-call:@page:results.jsp@#@action:begin.do@'><property name='elbowsX' value='443,280,280,117'/><property name='elbowsY' value='232,232,103,103'/><property name='fromPort' value='West_1'/><property name='toPort' value='East_2'/></pageflow-object>",
-    "<pageflow-object id='action:zipSuccess.do#java.lang.String'><property name='x' value='120'/><property name='y' value='320'/></pageflow-object>",
-    "<pageflow-object id='action-call:@external-jpf:getZip/GetZip.jpf@#@action:zipSuccess.do#java.lang.String@'><property name='elbowsX' value='120,120,120,120'/><property name='elbowsY' value='145,210,210,275'/><property name='fromPort' value='South_1'/><property name='toPort' value='North_1'/></pageflow-object>",
-    "<pageflow-object id='formbean:SubmitForm'/>",
-    "<pageflow-object id='validation-field:zip#@formbean:SubmitForm@'/>",
-    "<pageflow-object id='validation-rule:1#{}#@validation-field:zip#@formbean:SubmitForm@@'/>",
-    "<pageflow-object id='validation-field:name#@formbean:SubmitForm@'/>",
-    "<pageflow-object id='validation-rule:1#{}#@validation-field:name#@formbean:SubmitForm@@'/>",
-    "<pageflow-object id='return-to:@forward:returnTo#success#currentPage#@action:zipSuccess.do#java.lang.String@@'><property name='x' value='220'/><property name='y' value='200'/></pageflow-object>",
-    "<pageflow-object id='forward:returnTo#success#currentPage#@action:zipSuccess.do#java.lang.String@'><property name='elbowsX' value='157,170,170,183'/><property name='elbowsY' value='312,312,192,192'/><property name='fromPort' value='East_1'/><property name='toPort' value='West_1'/><property name='label' value='success'/></pageflow-object>",
-    "</view-properties>"
-})
-interface VIEW_PROPERTIES { }

Added: beehive/trunk/netui/test/webapps/drt/coreWeb/tree/renderer/Controller.jpf
URL: http://svn.apache.org/viewcvs/beehive/trunk/netui/test/webapps/drt/coreWeb/tree/renderer/Controller.jpf?rev=326395&view=auto
==============================================================================
--- beehive/trunk/netui/test/webapps/drt/coreWeb/tree/renderer/Controller.jpf (added)
+++ beehive/trunk/netui/test/webapps/drt/coreWeb/tree/renderer/Controller.jpf Tue Oct 18 22:10:36 2005
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package tree.renderer;
+
+import org.apache.beehive.netui.pageflow.PageFlowController;
+import org.apache.beehive.netui.pageflow.annotations.Jpf;
+import org.apache.beehive.netui.pageflow.requeststate.NameService;
+import org.apache.beehive.netui.tags.tree.ITreeRootElement;
+import org.apache.beehive.netui.tags.tree.TreeElement;
+import org.apache.beehive.netui.tags.tree.TreeRenderState;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpSession;
+import org.apache.beehive.netui.pageflow.Forward;
+
+@Jpf.Controller (
+    simpleActions = {
+        @Jpf.SimpleAction(name="postback", navigateTo=Jpf.NavigateTo.currentPage),
+        @Jpf.SimpleAction(name = "select", path = "index.jsp")
+    }
+)
+public class Controller extends PageFlowController
+{
+    private TreeElement _root;
+    private int[] _children = {3,2,0,2,0,2,1,1,2};
+    private int _child = 0;
+
+    public TreeElement getRoot()
+    {
+        return _root;
+    }
+
+    // Tree represented by tags in the JSP
+    TreeElement myJspTree;
+    public TreeElement getMyJspTree()
+    {
+        return this.myJspTree;
+    }
+    public void setMyJspTree(TreeElement myJspTree)
+    {
+        this.myJspTree = myJspTree;
+    }
+
+    @Jpf.Action(
+        forwards={
+            @Jpf.Forward(name="index", path="index.jsp")
+        }
+    )
+    protected Forward begin()
+    {
+        NameService ns = NameService.instance(getRequest().getSession());
+        ns.debugSetNameIntValue(17);
+        return new Forward("index");
+    }
+
+    @Jpf.Action(
+        forwards={
+           @Jpf.Forward(name="index", path="index.jsp")
+        }
+    )
+    protected Forward reset()
+    {
+        _child = 0;
+        myJspTree = null;
+        _root = new ExtTreeRootElement("0", false, getChildCount());
+        return new Forward("index");
+    }
+
+    /**
+     * Callback that is invoked when this controller instance is created.
+     */
+    protected void onCreate()
+    {
+        _root = new ExtTreeRootElement("0", false, getChildCount());
+    }
+
+    /**
+     * Callback that is invoked when this controller instance is destroyed.
+     */
+    protected void onDestroy(HttpSession session)
+    {
+    }
+
+    private int getChildCount()
+    {
+        if (_child == _children.length)
+            return 0;
+        return _children[_child++];
+    }
+
+    class ExtTreeElement extends TreeElement
+    {
+        private boolean _leaf;
+        private int _children;
+
+        public ExtTreeElement(String s, boolean b, int children)
+        {
+            super(s, b);
+            _leaf = (children == 0);
+            _children  = children;
+            setExpandOnServer(!_leaf);
+        }
+
+        public void onExpand(ServletRequest request, ServletResponse response)
+        {
+            if (_children > 0 && size() == 0) {
+                for (int i=0;i<_children;i++) {
+                    String name = getLabel() + "." + i;
+                    ExtTreeElement m = new ExtTreeElement(name, false, getChildCount());
+                    addChild(m);
+                }
+            }
+        }
+
+        public boolean isLeaf()
+        {
+            return _leaf;
+        }
+    }
+
+    class ExtTreeRootElement extends ExtTreeElement implements ITreeRootElement
+    {
+        private String _name = null;
+        private TreeRenderState _trs = null;
+        private TreeElement _selectedNode;
+        private String _rootNodeExpandedImage;
+        private String _rootNodeCollapsedImage;
+
+        public ExtTreeRootElement(String s, boolean b, int children)
+        {
+            super(s, b, children);
+        }
+
+        public TreeElement getSelectedNode()
+        {
+            return _selectedNode;
+        }
+
+        public void changeSelected(String selectNode,ServletRequest request)
+        {
+            // if there is a selectedNode then we need to raise the onSelect
+            // event on that node indicating it will soon not be selected
+            TreeElement n = findNode(selectNode);
+            if (n == null) {
+                return;
+            }
+
+            // change the node that was selected so it is no longer selected
+            if (_selectedNode != null) {
+                _selectedNode.onSelect(request);
+                _selectedNode.setSelected(false);
+            }
+
+            // change the node that is to be selected
+            n.onSelect(request);
+            n.setSelected(true);
+            _selectedNode = n;
+            return;
+        }
+
+        public TreeRenderState getTreeRenderState()
+        {
+            return _trs;
+        }
+
+        public void setTreeRenderState(TreeRenderState treeRenderState)
+        {
+            _trs = treeRenderState;
+        }
+
+        public void setObjectName(String s)
+        {
+            _name = s;
+        }
+
+        public String getObjectName()
+        {
+            return _name;
+        }
+
+        public String getRootNodeExpandedImage()
+        {
+            return _rootNodeExpandedImage;
+        }
+
+        public void setRootNodeExpandedImage(String rootNodeExpandedImage)
+        {
+            _rootNodeExpandedImage = rootNodeExpandedImage;
+        }
+
+        public String getRootNodeCollapsedImage()
+        {
+            return _rootNodeCollapsedImage;
+        }
+
+        public void setRootNodeCollapsedImage(String rootNodeCollapsedImage)
+        {
+            _rootNodeCollapsedImage = rootNodeCollapsedImage;
+        }
+    }
+}
+
+
+

Propchange: beehive/trunk/netui/test/webapps/drt/coreWeb/tree/renderer/Controller.jpf
------------------------------------------------------------------------------
    svn:eol-style = native