KickJava   Java API By Example, From Geeks To Geeks.

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


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.tags.HtmlUtils;
21 import org.apache.beehive.netui.tags.html.IUrlParams;
22 import org.apache.beehive.netui.util.ParamHelper;
23
24 import javax.servlet.ServletRequest JavaDoc;
25 import javax.servlet.ServletResponse JavaDoc;
26 import java.io.Serializable JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.HashMap JavaDoc;
29
30 /**
31  * An individual node of a <code>Tree</code>, and rendered by that Tree instance.
32  */

33 public class TreeElement implements IUrlParams, Serializable JavaDoc
34 {
35     // These are the bits for the boolean state. The boolean state is stored
36
// in the _boolState variable. All boolean values should be accessed through
37
// their property accessors.
38
private static final int EXPANDED = 0x01;
39     private static final int SELECTED = 0x02;
40     private static final int DISABLED = 0x04;
41     private static final int EXPAND_ON_SERVER = 0x08;
42
43     public static final String JavaDoc SELECTED_NODE = "netui_treeselected";
44     public static final String JavaDoc EXPAND_NODE = "netui_treenode";
45     public static final String JavaDoc TREE_ID = "netui_treeid";
46     public static final String JavaDoc TREE_JAVASCRIPT_CLASS = "NetUITree";
47
48     /**
49      * Constant used to indicate an anchor is an expand/collapse tree node
50      */

51     public static final String JavaDoc TREE_ANCHOR = "netui:treeAnchor";
52     public static final String JavaDoc TREE_ANCHOR_INIT = "netui:treeAnchorInit";
53     public static final String JavaDoc TREE_ANCHOR_ID = "netui:treeId";
54     public static final String JavaDoc TREE_EXPAND = "netui:expandOnServer";
55     public static final String JavaDoc TREE_EXPAND_PATH = "netui:expandPath";
56     public static final String JavaDoc TREE_NODE_LAST = "netui:expandLast";
57     public static final String JavaDoc TREE_EXPAND_STATE = "expand";
58     public static final String JavaDoc TREE_COLLAPSE_STATE = "collapse";
59     public static final String JavaDoc TREE_LEVEL = "netui:treeLevel";
60
61     public static final String JavaDoc TREE_EXPAND_IMAGE = "netui:imageExpand";
62     public static final String JavaDoc TREE_COLLAPSE_IMAGE = "netui:imageCollapse";
63
64     /**
65      * Constant used to indicate that a tree node anchor should be set expanded.
66      */

67     public static final String JavaDoc TREE_EXPANDED = "expand";
68
69     // this is used as the TreeElement list for leaf nodes because they don't have children
70
private static final TreeElement[] EMPTY_TREE = new TreeElement[0];
71
72     private String JavaDoc _content; // The extra HTML content of the node
73
private String JavaDoc _label; // The label that will be displayed when this node is visible.
74
private Boolean JavaDoc _labelAsAlt; // flag indicating that the label should be used as alt text.
75
private String JavaDoc _title;
76     private String JavaDoc _name; // The unique (within the entire tree) name of this node.
77
private int _boolState; // the boolean state of things
78

79     private TreeElement _parent; // The parent node of this node, null for the root
80
private ArrayList JavaDoc _children; // The children of this node
81
public ArrayList JavaDoc _attribute; // The attributes assocated with the element.
82

83     private ExtendedInfo _info; // The extended info
84

85     /**
86      * Default constructor for creating a simple tree.
87      */

88     public TreeElement()
89     {
90         _name = "0";
91     }
92
93     /**
94      * Construct a new TreeElement with the specified parameters.
95      * @param expanded Should this node be expanded?
96      */

97     public TreeElement(String JavaDoc label, boolean expanded)
98     {
99         this();
100         _label = label;
101         setExpanded(expanded);
102     }
103
104     //********************** PUBLICALLY EXPOSED PROPERTIES **********************************
105

106     /**
107      * Gets the pathname to the icon file displayed when this node is visible,
108      * relative to the image directory for the images.
109      * @return the icon pathname
110      */

111     public String JavaDoc getIcon()
112     {
113         return (_info == null) ? null : _info._icon;
114     }
115
116     /**
117      * Set the pathname to the icon to display when this node is visible. The name is relative to the
118      * image directory.
119      * @param icon The relative path to the icond.
120      */

121     public void setIcon(String JavaDoc icon)
122     {
123         ExtendedInfo info = getInfo(icon);
124         if (info != null)
125             info._icon = icon;
126     }
127
128     /**
129      * Gets the label that will be displayed when this node is visible.
130      * @return the label
131      */

132     public String JavaDoc getLabel()
133     {
134         return _label;
135     }
136
137     /**
138      * Set the text of the label associated with this node.
139      * @param label The text of the tree node.
140      */

141     public void setLabel(String JavaDoc label)
142     {
143         _label = label;
144     }
145
146     public boolean isLabelLegalAsAlt()
147     {
148         if (_labelAsAlt == null)
149             _labelAsAlt = new Boolean JavaDoc(!HtmlUtils.containsHtml(_label));
150         return _labelAsAlt.booleanValue();
151     }
152
153     /**
154      * Return the content. The content is extra HTML that will be output to the right of the
155      * Nodes's label.
156      * @return the content
157      */

158     public String JavaDoc getContent()
159     {
160         return _content;
161     }
162
163     /**
164      * Set the content of the node. The content will be output to the right of the Nodes label.
165      * @param content The text of the tree node.
166      */

167     public void setContent(String JavaDoc content)
168     {
169         _content = content;
170     }
171
172     /**
173      * Gets the action invoked if this node
174      * is selected by the user.
175      * @return the action
176      */

177     public String JavaDoc getAction()
178     {
179         return (_info == null) ? null : _info._action;
180     }
181
182     /**
183      * Set the action to be called when the node is selected. A tree node may only have a <code>action</code>
184      * or <code>href</code> or <code>clientAction</code> set but not both.
185      * @param action an action in the page flow that will run when the node is selected.
186      */

187     public void setAction(String JavaDoc action)
188     {
189         ExtendedInfo info = getInfo(action);
190         if (info != null)
191             info._action = action;
192     }
193
194     /**
195      * Gets the client action invoked if this node is selected by the user.
196      * @return the action
197      */

198     public String JavaDoc getClientAction()
199     {
200         return (_info == null) ? null : _info._clientAction;
201     }
202
203     /**
204      * Set the client action to be called when the node is selected. A tree node may only have a <code>action</code>
205      * or <code>href</code> or <code>clientAction</code> set but not both.
206      * @param clientAction an action in the page flow that will run when the node is selected.
207      */

208     public void setClientAction(String JavaDoc clientAction)
209     {
210         ExtendedInfo info = getInfo(clientAction);
211         if (info != null)
212             info._clientAction = clientAction;
213     }
214
215     /**
216      * Return the ID of the tag. The id may be rewritten by the container (such
217      * as a portal) to make sure it is unique. JavaScript my lookup the actual id
218      * of the element by looking it up in the <code>netui_names</code> table written
219      * into the HTML.
220      * @return the tagId.
221      */

222     public String JavaDoc getTagId()
223     {
224         return (_info == null) ? null : _info._tagId;
225     }
226
227     /**
228      * Set the ID of the tag.
229      * @param tagId the tagId.
230      */

231     public void setTagId(String JavaDoc tagId)
232     {
233         ExtendedInfo info = getInfo(tagId);
234         if (info != null)
235             info._tagId = tagId;
236     }
237
238     /**
239      * Gets the hyperlink to which control will be directed if this node
240      * is selected by the user.
241      * @return the action
242      */

243     public String JavaDoc getHref()
244     {
245         return (_info == null) ? null : _info._href;
246     }
247
248     /**
249      * Set the hyperlink which will be called when the node is selected. A tree node may only have
250      * a <code>action</code> or <code>href</code> or <code>clientAction</code> set but not both.
251      * @param href The hyperlink called when the node is selected.
252      */

253     public void setHref(String JavaDoc href)
254     {
255         ExtendedInfo info = getInfo(href);
256         if (info != null)
257             info._href = href;
258     }
259
260     /**
261      * Gets the window target for the hyperlink identified by the
262      * <code>action</code> property, if this node is selected.
263      * @return the window target
264      */

265     public String JavaDoc getTarget()
266     {
267         return (_info == null) ? null : _info._target;
268     }
269
270     /**
271      * Set the window target for the hyperlink indentified by the <code>action</code>.
272      * @param target the window target.
273      */

274     public void setTarget(String JavaDoc target)
275     {
276         ExtendedInfo info = getInfo(target);
277         if (info != null)
278             info._target = target;
279     }
280
281     /**
282      * Gets if this node is currently expanded.
283      * @return the expanded state
284      */

285     public boolean isExpanded()
286     {
287         return ((_boolState & EXPANDED) != 0);
288     }
289
290     /**
291      * Sets if this node is currently expanded.
292      * @param expanded the expanded state
293      */

294     public void setExpanded(boolean expanded)
295     {
296         if (expanded) {
297             _boolState = _boolState | EXPANDED;
298         }
299         else
300             _boolState = _boolState & (-1 ^ EXPANDED);
301     }
302
303     /**
304      * This method will return the state of the expand on server attribute.
305      * @return the boolean value of the expandOnServer attribute.
306      */

307     public boolean isExpandOnServer()
308     {
309         return ((_boolState & EXPAND_ON_SERVER) != 0);
310     }
311
312     /**
313      * Set the value of the expandOnServer attribute. If the attribute is <code>true</code>
314      * and <code>runAtClient</code> is also true, then an expansion on this node will cause that
315      * to happen on the server. When runAtClient is false, all expansions will happen on the server.
316      * @param expandOnServer boolean value indicating if the node should be expanded on the server.
317      */

318     public void setExpandOnServer(boolean expandOnServer)
319     {
320         if (expandOnServer)
321             _boolState = _boolState | EXPAND_ON_SERVER;
322         else
323             _boolState = _boolState & (-1 ^ EXPAND_ON_SERVER);
324     }
325
326     /**
327      * Get the target scope for this node's URI.
328      * @return a String that identifies the target scope for this node's URI.
329      * @see #setScope
330      */

331     public String JavaDoc getScope()
332     {
333         return (_info == null) ? null : _info._scope;
334     }
335
336     /**
337      * Set the target scope for this anchor's URI. Any page flow that handles the URI will be made active within the
338      * given scope. Scopes allow multiple page flows to be active within the same user session; page flows in different
339      * scopes do not in general interact with each other. This attribute is commonly used in conjunction with the
340      * <code>target</code> attribute to invoke a new page flow in a separate window.
341      * @param scope a String that identifies the scope in which the target page flow will be made active.
342      * @netui:attribute required="false" rtexprvalue="true"
343      * description="Set the target scope for this anchor's URI."
344      */

345     public void setScope(String JavaDoc scope)
346     {
347         ExtendedInfo info = getInfo(scope);
348         if (info != null)
349             info._scope = scope;
350     }
351
352     /**
353      * Set the title attribute for the node.
354      * @return String
355      */

356     public String JavaDoc getTitle()
357     {
358         return _title;
359     }
360
361     /**
362      * Returns the current title attribute for the node.
363      * @param title
364      */

365     public void setTitle(String JavaDoc title)
366     {
367         _title = title;
368     }
369
370     public InheritableState getInheritableState()
371     {
372         return (_info == null) ? null : _info._state;
373     }
374
375     public void setInheritableState(InheritableState state)
376     {
377         ExtendedInfo info = getInfo(state);
378         if (info != null) {
379             info._state = state;
380         }
381     }
382
383     public void addParameter(String JavaDoc name, Object JavaDoc value, String JavaDoc facet)
384     {
385         // use this to force the creation of the _info variable.
386
ExtendedInfo info = getInfo(this);
387         if (info._params == null) {
388             info._params = new HashMap JavaDoc();
389         }
390         ParamHelper.addParam(info._params, name, value);
391     }
392
393     public HashMap JavaDoc getParams()
394     {
395         return (_info == null) ? null : _info._params;
396     }
397
398     //*************************** READ-ONLY PROPERTIES SET BY INTERNAL METHODS **************************
399

400     /**
401      * Gets whether or not this is the last node in the set of children
402      * for the parent node.
403      * @return if this is the last or not
404      */

405     public boolean isLast()
406     {
407         if (_parent == null)
408             return true;
409         int last = _parent.size() - 1;
410         assert(last >= 0);
411         return (_parent.getChild(last) == this);
412     }
413
414     public int getLevel()
415     {
416         TreeElement t = getParent();
417         int level = 0;
418         while (t != null) {
419             t = t.getParent();
420             level++;
421         }
422         return level;
423     }
424
425     /**
426      * Gets whether or not this a "leaf" node (i.e. one with no children)
427      * @return if this is the last or not
428      */

429     public boolean isLeaf()
430     {
431         if (_children == null)
432             return true;
433         return (_children.size() < 1);
434     }
435
436     /**
437      * Returns the unique name of the node. The unique name is set when the child is added to the tree.
438      * @return The unique name of the node.
439      */

440     public String JavaDoc getName()
441     {
442         return _name;
443     }
444
445     /**
446      * Gets the parent node of this node, or <code>null</code> if this
447      * is the root node.
448      * @return the TreeElement parent
449      */

450     public TreeElement getParent()
451     {
452         return _parent;
453     }
454
455     /**
456      * Gets whether this node currently selected. This is set by the tag render method.
457      * @return the selected state
458      */

459     public boolean isSelected()
460     {
461         return ((_boolState & SELECTED) != 0);
462     }
463
464     /**
465      * Sets whether this node currently selected.
466      * @param selected the selected state
467      */

468     public void setSelected(boolean selected)
469     {
470         if (selected)
471             _boolState = _boolState | SELECTED;
472         else
473             _boolState = _boolState & (-1 ^ SELECTED);
474     }
475
476     /**
477      * Gets whether this node currently selected. This is set by the tag render method.
478      * @return the selected state
479      */

480     public boolean isDisabled()
481     {
482         return ((_boolState & DISABLED) != 0);
483     }
484
485     /**
486      * Sets whether this node currently selected.
487      * @param disabled the selected state
488      */

489     public void setDisabled(boolean disabled)
490     {
491         if (disabled)
492             _boolState = _boolState | DISABLED;
493         else
494             _boolState = _boolState & (-1 ^ DISABLED);
495     }
496
497     /**
498      * This method is called by the children tags of the TreeItem. If there is a <code>TreeHtmlAttribute</code>
499      * it will set the attribute name and value.
500      * @param attr
501      */

502     public void addAttribute(TreeHtmlAttributeInfo attr)
503     {
504         if (_attribute == null) {
505             _attribute = new ArrayList JavaDoc();
506         }
507         attr.setParent(this);
508         _attribute.add(attr);
509     }
510
511     /**
512      * Return the list of attributes. This method may return null if there are
513      * no elements. In addition, the map may be exist but be empty.
514      * @return a ArrayList of attribute values or null.
515      */

516     public ArrayList JavaDoc getAttributeList()
517     {
518         return _attribute;
519     }
520
521     ///*********************** PROTECTED PROPERTY SETTERS *************************************
522
/**
523      * Set the unique name of the node. Uniqueness is not verified by this routine. This routine is protected
524      * because it is only called during add and remove of children.
525      * @param name the name of the node.
526      */

527     protected void setName(String JavaDoc name)
528     {
529         _name = name;
530     }
531
532     /**
533      * Sets the parent node of this node. This node will set the width value (which is really the
534      * depth in the tree of the node).
535      * @param parent the TreeElement parent
536      */

537     protected void setParent(TreeElement parent)
538     {
539         _parent = parent;
540     }
541
542     //*************************** EVENT METHODS *****************************
543

544     /**
545      * Code that runs when the node is expanded.
546      */

547     public void onExpand(ServletRequest JavaDoc request, ServletResponse JavaDoc response)
548     {
549         //do nothing
550
}
551
552     /**
553      * Code that runs when the node is selected.
554      */

555     public void onSelect(ServletRequest JavaDoc request)
556     {
557         //do nothing
558
}
559
560     //***************** CHILD/PARENT MANAGEMENT METHODS **************************************
561

562     /**
563      * Add a new child node to the end of the list.
564      * @param child The new child node
565      * @throws IllegalArgumentException if the name of the new child
566      * node is not unique
567      */

568     public void addChild(TreeElement child)
569             throws IllegalArgumentException JavaDoc
570     {
571
572         TreeElement theChild = child;
573         theChild.setParent(this);
574         if (getName() == null) {
575             setName("0");
576         }
577         if (_children == null) {
578             _children = new ArrayList JavaDoc();
579         }
580         //int n = _children.size();
581
//if (n > 0) {
582
// TreeElement node = (TreeElement) _children.get(n - 1);
583
// node.setLast(false);
584
//}
585
//theChild.setLast(true);
586
_children.add(child);
587         int n = _children.size();
588         theChild.updateName(this, n - 1);
589     }
590
591     /**
592      * This method will return the number of children of the node.
593      * @return the number of children of this tree element.
594      */

595     public int size()
596     {
597         if (_children == null)
598             return 0;
599         return _children.size();
600     }
601
602     /**
603      * Add a new child node at the specified position in the child list.
604      * @param offset Zero-relative offset at which the new node
605      * should be inserted
606      * @param child The new child node
607      * @throws IllegalArgumentException if the name of the new child
608      * node is not unique
609      */

610     public void addChild(int offset, TreeElement child)
611             throws IllegalArgumentException JavaDoc
612     {
613         child.setSelected(false);
614         child.setParent(this);
615         if (_children == null)
616             _children = new ArrayList JavaDoc();
617         _children.add(offset, child);
618
619         //Need to rename all affected!
620
int size = _children.size();
621         for (int i = offset; i < size; i++) {
622             TreeElement thisChild = (TreeElement) _children.get(i);
623             thisChild.updateName(this, i);
624         }
625
626     }
627
628     /**
629      *
630      */

631     public void clearChildren()
632     {
633         _children.clear();
634     }
635
636     /**
637      * Return the set of child nodes for this node.
638      * @return the child node array
639      */

640     public TreeElement[] getChildren()
641     {
642         if (_children == null)
643             return EMPTY_TREE;
644         TreeElement results[] = new TreeElement[_children.size()];
645         return (TreeElement[]) _children.toArray(results);
646     }
647
648     /**
649      * Return the child node at the given zero-relative index.
650      * @param index The child node index
651      * @return the child node
652      */

653     public TreeElement getChild(int index)
654     {
655         TreeElement childNode = null;
656         if (_children == null)
657             return null;
658         Object JavaDoc child = _children.get(index);
659         if (child != null) {
660             childNode = (TreeElement) child;
661         }
662         return childNode;
663     }
664
665     /**
666      * Remove the child node (and all children of that child) at the
667      * specified position in the child list.
668      * @param offset Zero-relative offset at which the existing
669      * node should be removed
670      */

671     public void removeChild(int offset)
672     {
673         if (_children == null)
674             return;
675
676         TreeElement child = (TreeElement)_children.remove(offset);
677         child.setParent(null);
678         child.setName(null);
679
680         // Rename all affected children
681
int size = _children.size();
682         for (int i = offset; i < size; i++) {
683             TreeElement thisChild = (TreeElement) _children.get(i);
684             thisChild.updateName(this, i);
685         }
686     }
687
688     /**
689      * Remove the specified child node. All of the
690      * children of this child node will also be removed.
691      * @param child Child node to be removed
692      */

693     public void removeChild(TreeElement child)
694     {
695
696         if (child == null || _children == null)
697             return;
698
699         int size = _children.size();
700         int removeIndex = -1;
701         for (int i = 0; i < size; i++) {
702             if (child == (TreeElement) _children.get(i)) {
703                 _children.remove(i);
704                 child.setParent(null);
705                 removeIndex = i;
706                 break;
707             }
708         }
709         if (removeIndex >= 0) {
710             size = _children.size();
711             for (int i = removeIndex; i < size; i++) {
712                 TreeElement thisChild = (TreeElement) _children.get(i);
713                 thisChild.updateName(this, i);
714             }
715         }
716     }
717
718     /**
719      * This method will update the name of this node and all of the children node. The name
720      * of a node reflects it's position in the tree.
721      * @param parentNode The parent node of this node.
722      * @param index the index position of this node within the parent node.
723      */

724     protected void updateName(TreeElement parentNode, int index)
725     {
726         setName(getNodeName(parentNode, index));
727         TreeElement[] children = getChildren();
728         for (int i = 0; i < children.length; i++) {
729             children[i].updateName(this, i);
730         }
731     }
732
733     //************ TREE BASED MANAGEMENT METHODS **************************************
734
/**
735      * Gets the root node of this tree.
736      * @param node The TreeElement to start from
737      * @return The root node
738      */

739     public static TreeElement getRoot(TreeElement node)
740     {
741         TreeElement parentNode = node.getParent();
742         while (parentNode != null) {
743             node = parentNode;
744             parentNode = node.getParent();
745         }
746         return node;
747     }
748
749     /**
750      * Given a node, find the named child.
751      * @param nodeName the name of the child to find.
752      * @return the node identified by the name
753      */

754     public TreeElement findNode(String JavaDoc nodeName)
755     {
756         TreeElement root = getRoot(this);
757         TreeElement node = root.findNodeRecurse(nodeName, nodeName);
758         return node;
759     }
760
761     /**
762      * @param parentNode
763      * @param index
764      * @return
765      */

766     private String JavaDoc getNodeName(TreeElement parentNode, int index)
767     {
768         String JavaDoc nodeName = "" + index;
769         if (parentNode != null) {
770             nodeName = parentNode.getName() + "." + nodeName;
771         }
772
773         return nodeName;
774     }
775
776     /**
777      * Helper routine that will recursively search the tree for the node.
778      * @param fullName The full name that we are looking for
779      * @param currentName The name of the current node.
780      * @return The node matching the name or <code>null</code>
781      */

782     private TreeElement findNodeRecurse(String JavaDoc fullName, String JavaDoc currentName)
783     {
784         String JavaDoc remainingName = null;
785
786         if ((currentName == null) || (fullName == null)) {
787             return null;
788         }
789         if (getName().equals(fullName)) {
790             return this;
791         }
792         if (currentName.indexOf('.') > 0) {
793             remainingName = currentName.substring(currentName.indexOf('.') + 1);
794             int nextIndex = -1;
795             if (remainingName.indexOf(".") > -1) {
796                 nextIndex = new Integer JavaDoc(remainingName.substring(0, remainingName.indexOf('.'))).intValue();
797             }
798             else {
799                 nextIndex = new Integer JavaDoc(remainingName).intValue();
800             }
801
802             TreeElement child = getChild(nextIndex);
803             if (child != null) {
804                 return child.findNodeRecurse(fullName, remainingName);
805             }
806             else {
807                 return null;
808             }
809         }
810         return null;
811     }
812
813     /**
814      * This will get the ExtendedInfo object. If it hasn't been created, this routine only
815      * creates it if the object passed in is non-null.
816      * @param o
817      * @return
818      */

819     private ExtendedInfo getInfo(Object JavaDoc o)
820     {
821         if (_info == null && o != null) {
822             _info = new ExtendedInfo();
823         }
824         return _info;
825     }
826
827     /**
828      * This class contains the attributes which infrequently used. This is an optimiation
829      * where the tree only contains the things necessary to render the base tree. Less commmonly used
830      * features are not exposed by this structure.
831      */

832     private static class ExtendedInfo implements Serializable JavaDoc
833     {
834         public String JavaDoc _clientAction; // Action to run on the client.
835
public String JavaDoc _href; // href to call if the node is selected
836
public String JavaDoc _scope; // The Scope
837
public String JavaDoc _icon; // The pathname to the icon file displayed when this node is visible
838
public String JavaDoc _tagId; // The tagId of the node
839
public String JavaDoc _target; // The window target for the hyperlink identified
840
public String JavaDoc _action; // The action invoked if this node is selected by the user.
841
public HashMap JavaDoc _params; // params to be applied to the selection action
842
public InheritableState _state; // The inheritable state from the tree
843
}
844 }
845
Popular Tags