KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > tags > tree > Tree


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.tags.tree;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import org.apache.beehive.netui.pageflow.requeststate.INameable;
23 import org.apache.beehive.netui.pageflow.requeststate.NameService;
24 import org.apache.beehive.netui.script.ExpressionUpdateException;
25 import org.apache.beehive.netui.script.IllegalExpressionException;
26 import org.apache.beehive.netui.tags.*;
27 import org.apache.beehive.netui.tags.html.HtmlConstants;
28 import org.apache.beehive.netui.tags.javascript.CoreScriptFeature;
29 import org.apache.beehive.netui.tags.javascript.IScriptReporter;
30 import org.apache.beehive.netui.tags.javascript.ScriptRequestState;
31 import org.apache.beehive.netui.tags.rendering.AbstractHtmlState;
32 import org.apache.beehive.netui.tags.rendering.DivTag;
33 import org.apache.beehive.netui.tags.rendering.StringBuilderRenderAppender;
34 import org.apache.beehive.netui.tags.rendering.TagRenderingBase;
35 import org.apache.beehive.netui.util.Bundle;
36
37 import javax.servlet.http.HttpServletRequest JavaDoc;
38 import javax.servlet.http.HttpServletResponse JavaDoc;
39 import javax.servlet.jsp.JspException JavaDoc;
40 import javax.servlet.jsp.PageContext JavaDoc;
41 import java.io.IOException JavaDoc;
42
43
44 /**
45  * Netui tag that renders a tree control represented by a set of
46  * <code>TreeElement</code> objects.
47  * @jsptagref.tagdescription Renders a navigable tree of {@link TreeElement}
48  * objects.
49  *
50  * <p>The tree is bound to a variable through the <code>dataSource</code> attribute.
51  * If the bound variable has been initialized, then the body content of this tag is not
52  * processed and the dataSource's version of the tree is rendered. If the bound variable
53  * has not been initialized, we will process the body, create the <code>TreeElement</code>
54  * tree structure, and set the bound variable with the newly created tree.
55  *
56  * A &lt;netui:tree> tag cannot be nested within another &lt;netui:tree> element.
57  *
58  * <p>This tag can automatically handle display icons for the tree nodes
59  * through the <code>imageRoot</code> attribute. If you point the
60  * <code>imageRoot</code> attribute at a folder containing appropriately
61  * named image files, the correct images will be used for any given state
62  * of the tree's nodes. The default image names are:
63  *
64  * <blockquote>
65  * <ul>
66  * <li>folder.gif</li>
67  * <li>lastLineJoin.gif</li>
68  * <li>lastNodeCollapsed.gif</li>
69  * <li>lastNodeExpanded.gif</li>
70  * <li>lineJoin.gif</li>
71  * <li>nodeCollapsed.gif</li>
72  * <li>nodeExpanded.gif</li>
73  * <li>rootCollapsed.gif</li>
74  * <li>rootExpanded.gif</li>
75  * <li>spacer.gif</li>
76  * <li>verticalLine.gif</li>
77  * </ul>
78  * </blockquote>
79  *
80  * @example The following example shows a &lt;netui:tree> tag with a set of
81  * children &lt;netui:treeLabel> and &lt;netui:treeItem> tags that form the
82  * tree's navigational structure. The <code>dataSource</code> attribute
83  * identifies the {@link TreeElement} in the appropriate binding context; in this case,
84  * the page flow context is used. The <code>selectionAction</code> attribute
85  * is required so there can be a postback to the tree. <code>tagId</code> is
86  * used to uniquely identify a tree on the page.
87  *
88  * <pre> &lt;netui:tree
89  * dataSource="pageFlow.myTree"
90  * selectionAction="postback"
91  * tagId="myTree">
92  * &lt;netui:treeItem expanded="true" >
93  * &lt;netui:treeLabel>Root Folder&lt;/netui:treeLabel>
94  * &lt;netui:treeItem expanded="false">
95  * &lt;netui:treeLabel>I&lt;/netui:treeLabel>
96  * &lt;netui:treeItem expanded="false">
97  * &lt;netui:treeLabel>A&lt;/netui:treeLabel>
98  * &lt;netui:treeItem>1&lt;/netui:treeItem>
99  * &lt;netui:treeItem>2&lt;/netui:treeItem>
100  * &lt;/netui:treeItem>
101  * &lt;/netui:treeItem>
102  * &lt;/netui:treeItem>
103  * &lt;/netui:tree></pre>
104  * @netui:tag name="tree" body-content="scriptless" description="Renders a tree control represented by a set of TreeElement objects."
105  */

106 public class Tree extends AbstractSimpleTag implements HtmlConstants,
107         IAttributeConsumer, IErrorCollector
108 {
109     /**
110      * The name of the directory containing the images for our icons,
111      * relative to the page including this tag.
112      */

113     private TreeElement _rootNode = null;
114
115     private TreeRenderState _trs;
116
117     // The new style and class attributes
118
private String JavaDoc _treeStyle; // tree style
119
private String JavaDoc _treeStyleClass; // tree class
120

121     private InternalStringBuilder _errorText; // Text of any error that may have occurred.
122

123     private String JavaDoc _dataSource = null; // The name of the tree.
124
private boolean _renderTagIdLookup = false; // cause the base javascript support to be output
125

126     private InheritableState _iState = new InheritableState();
127     private String JavaDoc _rootNodeCollapsedImage;
128     private String JavaDoc _rootNodeExpandedImage;
129
130     // These are used in a stateless manner. They do not have to be cleared
131
// in the local release because each state is cleared before it is set to write a start tag.
132
private DivTag.State _divState = new DivTag.State();
133
134     private ExpressionHandling _expr;
135
136     public Tree()
137     {
138         _trs = new TreeRenderState();
139         _iState.initalizeTreeState();
140     }
141
142     /**
143      * Return the name of the Tag.
144      */

145     public String JavaDoc getTagName()
146     {
147         return "Tree";
148     }
149
150     /**
151      * Sets the action used for expanding and contracting tree nodes. This action will be
152      * inherited by the <code>TreeElements</code> inside the tree.
153      * @param action the action
154      * @jsptagref.attributedescription Sets the action used for expanding and contracting tree nodes.
155      * @jsptagref.databindable false
156      * @jsptagref.attributesyntaxvalue <i>string_action</i>
157      * @netui:attribute required="false" rtexprvalue="true"
158      * description="Sets the action used for expanding and contracting tree nodes."
159      */

160     public void setExpansionAction(String JavaDoc action)
161             throws JspException JavaDoc
162     {
163         _iState.setExpansionAction(setRequiredValueAttribute(action, "expansionAction"));
164     }
165
166     /**
167      * Sets the action used for selecting tree nodes. This action will be
168      * inherited by the <code>TreeElements</code> inside the tree.
169      * @param action the action
170      * @jsptagref.attributedescription Sets the action used when a tree node is selected.
171      * @jsptagref.databindable false
172      * @jsptagref.attributesyntaxvalue <i>string_action</i>
173      * @netui:attribute required="true" rtexprvalue="true"
174      * description="Sets the action used when a tree node is selected."
175      */

176     public void setSelectionAction(String JavaDoc action)
177             throws JspException JavaDoc
178     {
179         _iState.setSelectionAction(setRequiredValueAttribute(action, "selectionAction"));
180     }
181
182     /**
183      * Return the action for selection action on the tree. This action will be called
184      * when a TreeElement is selected.
185      * @return the selection action name.
186      */

187     public String JavaDoc getSelectionAction()
188     {
189         return _iState.getSelectionAction();
190     }
191
192     /**
193      * Sets the target for a selection action. This can specify the name
194      * of the frame where the document is to be opened.
195      * @param target the target for selection
196      * @jsptagref.attributedescription Sets the frame target used for selecting tree nodes.
197      * @jsptagref.databindable false
198      * @jsptagref.attributesyntaxvalue <i>string_target</i>
199      * @netui:attribute rtexprvalue="true"
200      * description="Sets the frame target used for selecting tree nodes."
201      */

202     public void setSelectionTarget(String JavaDoc target)
203     {
204         _iState.setSelectionTarget(setNonEmptyValueAttribute(target));
205     }
206
207
208     /**
209      * Set the ID of the tag. This is required and will not generate the
210      * standard JavaScript lookup code unless <code>RenderTagIdLookup</code>
211      * is set to <code>true</code>.
212      * @param tagId the tagId.
213      * @jsptagref.attributedescription Set the id of the tree. This appears on the containing &lt;div>.
214      * @jsptagref.databindable false
215      * @jsptagref.attributesyntaxvalue <i>string_tagId</i>
216      * @netui:attribute required="true" rtexprvalue="true"
217      * description="Set the id of the tree. This appears on the containing &lt;div>."
218      */

219     public void setTagId(String JavaDoc tagId)
220             throws JspException JavaDoc
221     {
222         _trs.tagId = setRequiredValueAttribute(tagId, "tagId");
223     }
224
225     /**
226      * Sets the image name for an open non-leaf node with no
227      * line below it. (Defaults to "lastNodeExpanded.gif").
228      * @param lastNodeExpandedImage the image name (including extension)
229      * @jsptagref.attributedescription The image name for an open non-leaf node with no line below it. (Defaults to "lastNodeExpanded.gif".)
230      * @jsptagref.databindable false
231      * @jsptagref.attributesyntaxvalue <i>string_imageHandleDownLast</i>
232      * @netui:attribute required="false" rtexprvalue="true"
233      * description="Sets the image name for an open non-leaf node with no
234      * line below it."
235      */

236     public void setLastNodeExpandedImage(String JavaDoc lastNodeExpandedImage)
237     {
238         String JavaDoc val = setNonEmptyValueAttribute(lastNodeExpandedImage);
239         if (val != null)
240             _iState.setLastNodeExpandedImage(setNonEmptyValueAttribute(val));
241     }
242
243     /**
244      * Sets the image name for an open non-leaf node with a
245      * line below it. (Defaults to "nodeExpanded.gif").
246      * @param nodeExpandedImage the image name (including extension)
247      * @jsptagref.attributedescription The image name for an open non-leaf node with a
248      * line below it. (Defaults to "nodeExpanded.gif".)
249      * @jsptagref.databindable false
250      * @jsptagref.attributesyntaxvalue <i>string_imageHandleDownMiddle</i>
251      * @netui:attribute required="false" rtexprvalue="true"
252      * description="Sets the image name for an open non-leaf node with a
253      * line below it."
254      */

255     public void setNodeExpandedImage(String JavaDoc nodeExpandedImage)
256     {
257         String JavaDoc val = setNonEmptyValueAttribute(nodeExpandedImage);
258         if (val != null)
259             _iState.setNodeExpandedImage(setNonEmptyValueAttribute(val));
260     }
261
262     /**
263      * Sets the image name for a closed non-leaf node with no
264      * line below it. (Defaults to "lastNodeCollapsed.gif").
265      * @param lastNodeCollapsedImage the image name (including extension)
266      * @jsptagref.attributedescription The image name for a closed non-leaf node with no
267      * line below it. (Defaults to "lastNodeCollapsed.gif".)
268      * @jsptagref.databindable false
269      * @jsptagref.attributesyntaxvalue <i>string_imageHandleRightLast</i>
270      * @netui:attribute required="false" rtexprvalue="true"
271      * description="Sets the image name for a closed non-leaf node with no
272      * line below it."
273      */

274     public void setLastNodeCollapsedImage(String JavaDoc lastNodeCollapsedImage)
275     {
276         String JavaDoc val = setNonEmptyValueAttribute(lastNodeCollapsedImage);
277         if (val != null)
278             _iState.setLastNodeCollapsedImage(setNonEmptyValueAttribute(val));
279     }
280
281     /**
282      * Sets the image name for a closed non-leaf node with a
283      * line below it. (Defaults to "nodeCollapsed.gif").
284      * @param nodeCollapsedImage the image name (including extension)
285      * @jsptagref.attributedescription The image name for a closed non-leaf node with a
286      * line below it. (Defaults to "nodeCollapsed.gif".)
287      * @jsptagref.databindable false
288      * @jsptagref.attributesyntaxvalue <i>string_imageHandleRightMiddle</i>
289      * @netui:attribute required="false" rtexprvalue="true"
290      * description="Sets the image name for a closed non-leaf node with a
291      * line below it."
292      */

293     public void setNodeCollapsedImage(String JavaDoc nodeCollapsedImage)
294     {
295         String JavaDoc val = setNonEmptyValueAttribute(nodeCollapsedImage);
296         if (val != null)
297             _iState.setNodeCollapsedImage(setNonEmptyValueAttribute(val));
298     }
299
300     /**
301      * Sets the image name for a blank area of the tree.
302      * (Defaults to "lastLineJoin.gif").
303      * @param lastLineJoinImage the image name (including extension)
304      * @jsptagref.attributedescription The image name for a blank area of the tree.
305      * (Defaults to "lastLineJoin.gif")
306      * @jsptagref.databindable false
307      * @jsptagref.attributesyntaxvalue <i>string_imageLineLast</i>
308      * @netui:attribute required="false" rtexprvalue="true"
309      * description="Sets the image name for a blank area of the tree."
310      */

311     public void setLastLineJoinImage(String JavaDoc lastLineJoinImage)
312     {
313         String JavaDoc val = setNonEmptyValueAttribute(lastLineJoinImage);
314         if (val != null)
315             _iState.setLastLineJoinImage(setNonEmptyValueAttribute(val));
316     }
317
318     /**
319      * Sets the default icon for TreeElements for a blank area of the tree.
320      * (Defaults to "folder.gif").
321      * @param itemIcon the image name of the itemIcon
322      * @jsptagref.attributedescription Sets the default icon for TreeElements for a blank area of the tree.
323      * (Defaults to "folder.gif").
324      * @jsptagref.databindable false
325      * @jsptagref.attributesyntaxvalue <i>string_itemIcon</i>
326      * @netui:attribute required="false" rtexprvalue="true"
327      * description="Sets the default icon for TreeElements for a blank area of the tree."
328      */

329     public void setItemIcon(String JavaDoc itemIcon)
330     {
331         String JavaDoc val = setNonEmptyValueAttribute(itemIcon);
332         if (val != null)
333             _iState.setItemIcon(setNonEmptyValueAttribute(val));
334     }
335
336     /**
337      * Sets the image name for an area with a line through it.
338      * (Defaults to "lineJoin.gif").
339      * @param lineJoinImage the image name (including extension)
340      * @jsptagref.attributedescription The image name for an area with a line through it.
341      * (Defaults to "lineJoin.gif").
342      * @jsptagref.databindable false
343      * @jsptagref.attributesyntaxvalue <i>string_imageLineMiddle</i>
344      * @netui:attribute required="false" rtexprvalue="true"
345      * description="Sets the image name for an area with a line through it."
346      */

347     public void setLineJoinImage(String JavaDoc lineJoinImage)
348     {
349         String JavaDoc val = setNonEmptyValueAttribute(lineJoinImage);
350         if (val != null)
351             _iState.setLineJoinImage(setNonEmptyValueAttribute(val));
352     }
353
354     /**
355      * Sets the image name for an area with a line through it.
356      * (Defaults to "verticalLine.gif").
357      * @param verticalLineImage the image name (including extension)
358      * @jsptagref.attributedescription The image name for an area with a line through it.
359      * (Defaults to "verticalLine.gif").
360      * @jsptagref.databindable false
361      * @jsptagref.attributesyntaxvalue <i>string_imageLIneVertical</i>
362      * @netui:attribute required="false" rtexprvalue="true"
363      * description="Sets the image name for an area with a line through it."
364      */

365     public void setVerticalLineImage(String JavaDoc verticalLineImage)
366     {
367         String JavaDoc val = setNonEmptyValueAttribute(verticalLineImage);
368         if (val != null)
369             _iState.setVerticalLineImage(setNonEmptyValueAttribute(val));
370     }
371
372     /**
373      * Sets the name of the directory containing the images. This should be specified
374      * absolutely within the webapp. This target will provide images for the structure of
375      * the tree. If the <code>iconRoot</code> is not set, then this will also specify where
376      * the icons come are found.
377      * @param imageRoot the directory name
378      * @jsptagref.attributedescription The directory containing the images for tree icons.
379      * @jsptagref.databindable false
380      * @jsptagref.attributesyntaxvalue <i>string_imageRoot</i>
381      * @netui:attribute required="false" rtexprvalue="true"
382      * description="Sets the name of the directory containing the images for our icons,
383      * and structure of the tree."
384      */

385     public void setImageRoot(String JavaDoc imageRoot)
386     {
387         _iState.setImageRoot(setNonEmptyValueAttribute(imageRoot));
388     }
389
390     /**
391      * This will set the location of the icon images. When the location
392      * is explicitly set, this works exactly the same as all other inheritable
393      * properties. When this is not set, it will return the <code>getImageRoot</code>
394      * location.
395      * @param iconRoot the directory name for the icons
396      * @jsptagref.attributedescription The directory containing the icon images for tree items.
397      * @jsptagref.databindable false
398      * @jsptagref.attributesyntaxvalue <i>string_iconRoot</i>
399      * @netui:attribute required="false" rtexprvalue="true"
400      * description="Sets the name of the directory containing the images for our icons."
401      */

402     public void setIconRoot(String JavaDoc iconRoot)
403     {
404         _iState.setIconRoot(iconRoot);
405     }
406
407     /**
408      * Sets the image that will be used for the root when it is Collapsed. The root must implement
409      * ITreeRootElement to support this. (Defaults to "rootCollapsed.gif").
410      * @param rootNodeCollapsedImage the image representing a root that is collapsed.
411      * @jsptagref.attributedescription The image representing the root when it is collapsed.
412      * (Defaults to "rootCollapsed.gif").
413      * @jsptagref.databindable true
414      * @jsptagref.attributesyntaxvalue <i>string_rootNodeCollapsedImage</i>
415      * @netui:attribute required="false" rtexprvalue="true"
416      * description="Sets the image representing the root when it is collapsed."
417      */

418     public void setRootNodeCollapsedImage(String JavaDoc rootNodeCollapsedImage)
419     {
420         _rootNodeCollapsedImage = setNonEmptyValueAttribute(rootNodeCollapsedImage);
421     }
422
423     /**
424      * Sets the image that will be used for the root when it is Expanded. The root must implement
425      * ITreeRootElement to support this. (Defaults to "rootExpanded.gif").
426      * @param rootNodeExpandedImage the image representing a root that is expanded.
427      * @jsptagref.attributedescription The image representing the root when it is expanded.
428      * (Defaults to "rootExpanded.gif").
429      * @jsptagref.databindable true
430      * @jsptagref.attributesyntaxvalue <i>string_rootNodeExpandedImage</i>
431      * @netui:attribute required="false" rtexprvalue="true"
432      * description="Sets the image representing the root when it is expanded."
433      */

434     public void setRootNodeExpandedImage(String JavaDoc rootNodeExpandedImage)
435     {
436         _rootNodeExpandedImage = setNonEmptyValueAttribute(rootNodeExpandedImage);
437     }
438
439     /**
440      * Cause expansion and contraction on the client. When this is set, the
441      * expand and collapse events will be handled on the client. TreeElements which are hidden
442      * becauses other TreeElements are collapsed will be rendered to the page and then displayed
443      * by JavaScript on the page. These expansion and contraction events will not call
444      * the server's expansion action.
445      * @param runAtClient
446      * @jsptagref.attributedescription Indicates whether that base expand and contraction will happen
447      * on the client.
448      * @jsptagref.databindable false
449      * @jsptagref.attributesyntaxvalue <i>boolean_runAtClient</i>
450      * @netui:attribute required="false" rtexprvalue="false" type="boolean"
451      * description="Indicates whether that base expand and contraction will happen on the client."
452      */

453     public void setRunAtClient(boolean runAtClient)
454     {
455         _trs.runAtClient = runAtClient;
456     }
457
458     /**
459      * This attribue will cause the content of labels to be escaped when the value if <i>true</i>.
460      * The default value is <i>false</i>.
461      * @param htmlEscape
462      * @jsptagref.attributedescription When true the content of labels will be escaped for HTML.
463      * @jsptagref.databindable false
464      * @jsptagref.attributesyntaxvalue <i>boolean_htmlEscape</i>
465      * @netui:attribute required="false" type="boolean"
466      * description="When true the content of labels will be escaped for HTML."
467      */

468     public void setEscapeForHtml(boolean htmlEscape)
469     {
470         _trs.escapeContent = htmlEscape;
471     }
472
473     /**
474      * This will cause the standard tagId to Id JavaScript to be output. For most
475      * of the HTML tags this is automatically output. For the tree, because the tagId
476      * is a required attribute, we make javascript support optional.
477      * @param renderTagIdLookup
478      * @jsptagref.attributedescription Output the standard tagId to Id JavaScript.
479      * @jsptagref.databindable false
480      * @jsptagref.attributesyntaxvalue <i>boolean_renderTagIdLookup</i>
481      * @netui:attribute required="false" type="boolean"
482      * description="Output the standard tagId to Id JavaScript."
483      */

484     public void setRenderTagIdLookup(boolean renderTagIdLookup)
485     {
486         _renderTagIdLookup = renderTagIdLookup;
487     }
488
489     /**
490      * Sets the root <code>TreeElement</code> of this tree.
491      * @param rootNode the root treeNode
492      */

493     public void setRootNode(TreeElement rootNode)
494     {
495         _rootNode = rootNode;
496         if (rootNode.getName() == null) {
497             rootNode.setName("0");
498         }
499     }
500
501     /**
502      * Return the root node of the tree.
503      * @return returns the root node of the tree.
504      */

505     public TreeElement getRootNode()
506     {
507         return _rootNode;
508     }
509
510     /**
511      * Set the style of a tree element when is is selected. This results in a <code>style</code>
512      * attribute being generated for this tree node.
513      * @param selectedStyle
514      * @jsptagref.attributedescription Set the style of a tree element when is is selected. This results in a
515      * <code>style</code> attribute being generated for this tree node.
516      * @jsptagref.databindable false
517      * @jsptagref.attributesyntaxvalue <i>string_selectedStyle</i>
518      * @netui:attribute required="false" rtexprvalue="true"
519      * description="Set the style of a tree element when is is selected. This results in a <code>style</code>
520      * attribute being generated for this tree node."
521      */

522     public void setSelectedStyle(String JavaDoc selectedStyle)
523     {
524         _trs.selectedStyle = setNonEmptyValueAttribute(selectedStyle);
525     }
526
527     /**
528      * Set the style class of a tree element when is is disabled. A disabled element will have
529      * a style that can be expanded/contracted, but may not be selected.
530      * @param disableStyleClass
531      * @jsptagref.attributedescription Set the style class of a tree element when is is disabled. A
532      * disabled element will have a style that may be expanded/contracted, but may not be selected.
533      * @jsptagref.databindable false
534      * @jsptagref.attributesyntaxvalue <i>string_disableStyleClass</i>
535      * @netui:attribute required="false" rtexprvalue="true"
536      * description="Set the style class of a tree element when is is disabled. A disabled element will have
537      * a style that can be expanded/contracted, but may not be selected."
538      */

539
540     public void setDisabledStyleClass(String JavaDoc disableStyleClass)
541     {
542         _trs.disabledStyleClass = setNonEmptyValueAttribute(disableStyleClass);
543     }
544
545     /**
546      * Set the style of a tree element when is is disabled. A disabled element will have
547      * a style that can be expanded/contracted, but may not be selected.
548      * @param disabledStyle
549      * @jsptagref.attributedescription Set the style of a tree element when is is disabled. A
550      * disabled element will have a style that can be expanded/contracted, but may not be selected.
551      * @jsptagref.databindable false
552      * @jsptagref.attributesyntaxvalue <i>string_disableStyle</i>
553      * @netui:attribute required="false" rtexprvalue="true"
554      * description="Set the style of a tree element when is is disabled. A disabled element will have
555      * a style that can be expanded/contracted, but may not be selected."
556      */

557     public void setDisabledStyle(String JavaDoc disabledStyle)
558     {
559         _trs.disabledStyle = setNonEmptyValueAttribute(disabledStyle);
560     }
561
562     /**
563      * Set the style class of a tree element when is is selected. This results in a <code>class</code>
564      * attribute being generated for this tree node.
565      * @param selectedStyleClass
566      * @jsptagref.attributedescription Set the style class of a tree element when is is selected. This
567      * results in a <code>class</code> attribute being generated for this tree node.
568      * @jsptagref.databindable false
569      * @jsptagref.attributesyntaxvalue <i>string_selectedStyleClass</i>
570      * @netui:attribute required="false" rtexprvalue="true"
571      * description="Set the style class of a tree element when is is selected. This results in a <code>class</code>
572      * attribute being generated for this tree node."
573      */

574     public void setSelectedStyleClass(String JavaDoc selectedStyleClass)
575     {
576         _trs.selectedStyleClass = setNonEmptyValueAttribute(selectedStyleClass);
577     }
578
579     /**
580      * Set the style class of a tree element when is is not selected. This results in a <code>style</code>
581      * attribute being generated for this tree node.
582      * @param unselectedStyle
583      * @jsptagref.attributedescription Set the style of a tree element when is is not selected. This
584      * results in a <code>style</code> attribute being generated for this tree node.
585      * @jsptagref.databindable false
586      * @jsptagref.attributesyntaxvalue <i>string_unselectedStyle</i>
587      * @netui:attribute required="false" rtexprvalue="true"
588      * description="Set the style of a tree element when is is not selected. This results in a <code>style</code>
589      * attribute being generated for this tree node."
590      */

591     public void setUnselectedStyle(String JavaDoc unselectedStyle)
592     {
593         _trs.unselectedStyle = setNonEmptyValueAttribute(unselectedStyle);
594     }
595
596     /**
597      * Set the style class of a tree element when is is selected. This results in a <code>class</code>
598      * attribute being generated for this tree node.
599      * @param unselectedStyleClass
600      * @jsptagref.attributedescription Set the style class of a tree element when is is not selected. This
601      * results in a <code>style</code> attribute being generated for this tree node.
602      * @jsptagref.databindable false
603      * @jsptagref.attributesyntaxvalue <i>string_unselectedStyleClasss</i>
604      * @netui:attribute required="false" rtexprvalue="true"
605      * description="Set the style class of a tree element when is is selected. This results in a <code>class</code>
606      * attribute being generated for this tree node."
607      */

608     public void setUnselectedStyleClass(String JavaDoc unselectedStyleClass)
609     {
610         _trs.unselectedStyleClass = setNonEmptyValueAttribute(unselectedStyleClass);
611     }
612
613     /**
614      * Sets the <code>style</code> attribute of the tree.
615      * @param treeStyle the style
616      * @jsptagref.attributedescription Sets the <code>style</code> attribute of the tree.
617      * @jsptagref.databindable false
618      * @jsptagref.attributesyntaxvalue <i>string_treeStyle</i>
619      * @netui:attribute required="false" rtexprvalue="true"
620      * description="Sets the <code>style</code> attribute of the tree."
621      */

622     public void setTreeStyle(String JavaDoc treeStyle)
623     {
624         _treeStyle = setNonEmptyValueAttribute(treeStyle);
625     }
626
627     /**
628      * Sets the <code>class</code> attribute of the tree. This will be set
629      * on the containing &lt;div> for the tree.
630      * @param treeStyleClass the style
631      * @jsptagref.attributedescription Sets the <code>class</code> attribute of the tree.
632      * @jsptagref.databindable false
633      * @jsptagref.attributesyntaxvalue <i>string_treeStyleClass</i>
634      * @netui:attribute required="false" rtexprvalue="true"
635      * description="Sets the <code>class</code> attribute of the tree."
636      */

637     public void setTreeStyleClass(String JavaDoc treeStyleClass)
638     {
639         _treeStyleClass = setNonEmptyValueAttribute(treeStyleClass);
640     }
641
642     /**
643      * Sets an expression which indentifies the TreeElement that represents the root of
644      * the tree. When the variable being bound to is not null, the body of the Tree
645      * will be ignored and the tree being bound to will be rendered. If the variable
646      * being bound to is null, then the body of the tree will be processed to create
647      * the initial tree state and the bound variable will be set. In this situation
648      * the property must support both read and write.
649      * @param dataSource the tree attribute name
650      * @jsptagref.attributedescription sets an expression which indentifies the TreeElement
651      * that represents the root of the tree.
652      * @jsptagref.databindable true
653      * @jsptagref.attributesyntaxvalue <i>string_dataSource</i>
654      * @netui:attribute required="true"
655      * description="Sets an expression which indentifies the TreeElement that represents the root of
656      * the tree."
657      */

658     public void setDataSource(String JavaDoc dataSource)
659     {
660         _dataSource = dataSource;
661     }
662
663     /**
664      * Set an attribute value on the implementing class. The <code>name</code> represents
665      * the name of the attribute. The <code>value</code> represents the value and may contains
666      * an expression. The <code>facet</code> is optional and may be used by complex types to
667      * target the attribute to a sub part of the generated markup. This method may result in errors
668      * being generated.
669      * @param name The name of the attribute. This value may not be null or the empty string.
670      * @param value The value of the attribute. This may contain an expression.
671      * @param facet The name of a facet to which the attribute will be applied. This is optional.
672      * @throws javax.servlet.jsp.JspException A JspException may be thrown if there is an error setting the attribute.
673      */

674     public void setAttribute(String JavaDoc name, String JavaDoc value, String JavaDoc facet)
675             throws JspException JavaDoc
676     {
677         // validate the name attribute, in the case of an error simply return.
678
if (name == null || name.length() <= 0) {
679             String JavaDoc s = Bundle.getString("Tags_AttributeNameNotSet");
680             registerTagError(s, null);
681             return;
682         }
683         // it's not legal to set the id or name attributes this way
684
if (name != null && (name.equals("netui:treeName"))) {
685             String JavaDoc s = Bundle.getString("Tags_AttributeMayNotBeSet", new Object JavaDoc[]{name});
686             registerTagError(s, null);
687             return;
688         }
689
690         _divState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, name, value);
691     }
692
693     /**
694      * Prepare the Tree for rendering.
695      * @throws JspException if a JSP exception has occurred
696      */

697     public void doTag()
698             throws JspException JavaDoc, IOException JavaDoc
699     {
700         if (hasErrors()) {
701             reportErrors();
702             return;
703         }
704
705         // See if there is a TreeRoot already defined.
706
_expr = new ExpressionHandling(this);
707         TreeElement root = null;
708         try {
709             root = getTreeRoot(_expr);
710         }
711         catch (IllegalExpressionException iee) {
712             String JavaDoc s = Bundle.getString("TreeRootError", new Object JavaDoc[]{_dataSource, iee.getMessage()});
713             registerTagError(s, null);
714             return;
715         }
716         if (hasErrors()) {
717             reportErrors();
718             return;
719         }
720
721         // If we don't have a root element, then we need to create it by processing the body which contains
722
// /*<TreeItems>*/ tags that define the tree.
723
if (root == null) {
724             getBufferBody(false);
725
726             // check to see if we should exit due to an error occuring
727
// write out any error text and return.
728
if (_errorText != null) {
729                 write(_errorText.toString());
730                 if (hasErrors())
731                     reportErrors();
732             }
733         }
734
735         // Set the image Root if it is not set.
736
PageContext JavaDoc pageContext = getPageContext();
737         if (_iState.getImageRoot() == null)
738             _iState.setImageRoot(((HttpServletRequest JavaDoc) pageContext.getRequest()).getContextPath() + "/" +
739                     TagConfig.getTreeImageLocation());
740
741         // errors should have been caught above
742
TreeElement treeRoot = getTreeRoot(_expr);
743
744         // if the tree root hasn't been defined, then we need to update the what the object that is
745
// pointed at by the dataSource expression.
746
if (treeRoot == null) {
747             if (_rootNode != null) {
748                 try {
749                     String JavaDoc datasource = "{" + _dataSource + "}";
750                     _expr.updateExpression(datasource, _rootNode, pageContext);
751                 }
752                 catch (ExpressionUpdateException e) {
753                     String JavaDoc s = Bundle.getString("Tags_UnableToWriteTree", new Object JavaDoc[]{_dataSource, e.getMessage()});
754                     registerTagError(s, null);
755                     reportErrors();
756                     return;
757                 }
758                 treeRoot = _rootNode;
759             }
760
761             // indicate an update error and return
762
if (treeRoot == null) {
763                 String JavaDoc s = Bundle.getString("Tags_TreeNoAttribute", _dataSource);
764                 registerTagError(s, null);
765                 reportErrors();
766                 return;
767             }
768
769         }
770
771         // set the root image
772
if (treeRoot instanceof ITreeRootElement) {
773             ITreeRootElement tre = (ITreeRootElement) treeRoot;
774             if (tre.getRootNodeExpandedImage() == null) {
775                 tre.setRootNodeExpandedImage((_rootNodeExpandedImage != null) ?
776                         _rootNodeExpandedImage : InheritableState.IMAGE_ROOT_EXPANDED);
777             }
778             if (tre.getRootNodeCollapsedImage() == null) {
779                 tre.setRootNodeCollapsedImage((_rootNodeCollapsedImage != null) ?
780                         _rootNodeCollapsedImage : InheritableState.IMAGE_ROOT_COLLAPSED);
781             }
782         }
783
784         // if we are running the tree at the client, then
785
// we need to register the tree with the NameService
786
if (_trs.runAtClient) {
787             // it's currently not legal to have a runAtClient but not be an instance of INameable which is
788
// implemented by the ITreeRootElement.
789
if (!(treeRoot instanceof INameable)) {
790                 String JavaDoc s = Bundle.getString("Tags_TreeRunAtClientRoot", null);
791                 registerTagError(s, null);
792                 reportErrors();
793                 return;
794             }
795
796             // name the tree if it hasn't been named already
797
INameable in = (INameable) treeRoot;
798             String JavaDoc o = in.getObjectName();
799             if (o == null) {
800                 NameService ns = NameService.instance(pageContext.getSession());
801                 ns.nameObject("Tree", in);
802                 ns.put(in);
803             }
804         }
805
806
807         // prepare to render the tree
808
HttpServletRequest JavaDoc request = (HttpServletRequest JavaDoc) pageContext.getRequest();
809         HttpServletResponse JavaDoc response = (HttpServletResponse JavaDoc) pageContext.getResponse();
810         InternalStringBuilder sb = new InternalStringBuilder(1024);
811         StringBuilderRenderAppender writer = new StringBuilderRenderAppender(sb);
812
813         // this is the treeId from the request. If there was an tree expansion this will be
814
// non-null and it identifies what tree had the expansion request.
815
// we need to qualify the tree based upon the tagId
816
assert(_trs.tagId != null);
817         _trs.tagId = getIdForTagId(_trs.tagId);
818
819         String JavaDoc treeId = request.getParameter(TreeElement.TREE_ID);
820         if (treeId != null && _trs.tagId.equals(treeId)) {
821             TreeHelpers.processTreeRequest(treeId, treeRoot, request, response);
822         }
823
824         // check for the nodes that are expanded...
825
// Add the script support for the tree.
826
if (_trs.runAtClient) {
827             IScriptReporter sr = getScriptReporter();
828             if (sr == null) {
829                 String JavaDoc s = Bundle.getString("Tags_TreeRunAtClientSC", null);
830                 registerTagError(s, null);
831                 reportErrors();
832                 return;
833             }
834
835             ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
836             if (!srs.isFeatureWritten(CoreScriptFeature.DYNAMIC_INIT)) {
837                 String JavaDoc s = Bundle.getString("Tags_TreeHtmlRunAtClient", null);
838                 registerTagError(s, null);
839                 reportErrors();
840                 return;
841             }
842
843             assert(treeRoot instanceof ITreeRootElement);
844             ITreeRootElement tre = (ITreeRootElement) treeRoot;
845
846             Object JavaDoc[] args = new Object JavaDoc[8];
847             args[0] = _iState.getImageRoot() + "/";
848             args[1] = tre.getObjectName();
849             args[2] = _iState.getNodeCollapsedImage();
850             args[3] = _iState.getNodeExpandedImage();
851             args[4] = _iState.getLastNodeCollapsedImage();
852             args[5] = _iState.getLastNodeExpandedImage();
853             args[6] = Bundle.getString("Tags_TreeAltTextExpand", null);
854             args[7] = Bundle.getString("Tags_TreeAltTextCollapse", null);
855             srs.writeFeature(sr, writer, CoreScriptFeature.TREE_INIT, false, false, args);
856
857             tre.setTreeRenderState(_trs);
858             tre.setInheritableState(_iState);
859         }
860
861         // create a containing tree level <div> and place the tree level styles on it.
862
_divState.styleClass = _treeStyleClass;
863         _divState.style = _treeStyle;
864         String JavaDoc divId = null;
865         if (_renderTagIdLookup) {
866             _divState.id = _trs.tagId;
867             divId = _divState.id;
868         }
869
870         // if we are running on the client then we need to output the tree name into the top level tree <div> tag
871
if (_trs.runAtClient) {
872             _divState.registerAttribute(AbstractHtmlState.ATTR_GENERAL, "netui:treeName",
873                     ((INameable) treeRoot).getObjectName());
874         }
875
876         TagRenderingBase divRenderer = TagRenderingBase.Factory.getRendering(TagRenderingBase.DIV_TAG, request);
877         divRenderer.doStartTag(writer, _divState);
878         sb.append("\n");
879
880         // Render the tree.
881
AttributeRenderer extraAttrs = new AttributeRenderer();
882         TagTreeRenderer ttr = new TagTreeRenderer(this, _trs, request, response, pageContext.getServletContext());
883         ttr.render(sb, treeRoot, 0, extraAttrs, _iState);
884         if (hasErrors()) {
885             reportErrors();
886             return;
887         }
888
889         // finish the tree representation and write it
890
divRenderer.doEndTag(writer);
891         sb.append("\n");
892         write(sb.toString());
893
894         if (!(treeRoot instanceof ITreeRootElement)) {
895             boolean error = false;
896             if (_rootNodeExpandedImage != null) {
897                 String JavaDoc s = Bundle.getString("Tags_TreeRootImageError", null);
898                 registerTagError(s, null);
899                 error = true;
900             }
901             if (_rootNodeCollapsedImage != null) {
902                 String JavaDoc s = Bundle.getString("Tags_TreeRootImageError", null);
903                 registerTagError(s, null);
904                 error = true;
905             }
906             if (error) {
907                 reportErrors();
908             }
909         }
910
911         // check to see if we are writing out the java.
912
if (_renderTagIdLookup) {
913             String JavaDoc jsOut = renderDefaultJavaScript(request, divId);
914             if (jsOut != null)
915                 write(jsOut);
916         }
917     }
918
919     /**
920      * Return the <code>TreeControl</code> instance for the tree control that
921      * we are rendering.
922      * @throws JspException if no TreeControl instance can be found
923      */

924     protected TreeElement getTreeRoot(ExpressionHandling expr)
925             throws JspException JavaDoc
926     {
927         String JavaDoc datasource = "{" + _dataSource + "}";
928         Object JavaDoc treeNode = expr.evaluateExpression(datasource, "dataSource", getPageContext());
929         if (treeNode == null || hasErrors()) {
930             return null;
931         }
932
933         if (!(treeNode instanceof TreeElement)) {
934             String JavaDoc s = Bundle.getString("Tags_TreeInvalidAttribute", _dataSource);
935             registerTagError(s, null);
936             return null;
937         }
938         return (TreeElement) treeNode;
939     }
940
941     /**
942      * Replace any occurrence of the specified placeholder in the specified
943      * template string with the specified replacement value.
944      * @param template Pattern string possibly containing the placeholder
945      * @param placeholder Placeholder expression to be replaced
946      * @param value Replacement value for the placeholder
947      */

948     protected String JavaDoc replace(String JavaDoc template, String JavaDoc placeholder, String JavaDoc value)
949     {
950         if (template == null)
951             return null;
952         if ((placeholder == null) || (value == null))
953             return template;
954
955         while (true) {
956             int index = template.indexOf(placeholder);
957             if (index < 0)
958                 break;
959             InternalStringBuilder temp = new InternalStringBuilder(template.substring(0, index));
960             temp.append(value);
961             temp.append(template.substring(index + placeholder.length()));
962             template = temp.toString();
963         }
964         return template;
965     }
966
967     /**
968      * This method will handle creating the tagId attribute. The tagId attribute indentifies the
969      * tag in the generated HTML. There is a lookup table created in JavaScript mapping the <coe>tagId</code>
970      * to the actual name. The tagId is also run through the naming service so it can be scoped. Some tags will
971      * write that <code>tagid</code> out as the <code>id</code> attribute of the HTML tag being generated.
972      * @param tagId
973      * @param state
974      * @return String
975      */

976     protected final String JavaDoc renderTagId(HttpServletRequest JavaDoc request, String JavaDoc tagId, AbstractHtmlState state)
977     {
978         assert(_trs.tagId != null);
979         state.id = getIdForTagId(tagId);
980         String JavaDoc script = renderDefaultJavaScript(request, state.id);
981         return script;
982     }
983
984     /**
985      * This method will report all collected errors.
986      * @param error
987      */

988     public void collectChildError(String JavaDoc error)
989     {
990         if (_errorText == null) {
991             _errorText = new InternalStringBuilder(32);
992         }
993         _errorText.append(error);
994     }
995
996     //****************************
997
/**
998      * Much of the code below is taken from the HtmlBaseTag. We need to eliminate this duplication
999      * through some type of helper methods.
1000     */

1001    private String JavaDoc renderDefaultJavaScript(HttpServletRequest JavaDoc request, String JavaDoc realId)
1002    {
1003        String JavaDoc idScript = null;
1004
1005        // map the tagId to the real id
1006
if (TagConfig.isDefaultJavaScript()) {
1007            ScriptRequestState srs = ScriptRequestState.getScriptRequestState(request);
1008            idScript = srs.mapTagId(getScriptReporter(), _trs.tagId, realId, null);
1009        }
1010        return idScript;
1011    }
1012}
1013
Popular Tags