/* * $Id$ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ package org.apache.struts2.dojo.components; import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.components.ClosingUIBean; import org.apache.struts2.views.annotations.StrutsTag; import org.apache.struts2.views.annotations.StrutsTagAttribute; import org.apache.struts2.views.annotations.StrutsTagSkipInheritance; import com.opensymphony.xwork2.util.ValueStack; /** * <!-- START SNIPPET: javadoc --> * * Renders a tree widget with AJAX support.<p/> * * The "id "attribute is normally specified(recommended), such that it could be looked up using * javascript if necessary. The "id" attribute is required if the "selectedNotifyTopic" or the * "href" attributes are going to be used.<p/> * * <!-- END SNIPPET: javadoc --> * * <!-- START SNIPPET: example1 --> * <s:tree id="..." label="..."> * <s:treenode id="..." label="..." /> * <s:treenode id="..." label="..."> * <s:treenode id="..." label="..." /> * <s:treenode id="..." label="..." /> * </s:treenode> * <s:treenode id="..." label="..." /> * </s:tree> * <!-- END SNIPPET: example1 --> * * <!-- START SNIPPET: example2 --> * <s:tree * id="..." * rootNode="..." * nodeIdProperty="..." * nodeTitleProperty="..." * childCollectionProperty="..." /> * <!-- END SNIPPET: example2 --> * * <!-- START SNIPPET: example3 --> * <s:url id="nodesUrl" namespace="/nodecorate" action="getNodes" /> * <div style="float:left; margin-right: 50px;"> * <sx:tree id="tree" href="%{#nodesUrl}" /> * </div> * * On this example the url specified on the "href" attibute will be called to load * the elements on the root. The response is expected to be a JSON array of objects like: * [ * { * label: "Node 1", * hasChildren: false, * id: "Node1" * }, * { * label: "Node 2", * hasChildren: true, * id: "Node2" * }, * ] * * "label" is the text that will be displayed for the node. "hasChildren" marks the node has * having children or not (if true, a plus icon will be assigned to the node so it can be * expanded). The "id" attribute will be used to load the children of the node, when the node * is expanded. When a node is expanded a request will be made to the url in the "href" attribute * and the node's "id" will be passed in the parameter "nodeId". * * The children collection for a node will be loaded only once, to reload the children of a * node, use the "reload()" function of the treenode widget. To reload the children nodes of "Node1" * from the example above use the following javascript: * * dojo.widget.byId("Node1").reload(); * <!-- END SNIPPET: example3 --> */ @StrutsTag(name="tree", tldTagClass="org.apache.struts2.dojo.views.jsp.ui.TreeTag", description="Render a tree widget.") public class Tree extends ClosingUIBean { private static final String TEMPLATE = "tree-close"; private static final String OPEN_TEMPLATE = "tree"; private final static transient Random RANDOM = new Random(); protected String toggle; protected String selectedNotifyTopics; protected String expandedNotifyTopics; protected String collapsedNotifyTopics; protected String rootNodeAttr; protected String childCollectionProperty; protected String nodeTitleProperty; protected String nodeIdProperty; protected String showRootGrid; protected String showGrid; protected String blankIconSrc; protected String gridIconSrcL; protected String gridIconSrcV; protected String gridIconSrcP; protected String gridIconSrcC; protected String gridIconSrcX; protected String gridIconSrcY; protected String expandIconSrcPlus; protected String expandIconSrcMinus; protected String iconWidth; protected String iconHeight; protected String toggleDuration; protected String templateCssPath; protected String href; protected String errorNotifyTopics; private List<String> childrenIds; public Tree(ValueStack stack, HttpServletRequest request, HttpServletResponse response) { super(stack, request, response); } public boolean start(Writer writer) { boolean result = super.start(writer); if (this.label == null && (href == null)) { if ((rootNodeAttr == null) || (childCollectionProperty == null) || (nodeTitleProperty == null) || (nodeIdProperty == null)) { fieldError("label","The TreeTag requires either a value for 'label' or 'href' or ALL of 'rootNode', " + "'childCollectionProperty', 'nodeTitleProperty', and 'nodeIdProperty'", null); } } return result; } protected void evaluateExtraParams() { super.evaluateExtraParams(); if (toggle != null) { addParameter("toggle", findString(toggle)); } else { addParameter("toggle", "fade"); } if (selectedNotifyTopics != null) { addParameter("selectedNotifyTopics", findString(selectedNotifyTopics)); } if (expandedNotifyTopics != null) { addParameter("expandedNotifyTopics", findString(expandedNotifyTopics)); } if (collapsedNotifyTopics != null) { addParameter("collapsedNotifyTopics", findString(collapsedNotifyTopics)); } if (rootNodeAttr != null) { addParameter("rootNode", findValue(rootNodeAttr)); } if (childCollectionProperty != null) { addParameter("childCollectionProperty", findString(childCollectionProperty)); } if (nodeTitleProperty != null) { addParameter("nodeTitleProperty", findString(nodeTitleProperty)); } if (nodeIdProperty != null) { addParameter("nodeIdProperty", findString(nodeIdProperty)); } if (showRootGrid != null) { addParameter("showRootGrid", findValue(showRootGrid, Boolean.class)); } if (showGrid != null) { addParameter("showGrid", findValue(showGrid, Boolean.class)); } if (blankIconSrc != null) { addParameter("blankIconSrc", findString(blankIconSrc)); } if (gridIconSrcL != null) { addParameter("gridIconSrcL", findString(gridIconSrcL)); } if (gridIconSrcV != null) { addParameter("gridIconSrcV", findString(gridIconSrcV)); } if (gridIconSrcP != null) { addParameter("gridIconSrcP", findString(gridIconSrcP)); } if (gridIconSrcC != null) { addParameter("gridIconSrcC", findString(gridIconSrcC)); } if (gridIconSrcX != null) { addParameter("gridIconSrcX", findString(gridIconSrcX)); } if (gridIconSrcY != null) { addParameter("gridIconSrcY", findString(gridIconSrcY)); } if (expandIconSrcPlus != null) { addParameter("expandIconSrcPlus", findString(expandIconSrcPlus)); } if (expandIconSrcMinus != null) { addParameter("expandIconSrcMinus", findString(expandIconSrcMinus)); } if (iconWidth != null) { addParameter("iconWidth", findValue(iconWidth, Integer.class)); } if (iconHeight != null) { addParameter("iconHeight", findValue(iconHeight, Integer.class)); } if (toggleDuration != null) { addParameter("toggleDuration", findValue(toggleDuration, Integer.class)); } if (templateCssPath != null) { addParameter("templateCssPath", findString(templateCssPath)); } if (href != null) addParameter("href", findString(href)); if (errorNotifyTopics != null) addParameter("errorNotifyTopics", findString(errorNotifyTopics)); // generate a random ID if not explicitly set and not parsing the content Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT); boolean generateId = (parseContent != null ? !parseContent : true); addParameter("pushId", generateId); if ((this.id == null || this.id.length() == 0) && generateId) { // resolves Math.abs(Integer.MIN_VALUE) issue reported by FindBugs // http://findbugs.sourceforge.net/bugDescriptions.html#RV_ABSOLUTE_VALUE_OF_RANDOM_INT int nextInt = RANDOM.nextInt(); nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt); this.id = "widget_" + String.valueOf(nextInt); addParameter("id", this.id); } if (this.childrenIds != null) addParameter("childrenIds", this.childrenIds); } public void addChildrenId(String id) { if (this.childrenIds == null) this.childrenIds = new ArrayList<String>(); this.childrenIds.add(id); } @Override @StrutsTagSkipInheritance public void setTheme(String theme) { super.setTheme(theme); } @Override public String getTheme() { return "ajax"; } public String getDefaultOpenTemplate() { return OPEN_TEMPLATE; } protected String getDefaultTemplate() { return TEMPLATE; } public String getToggle() { return toggle; } @StrutsTagAttribute(description="The toggle property (either 'explode' or 'fade')", defaultValue="fade") public void setToggle(String toggle) { this.toggle = toggle; } @StrutsTagAttribute(description="Deprecated. Use 'selectedNotifyTopics' instead.") public void setTreeSelectedTopic(String selectedNotifyTopic) { this.selectedNotifyTopics = selectedNotifyTopic; } @StrutsTagAttribute(description="Deprecated. Use 'expandedNotifyTopics' instead.") public void setTreeExpandedTopics(String expandedNotifyTopic) { this.expandedNotifyTopics = expandedNotifyTopic; } @StrutsTagAttribute(description="Deprecated. Use 'collapsedNotifyTopics' instead.") public void setTreeCollapsedTopics(String collapsedNotifyTopic) { this.collapsedNotifyTopics = collapsedNotifyTopic; } public String getRootNode() { return rootNodeAttr; } @StrutsTagAttribute(description="The rootNode property.") public void setRootNode(String rootNode) { this.rootNodeAttr = rootNode; } public String getChildCollectionProperty() { return childCollectionProperty; } @StrutsTagAttribute(description="The childCollectionProperty property.") public void setChildCollectionProperty(String childCollectionProperty) { this.childCollectionProperty = childCollectionProperty; } public String getNodeTitleProperty() { return nodeTitleProperty; } @StrutsTagAttribute(description="The nodeTitleProperty property.") public void setNodeTitleProperty(String nodeTitleProperty) { this.nodeTitleProperty = nodeTitleProperty; } public String getNodeIdProperty() { return nodeIdProperty; } @StrutsTagAttribute(description="The nodeIdProperty property.") public void setNodeIdProperty(String nodeIdProperty) { this.nodeIdProperty = nodeIdProperty; } @StrutsTagAttribute(description="The showRootGrid property (default true).") public void setShowRootGrid(String showRootGrid) { this.showRootGrid = showRootGrid; } public String getShowRootGrid() { return showRootGrid; } public String getBlankIconSrc() { return blankIconSrc; } @StrutsTagAttribute(description="Blank icon image source.") public void setBlankIconSrc(String blankIconSrc) { this.blankIconSrc = blankIconSrc; } public String getExpandIconSrcMinus() { return expandIconSrcMinus; } @StrutsTagAttribute(description="Expand icon (-) image source.") public void setExpandIconSrcMinus(String expandIconSrcMinus) { this.expandIconSrcMinus = expandIconSrcMinus; } public String getExpandIconSrcPlus() { return expandIconSrcPlus; } @StrutsTagAttribute(description="Expand Icon (+) image source.") public void setExpandIconSrcPlus(String expandIconSrcPlus) { this.expandIconSrcPlus = expandIconSrcPlus; } public String getGridIconSrcC() { return gridIconSrcC; } @StrutsTagAttribute(description="Image source for under child item child icons.") public void setGridIconSrcC(String gridIconSrcC) { this.gridIconSrcC = gridIconSrcC; } public String getGridIconSrcL() { return gridIconSrcL; } @StrutsTagAttribute(description=" Image source for last child grid.") public void setGridIconSrcL(String gridIconSrcL) { this.gridIconSrcL = gridIconSrcL; } public String getGridIconSrcP() { return gridIconSrcP; } @StrutsTagAttribute(description="Image source for under parent item child icons.") public void setGridIconSrcP(String gridIconSrcP) { this.gridIconSrcP = gridIconSrcP; } public String getGridIconSrcV() { return gridIconSrcV; } @StrutsTagAttribute(description="Image source for vertical line.") public void setGridIconSrcV(String gridIconSrcV) { this.gridIconSrcV = gridIconSrcV; } public String getGridIconSrcX() { return gridIconSrcX; } @StrutsTagAttribute(description="Image source for grid for sole root item.") public void setGridIconSrcX(String gridIconSrcX) { this.gridIconSrcX = gridIconSrcX; } public String getGridIconSrcY() { return gridIconSrcY; } @StrutsTagAttribute(description="Image source for grid for last root item.") public void setGridIconSrcY(String gridIconSrcY) { this.gridIconSrcY = gridIconSrcY; } public String getIconHeight() { return iconHeight; } @StrutsTagAttribute(description="Icon height", defaultValue="18px") public void setIconHeight(String iconHeight) { this.iconHeight = iconHeight; } public String getIconWidth() { return iconWidth; } @StrutsTagAttribute(description="Icon width", defaultValue="19px") public void setIconWidth(String iconWidth) { this.iconWidth = iconWidth; } public String getTemplateCssPath() { return templateCssPath; } @StrutsTagAttribute(description="Template css path", defaultValue="{contextPath}/struts/tree.css.") public void setTemplateCssPath(String templateCssPath) { this.templateCssPath = templateCssPath; } public String getToggleDuration() { return toggleDuration; } @StrutsTagAttribute(description="Toggle duration in milliseconds", defaultValue="150") public void setToggleDuration(String toggleDuration) { this.toggleDuration = toggleDuration; } public String getShowGrid() { return showGrid; } @StrutsTagAttribute(description="Show grid", type="Boolean", defaultValue="true") public void setShowGrid(String showGrid) { this.showGrid = showGrid; } @StrutsTagAttribute(description="The css class to use for element") public void setCssClass(String cssClass) { super.setCssClass(cssClass); } @StrutsTagAttribute(description="The css style to use for element") public void setCssStyle(String cssStyle) { super.setCssStyle(cssStyle); } @StrutsTagAttribute(description="The id to use for the element") public void setId(String id) { super.setId(id); } @StrutsTagAttribute(description="The name to set for element") public void setName(String name) { super.setName(name); } @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" + " is collapsed. An object with a 'node' property will be passed as parameter to the topics.") public void setCollapsedNotifyTopics(String collapsedNotifyTopics) { this.collapsedNotifyTopics = collapsedNotifyTopics; } @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" + " is expanded. An object with a 'node' property will be passed as parameter to the topics.") public void setExpandedNotifyTopics(String expandedNotifyTopics) { this.expandedNotifyTopics= expandedNotifyTopics; } @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" + " is selected. An object with a 'node' property will be passed as parameter to the topics.") public void setSelectedNotifyTopics(String selectedNotifyTopics) { this.selectedNotifyTopics = selectedNotifyTopics; } @StrutsTagAttribute(description="Url used to load the list of children nodes for an specific node, whose id will be " + "passed as a parameter named 'nodeId' (empty for root)") public void setHref(String href) { this.href = href; } @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request fails)." + "Only valid if 'href' is set") public void setErrorNotifyTopics(String errorNotifyTopics) { this.errorNotifyTopics = errorNotifyTopics; } }