1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.dojo.components;
23
24 import java.io.Writer;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Random;
28
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.apache.struts2.components.ClosingUIBean;
33 import org.apache.struts2.views.annotations.StrutsTag;
34 import org.apache.struts2.views.annotations.StrutsTagAttribute;
35 import org.apache.struts2.views.annotations.StrutsTagSkipInheritance;
36
37 import com.opensymphony.xwork2.util.ValueStack;
38
39 /***
40 * <!-- START SNIPPET: javadoc -->
41 *
42 * Renders a tree widget with AJAX support.<p/>
43 *
44 * The "id "attribute is normally specified(recommended), such that it could be looked up using
45 * javascript if necessary. The "id" attribute is required if the "selectedNotifyTopic" or the
46 * "href" attributes are going to be used.<p/>
47 *
48 * <!-- END SNIPPET: javadoc -->
49 *
50 * <!-- START SNIPPET: example1 -->
51 * <s:tree id="..." label="...">
52 * <s:treenode id="..." label="..." />
53 * <s:treenode id="..." label="...">
54 * <s:treenode id="..." label="..." />
55 * <s:treenode id="..." label="..." />
56 * </s:treenode>
57 * <s:treenode id="..." label="..." />
58 * </s:tree>
59 * <!-- END SNIPPET: example1 -->
60 *
61 * <!-- START SNIPPET: example2 -->
62 * <s:tree
63 * id="..."
64 * rootNode="..."
65 * nodeIdProperty="..."
66 * nodeTitleProperty="..."
67 * childCollectionProperty="..." />
68 * <!-- END SNIPPET: example2 -->
69 *
70 * <!-- START SNIPPET: example3 -->
71 * <s:url id="nodesUrl" namespace="/nodecorate" action="getNodes" />
72 * <div style="float:left; margin-right: 50px;">
73 * <sx:tree id="tree" href="%{#nodesUrl}" />
74 * </div>
75 *
76 * On this example the url specified on the "href" attibute will be called to load
77 * the elements on the root. The response is expected to be a JSON array of objects like:
78 * [
79 * {
80 * label: "Node 1",
81 * hasChildren: false,
82 * id: "Node1"
83 * },
84 * {
85 * label: "Node 2",
86 * hasChildren: true,
87 * id: "Node2"
88 * },
89 * ]
90 *
91 * "label" is the text that will be displayed for the node. "hasChildren" marks the node has
92 * having children or not (if true, a plus icon will be assigned to the node so it can be
93 * expanded). The "id" attribute will be used to load the children of the node, when the node
94 * is expanded. When a node is expanded a request will be made to the url in the "href" attribute
95 * and the node's "id" will be passed in the parameter "nodeId".
96 *
97 * The children collection for a node will be loaded only once, to reload the children of a
98 * node, use the "reload()" function of the treenode widget. To reload the children nodes of "Node1"
99 * from the example above use the following javascript:
100 *
101 * dojo.widget.byId("Node1").reload();
102 * <!-- END SNIPPET: example3 -->
103 */
104 @StrutsTag(name="tree", tldTagClass="org.apache.struts2.dojo.views.jsp.ui.TreeTag", description="Render a tree widget.")
105 public class Tree extends ClosingUIBean {
106
107 private static final String TEMPLATE = "tree-close";
108 private static final String OPEN_TEMPLATE = "tree";
109 private final static transient Random RANDOM = new Random();
110
111 protected String toggle;
112 protected String selectedNotifyTopics;
113 protected String expandedNotifyTopics;
114 protected String collapsedNotifyTopics;
115 protected String rootNodeAttr;
116 protected String childCollectionProperty;
117 protected String nodeTitleProperty;
118 protected String nodeIdProperty;
119 protected String showRootGrid;
120
121 protected String showGrid;
122 protected String blankIconSrc;
123 protected String gridIconSrcL;
124 protected String gridIconSrcV;
125 protected String gridIconSrcP;
126 protected String gridIconSrcC;
127 protected String gridIconSrcX;
128 protected String gridIconSrcY;
129 protected String expandIconSrcPlus;
130 protected String expandIconSrcMinus;
131 protected String iconWidth;
132 protected String iconHeight;
133 protected String toggleDuration;
134 protected String templateCssPath;
135 protected String href;
136 protected String errorNotifyTopics;
137
138 private List<String> childrenIds;
139
140 public Tree(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
141 super(stack, request, response);
142 }
143
144 public boolean start(Writer writer) {
145 boolean result = super.start(writer);
146
147 if (this.label == null && (href == null)) {
148 if ((rootNodeAttr == null)
149 || (childCollectionProperty == null)
150 || (nodeTitleProperty == null)
151 || (nodeIdProperty == null)) {
152 fieldError("label","The TreeTag requires either a value for 'label' or 'href' or ALL of 'rootNode', " +
153 "'childCollectionProperty', 'nodeTitleProperty', and 'nodeIdProperty'", null);
154 }
155 }
156 return result;
157 }
158
159 protected void evaluateExtraParams() {
160 super.evaluateExtraParams();
161
162 if (toggle != null) {
163 addParameter("toggle", findString(toggle));
164 } else {
165 addParameter("toggle", "fade");
166 }
167
168 if (selectedNotifyTopics != null) {
169 addParameter("selectedNotifyTopics", findString(selectedNotifyTopics));
170 }
171
172 if (expandedNotifyTopics != null) {
173 addParameter("expandedNotifyTopics", findString(expandedNotifyTopics));
174 }
175
176 if (collapsedNotifyTopics != null) {
177 addParameter("collapsedNotifyTopics", findString(collapsedNotifyTopics));
178 }
179
180 if (rootNodeAttr != null) {
181 addParameter("rootNode", findValue(rootNodeAttr));
182 }
183
184 if (childCollectionProperty != null) {
185 addParameter("childCollectionProperty", findString(childCollectionProperty));
186 }
187
188 if (nodeTitleProperty != null) {
189 addParameter("nodeTitleProperty", findString(nodeTitleProperty));
190 }
191
192 if (nodeIdProperty != null) {
193 addParameter("nodeIdProperty", findString(nodeIdProperty));
194 }
195
196 if (showRootGrid != null) {
197 addParameter("showRootGrid", findValue(showRootGrid, Boolean.class));
198 }
199
200
201 if (showGrid != null) {
202 addParameter("showGrid", findValue(showGrid, Boolean.class));
203 }
204
205 if (blankIconSrc != null) {
206 addParameter("blankIconSrc", findString(blankIconSrc));
207 }
208
209 if (gridIconSrcL != null) {
210 addParameter("gridIconSrcL", findString(gridIconSrcL));
211 }
212
213 if (gridIconSrcV != null) {
214 addParameter("gridIconSrcV", findString(gridIconSrcV));
215 }
216
217 if (gridIconSrcP != null) {
218 addParameter("gridIconSrcP", findString(gridIconSrcP));
219 }
220
221 if (gridIconSrcC != null) {
222 addParameter("gridIconSrcC", findString(gridIconSrcC));
223 }
224
225 if (gridIconSrcX != null) {
226 addParameter("gridIconSrcX", findString(gridIconSrcX));
227 }
228
229 if (gridIconSrcY != null) {
230 addParameter("gridIconSrcY", findString(gridIconSrcY));
231 }
232
233 if (expandIconSrcPlus != null) {
234 addParameter("expandIconSrcPlus", findString(expandIconSrcPlus));
235 }
236
237 if (expandIconSrcMinus != null) {
238 addParameter("expandIconSrcMinus", findString(expandIconSrcMinus));
239 }
240
241 if (iconWidth != null) {
242 addParameter("iconWidth", findValue(iconWidth, Integer.class));
243 }
244 if (iconHeight != null) {
245 addParameter("iconHeight", findValue(iconHeight, Integer.class));
246 }
247 if (toggleDuration != null) {
248 addParameter("toggleDuration", findValue(toggleDuration, Integer.class));
249 }
250 if (templateCssPath != null) {
251 addParameter("templateCssPath", findString(templateCssPath));
252 }
253 if (href != null)
254 addParameter("href", findString(href));
255 if (errorNotifyTopics != null)
256 addParameter("errorNotifyTopics", findString(errorNotifyTopics));
257
258
259 Boolean parseContent = (Boolean)stack.getContext().get(Head.PARSE_CONTENT);
260 boolean generateId = (parseContent != null ? !parseContent : true);
261
262 addParameter("pushId", generateId);
263 if ((this.id == null || this.id.length() == 0) && generateId) {
264
265
266 int nextInt = RANDOM.nextInt();
267 nextInt = nextInt == Integer.MIN_VALUE ? Integer.MAX_VALUE : Math.abs(nextInt);
268 this.id = "widget_" + String.valueOf(nextInt);
269 addParameter("id", this.id);
270 }
271
272 if (this.childrenIds != null)
273 addParameter("childrenIds", this.childrenIds);
274 }
275
276 public void addChildrenId(String id) {
277 if (this.childrenIds == null)
278 this.childrenIds = new ArrayList<String>();
279 this.childrenIds.add(id);
280 }
281
282 @Override
283 @StrutsTagSkipInheritance
284 public void setTheme(String theme) {
285 super.setTheme(theme);
286 }
287
288 @Override
289 public String getTheme() {
290 return "ajax";
291 }
292
293 public String getDefaultOpenTemplate() {
294 return OPEN_TEMPLATE;
295 }
296
297 protected String getDefaultTemplate() {
298 return TEMPLATE;
299 }
300
301 public String getToggle() {
302 return toggle;
303 }
304
305 @StrutsTagAttribute(description="The toggle property (either 'explode' or 'fade')", defaultValue="fade")
306 public void setToggle(String toggle) {
307 this.toggle = toggle;
308 }
309
310 @StrutsTagAttribute(description="Deprecated. Use 'selectedNotifyTopics' instead.")
311 public void setTreeSelectedTopic(String selectedNotifyTopic) {
312 this.selectedNotifyTopics = selectedNotifyTopic;
313 }
314
315 @StrutsTagAttribute(description="Deprecated. Use 'expandedNotifyTopics' instead.")
316 public void setTreeExpandedTopics(String expandedNotifyTopic) {
317 this.expandedNotifyTopics = expandedNotifyTopic;
318 }
319
320 @StrutsTagAttribute(description="Deprecated. Use 'collapsedNotifyTopics' instead.")
321 public void setTreeCollapsedTopics(String collapsedNotifyTopic) {
322 this.collapsedNotifyTopics = collapsedNotifyTopic;
323 }
324
325 public String getRootNode() {
326 return rootNodeAttr;
327 }
328
329 @StrutsTagAttribute(description="The rootNode property.")
330 public void setRootNode(String rootNode) {
331 this.rootNodeAttr = rootNode;
332 }
333
334 public String getChildCollectionProperty() {
335 return childCollectionProperty;
336 }
337
338 @StrutsTagAttribute(description="The childCollectionProperty property.")
339 public void setChildCollectionProperty(String childCollectionProperty) {
340 this.childCollectionProperty = childCollectionProperty;
341 }
342
343 public String getNodeTitleProperty() {
344 return nodeTitleProperty;
345 }
346
347 @StrutsTagAttribute(description="The nodeTitleProperty property.")
348 public void setNodeTitleProperty(String nodeTitleProperty) {
349 this.nodeTitleProperty = nodeTitleProperty;
350 }
351
352 public String getNodeIdProperty() {
353 return nodeIdProperty;
354 }
355
356 @StrutsTagAttribute(description="The nodeIdProperty property.")
357 public void setNodeIdProperty(String nodeIdProperty) {
358 this.nodeIdProperty = nodeIdProperty;
359 }
360
361 @StrutsTagAttribute(description="The showRootGrid property (default true).")
362 public void setShowRootGrid(String showRootGrid) {
363 this.showRootGrid = showRootGrid;
364 }
365
366 public String getShowRootGrid() {
367 return showRootGrid;
368 }
369
370 public String getBlankIconSrc() {
371 return blankIconSrc;
372 }
373
374 @StrutsTagAttribute(description="Blank icon image source.")
375 public void setBlankIconSrc(String blankIconSrc) {
376 this.blankIconSrc = blankIconSrc;
377 }
378
379 public String getExpandIconSrcMinus() {
380 return expandIconSrcMinus;
381 }
382
383 @StrutsTagAttribute(description="Expand icon (-) image source.")
384 public void setExpandIconSrcMinus(String expandIconSrcMinus) {
385 this.expandIconSrcMinus = expandIconSrcMinus;
386 }
387
388 public String getExpandIconSrcPlus() {
389 return expandIconSrcPlus;
390 }
391
392 @StrutsTagAttribute(description="Expand Icon (+) image source.")
393 public void setExpandIconSrcPlus(String expandIconSrcPlus) {
394 this.expandIconSrcPlus = expandIconSrcPlus;
395 }
396
397 public String getGridIconSrcC() {
398 return gridIconSrcC;
399 }
400
401 @StrutsTagAttribute(description="Image source for under child item child icons.")
402 public void setGridIconSrcC(String gridIconSrcC) {
403 this.gridIconSrcC = gridIconSrcC;
404 }
405
406 public String getGridIconSrcL() {
407 return gridIconSrcL;
408 }
409
410
411 @StrutsTagAttribute(description=" Image source for last child grid.")
412 public void setGridIconSrcL(String gridIconSrcL) {
413 this.gridIconSrcL = gridIconSrcL;
414 }
415
416 public String getGridIconSrcP() {
417 return gridIconSrcP;
418 }
419
420 @StrutsTagAttribute(description="Image source for under parent item child icons.")
421 public void setGridIconSrcP(String gridIconSrcP) {
422 this.gridIconSrcP = gridIconSrcP;
423 }
424
425 public String getGridIconSrcV() {
426 return gridIconSrcV;
427 }
428
429 @StrutsTagAttribute(description="Image source for vertical line.")
430 public void setGridIconSrcV(String gridIconSrcV) {
431 this.gridIconSrcV = gridIconSrcV;
432 }
433
434 public String getGridIconSrcX() {
435 return gridIconSrcX;
436 }
437
438 @StrutsTagAttribute(description="Image source for grid for sole root item.")
439 public void setGridIconSrcX(String gridIconSrcX) {
440 this.gridIconSrcX = gridIconSrcX;
441 }
442
443 public String getGridIconSrcY() {
444 return gridIconSrcY;
445 }
446
447 @StrutsTagAttribute(description="Image source for grid for last root item.")
448 public void setGridIconSrcY(String gridIconSrcY) {
449 this.gridIconSrcY = gridIconSrcY;
450 }
451
452 public String getIconHeight() {
453 return iconHeight;
454 }
455
456
457 @StrutsTagAttribute(description="Icon height", defaultValue="18px")
458 public void setIconHeight(String iconHeight) {
459 this.iconHeight = iconHeight;
460 }
461
462 public String getIconWidth() {
463 return iconWidth;
464 }
465
466 @StrutsTagAttribute(description="Icon width", defaultValue="19px")
467 public void setIconWidth(String iconWidth) {
468 this.iconWidth = iconWidth;
469 }
470
471
472
473 public String getTemplateCssPath() {
474 return templateCssPath;
475 }
476
477 @StrutsTagAttribute(description="Template css path", defaultValue="{contextPath}/struts/tree.css.")
478 public void setTemplateCssPath(String templateCssPath) {
479 this.templateCssPath = templateCssPath;
480 }
481
482 public String getToggleDuration() {
483 return toggleDuration;
484 }
485
486 @StrutsTagAttribute(description="Toggle duration in milliseconds", defaultValue="150")
487 public void setToggleDuration(String toggleDuration) {
488 this.toggleDuration = toggleDuration;
489 }
490
491 public String getShowGrid() {
492 return showGrid;
493 }
494
495 @StrutsTagAttribute(description="Show grid", type="Boolean", defaultValue="true")
496 public void setShowGrid(String showGrid) {
497 this.showGrid = showGrid;
498 }
499
500 @StrutsTagAttribute(description="The css class to use for element")
501 public void setCssClass(String cssClass) {
502 super.setCssClass(cssClass);
503 }
504
505 @StrutsTagAttribute(description="The css style to use for element")
506 public void setCssStyle(String cssStyle) {
507 super.setCssStyle(cssStyle);
508 }
509
510 @StrutsTagAttribute(description="The id to use for the element")
511 public void setId(String id) {
512 super.setId(id);
513 }
514
515 @StrutsTagAttribute(description="The name to set for element")
516 public void setName(String name) {
517 super.setName(name);
518 }
519
520 @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" +
521 " is collapsed. An object with a 'node' property will be passed as parameter to the topics.")
522 public void setCollapsedNotifyTopics(String collapsedNotifyTopics) {
523 this.collapsedNotifyTopics = collapsedNotifyTopics;
524 }
525
526 @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" +
527 " is expanded. An object with a 'node' property will be passed as parameter to the topics.")
528 public void setExpandedNotifyTopics(String expandedNotifyTopics) {
529 this.expandedNotifyTopics= expandedNotifyTopics;
530 }
531
532 @StrutsTagAttribute(description="Comma separated lis of topics to be published when a node" +
533 " is selected. An object with a 'node' property will be passed as parameter to the topics.")
534 public void setSelectedNotifyTopics(String selectedNotifyTopics) {
535 this.selectedNotifyTopics = selectedNotifyTopics;
536 }
537
538 @StrutsTagAttribute(description="Url used to load the list of children nodes for an specific node, whose id will be " +
539 "passed as a parameter named 'nodeId' (empty for root)")
540 public void setHref(String href) {
541 this.href = href;
542 }
543
544 @StrutsTagAttribute(description="Comma delimmited list of topics that will published after the request(if the request fails)." +
545 "Only valid if 'href' is set")
546 public void setErrorNotifyTopics(String errorNotifyTopics) {
547 this.errorNotifyTopics = errorNotifyTopics;
548 }
549 }
550
551