001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033:
034: package com.icesoft.faces.component.tree;
035:
036: import com.icesoft.faces.component.CSS_DEFAULT;
037: import com.icesoft.faces.component.InvalidComponentTypeException;
038: import com.icesoft.faces.component.ext.taglib.Util;
039: import com.icesoft.faces.component.util.CustomComponentUtils;
040: import com.icesoft.faces.context.DOMContext;
041: import com.icesoft.faces.renderkit.dom_html_basic.DomBasicRenderer;
042: import com.icesoft.faces.renderkit.dom_html_basic.FormRenderer;
043: import com.icesoft.faces.renderkit.dom_html_basic.HTML;
044: import com.icesoft.faces.renderkit.dom_html_basic.PassThruAttributeRenderer;
045: import com.icesoft.faces.util.CoreUtils;
046:
047: import org.w3c.dom.Element;
048: import org.w3c.dom.Text;
049:
050: import javax.faces.component.UIComponent;
051: import javax.faces.context.FacesContext;
052: import javax.faces.event.ActionEvent;
053: import javax.swing.tree.DefaultMutableTreeNode;
054: import javax.swing.tree.TreeModel;
055: import java.io.IOException;
056: import java.util.Map;
057:
058: /**
059: * TreeRenderer is an ICEfaces D2D renderer for the Tree component.
060: *
061: * @author gmccleary
062: * @version 1.1
063: */
064: public class TreeRenderer extends DomBasicRenderer {
065:
066: /**
067: *
068: */
069: public static final String PATH_DELIMITER = "-";
070:
071: /**
072: * @return true as this component will render its children.
073: */
074: public boolean getRendersChildren() {
075: return true;
076: }
077:
078: /**
079: * @param facesContext
080: * @param uiComponent
081: */
082: public void decode(FacesContext facesContext,
083: UIComponent uiComponent) {
084: if (isStatic(uiComponent)) {
085: return;
086: }
087:
088: Tree treeComponent = (Tree) uiComponent;
089: String expandNodeKey = CustomComponentUtils
090: .getHiddenTreeExpandFieldName(uiComponent
091: .getClientId(facesContext),
092: CustomComponentUtils.getFormName(uiComponent,
093: facesContext));
094: String pathToExpandedNode = (String) facesContext
095: .getExternalContext().getRequestParameterMap().get(
096: expandNodeKey);
097: // handle navigation: if the user clicked on an open/close icon
098: // then expand/contract the appropriate node by updating the state
099: // of the user object encapsulated by the tree node that was expanded/collapsed
100: if (pathToExpandedNode != null
101: && !pathToExpandedNode.equalsIgnoreCase("")) {
102: try {
103: // get the node that was expanded/contracted
104: DefaultMutableTreeNode navigatedNode = treeComponent
105: .getNodeAtPathsEnd(pathToExpandedNode);
106: treeComponent.setNavigatedNode(navigatedNode);
107: IceUserObject userObject = (IceUserObject) navigatedNode
108: .getUserObject();
109: if (userObject != null) {
110: treeComponent
111: .setNavigationEventType(userObject
112: .isExpanded() ? Tree.NAVIGATION_EVENT_COLLAPSE
113: : Tree.NAVIGATION_EVENT_EXPAND);
114: userObject.setExpanded(!userObject.isExpanded());
115: }
116:
117: ActionEvent actionEvent = new ActionEvent(uiComponent);
118: uiComponent.queueEvent(actionEvent);
119:
120: } catch (NumberFormatException nfe) {
121: throw new InvalidNavigationId(
122: "TreeRenderer.decode() NumberFormatException invalid tree navigation id",
123: nfe);
124: }
125: }
126: }
127:
128: /**
129: * @param facesContext
130: * @param uiComponent
131: * @throws IOException
132: */
133: public void encodeBegin(FacesContext facesContext,
134: UIComponent uiComponent) throws IOException {
135:
136: // get domContext first, to check if we are stream writing
137: DOMContext domContext = DOMContext.attachDOMContext(
138: facesContext, uiComponent);
139:
140: // setup
141: validateParameters(facesContext, uiComponent, Tree.class);
142:
143: Tree treeComponent = (Tree) uiComponent;
144: TreeModel treeModel = (TreeModel) uiComponent.getValueBinding(
145: "value").getValue(facesContext);
146:
147: if (treeComponent.getChildCount() != 1) {
148: throw new MalformedTreeTagException(
149: "The tree tag requires a single child treeNode tag. Found ["
150: + treeComponent.getChildCount() + "]");
151: }
152:
153: if (treeModel == null) {
154: return;
155: }
156:
157: // set up form fields
158: FormRenderer.addHiddenField(facesContext, CustomComponentUtils
159: .getHiddenTreeExpandFieldName(uiComponent
160: .getClientId(facesContext),
161: CustomComponentUtils.getFormName(uiComponent,
162: facesContext)));
163: FormRenderer.addHiddenField(facesContext, CustomComponentUtils
164: .getHiddenTreeActionFieldName(uiComponent
165: .getClientId(facesContext),
166: CustomComponentUtils.getFormName(uiComponent,
167: facesContext)));
168:
169: // encode the root DIV
170: if (!domContext.isInitialized()) {
171: Element rootDOMNode = domContext
172: .createRootElement(HTML.DIV_ELEM);
173: rootDOMNode.setAttribute(HTML.ID_ATTR, uiComponent
174: .getClientId(facesContext));
175: }
176: // get the root node
177: Element rootDomNode = (Element) domContext.getRootNode();
178:
179: // Apply default styleClass and style to the root node.
180: rootDomNode.setAttribute(HTML.CLASS_ATTR, treeComponent
181: .getStyleClass());
182: String style = treeComponent.getStyle();
183: if (style != null && style.length() > 0)
184: rootDomNode.setAttribute(HTML.STYLE_ATTR, style);
185: else
186: rootDomNode.removeAttribute(HTML.STYLE_ATTR);
187:
188: // clean up, and remove nodes
189: DOMContext.removeChildren(rootDomNode);
190:
191: if (PassThruAttributeRenderer
192: .passThruAttributeExists(uiComponent)) {
193: PassThruAttributeRenderer.renderAttributes(facesContext,
194: uiComponent, null);
195: }
196:
197: // startNode is used in conjunction with endNode as an alternative to streamWrite method
198: domContext.startNode(facesContext, treeComponent, rootDomNode);
199:
200: domContext.stepInto(uiComponent);
201:
202: }
203:
204: private boolean isHideRootNode(Tree treeComponent) {
205: String hideRootNodeAttribute = (String) treeComponent
206: .getAttributes().get("hideRootNode");
207: return hideRootNodeAttribute != null
208: && hideRootNodeAttribute.equalsIgnoreCase("true");
209: }
210:
211: private boolean isHideNavigation(Tree treeComponent) {
212: String hideNavAttr = (String) treeComponent.getAttributes()
213: .get("hideNavigation");
214: return hideNavAttr != null
215: && hideNavAttr.equalsIgnoreCase("true");
216: }
217:
218: /**
219: * @param facesContext
220: * @param uiComponent
221: * @throws IOException
222: */
223: public void encodeChildren(FacesContext facesContext,
224: UIComponent uiComponent) throws IOException {
225:
226: // get domContext first to check if we are stream writing
227: DOMContext domContext = DOMContext.getDOMContext(facesContext,
228: uiComponent);
229:
230: TreeModel treeModel = (TreeModel) uiComponent.getValueBinding(
231: "value").getValue(facesContext);
232: DefaultMutableTreeNode treeComponentRootNode = (DefaultMutableTreeNode) treeModel
233: .getRoot();
234: Element rootNode = (Element) domContext.getRootNode();
235: com.icesoft.faces.component.tree.TreeNode treeNode = (TreeNode) (uiComponent)
236: .getChildren().get(0);
237: boolean hideRootNode;
238: if (uiComponent instanceof Tree) {
239: hideRootNode = isHideRootNode((Tree) uiComponent);
240: } else {
241: throw new InvalidComponentTypeException("Expecting a Tree");
242: }
243:
244: encodeParentAndChildNodes(facesContext, (Tree) uiComponent,
245: (DefaultMutableTreeNode) treeModel.getRoot(),
246: hideRootNode, rootNode, treeComponentRootNode, treeNode);
247:
248: }
249:
250: /**
251: * @param facesContext
252: * @param treeComponent
253: * @param current
254: * @param hideCurrentNode
255: * @param parentDOMNode
256: * @param treeComponentRootNode
257: * @param treeNode
258: */
259: public void encodeParentAndChildNodes(FacesContext facesContext,
260: Tree treeComponent, DefaultMutableTreeNode current,
261: boolean hideCurrentNode, Element parentDOMNode,
262: DefaultMutableTreeNode treeComponentRootNode,
263: TreeNode treeNode) {
264:
265: DOMContext domContext = DOMContext.getDOMContext(facesContext,
266: treeComponent);
267:
268: Element treeNodeDiv = domContext.createElement(HTML.DIV_ELEM);
269: if (!hideCurrentNode) {
270: // put the next node on the request map
271: Map requestMap = facesContext.getExternalContext()
272: .getRequestMap();
273: String varAttribute = treeComponent.getVar();
274: requestMap.put(varAttribute, current);
275: domContext.setCursorParent(parentDOMNode);
276:
277: treeNodeDiv.setAttribute(HTML.NAME_ATTR, "treeNodeDiv");
278: treeNodeDiv.setAttribute(HTML.CLASS_ATTR, treeComponent
279: .getTreeRowStyleClass());
280: parentDOMNode.appendChild(treeNodeDiv);
281: domContext.setCursorParent(treeNodeDiv);
282: // startNode is used in conjunction with endNode as an alternative to streamWrite method
283: try {
284: domContext.startNode(facesContext, treeComponent,
285: treeNodeDiv);
286: } catch (IOException ioe) {
287: ioe.printStackTrace();
288: }
289:
290: encodeNode(facesContext, treeComponent, current,
291: treeNodeDiv, domContext, treeComponentRootNode,
292: treeNode, parentDOMNode);
293:
294: } else {
295: // root node is hidden
296: // put the next node on the request map
297: Map requestMap = facesContext.getExternalContext()
298: .getRequestMap();
299: String varAttribute = treeComponent.getVar();
300: requestMap.put(varAttribute, current);
301: domContext.setCursorParent(parentDOMNode);
302:
303: treeNodeDiv.setAttribute(HTML.NAME_ATTR, "treeNodeDiv");
304: treeNodeDiv.setAttribute(HTML.CLASS_ATTR, treeComponent
305: .getTreeRowStyleClass());
306: // treeNodeDiv id is assigned here when roo node is hidden
307: treeNodeDiv.setAttribute(HTML.ID_ATTR, treeComponent
308: .getClientId(facesContext)
309: + "-div-root");
310: parentDOMNode.appendChild(treeNodeDiv);
311: domContext.setCursorParent(treeNodeDiv);
312: // startNode is used in conjunction with endNode as an alternative to streamWrite method
313: try {
314: domContext.startNode(facesContext, treeComponent,
315: treeNodeDiv);
316: } catch (IOException ioe) {
317: ioe.printStackTrace();
318: }
319:
320: }
321: // iterate child nodes
322: int childCount = current.getChildCount();
323: if (childCount > 0
324: && ((IceUserObject) current.getUserObject())
325: .isExpanded()) {
326: // render CHILD div
327: Element childDiv = domContext.createElement(HTML.DIV_ELEM);
328: childDiv.setAttribute(HTML.NAME_ATTR, "CHILD");
329: childDiv.setAttribute(HTML.ID_ATTR, treeNodeDiv
330: .getAttribute(HTML.ID_ATTR)
331: + "-child");
332:
333: treeNodeDiv.appendChild(childDiv);
334:
335: // this method is used in conjunction with endNode as an alternative to streamWrite method
336: try {
337: domContext.startNode(facesContext, treeComponent,
338: childDiv);
339: } catch (IOException ioe) {
340: ioe.printStackTrace();
341: }
342:
343: // recurse children
344: DefaultMutableTreeNode next;
345: for (int i = 0; i < childCount; i++) {
346: next = (DefaultMutableTreeNode) current.getChildAt(i);
347: encodeParentAndChildNodes(facesContext, treeComponent,
348: next, false, childDiv, treeComponentRootNode,
349: treeNode);
350: }
351: // endNode is used in conjunction with startNode as an alternative to streamWrite method
352: try {
353: domContext.endNode(facesContext, treeComponent,
354: childDiv);
355: } catch (IOException ioe) {
356: ioe.printStackTrace();
357: }
358:
359: }
360:
361: }
362:
363: /**
364: * @param facesContext
365: * @param treeComponent
366: * @param currentNode
367: * @param treeNodeDiv
368: * @param domContext
369: * @param treeComponentRootNode
370: * @param treeNode
371: * @param parentDOMNode
372: */
373: public void encodeNode(FacesContext facesContext,
374: Tree treeComponent, DefaultMutableTreeNode currentNode,
375: Element treeNodeDiv, DOMContext domContext,
376: DefaultMutableTreeNode treeComponentRootNode,
377: TreeNode treeNode, Element parentDOMNode) {
378:
379: String pathToCurrentRoot = getPathAsString(currentNode,
380: treeComponentRootNode);
381: boolean hideRootNode = isHideRootNode(treeComponent);
382: boolean hideNavigation = isHideNavigation(treeComponent);
383:
384: treeNode.setMutable(currentNode);
385: treeNode.setId(Tree.ID_PREFIX + pathToCurrentRoot);
386: treeNode.setParent(treeComponent);
387:
388: // efficiency and simplicity
389: IceUserObject userObject = (IceUserObject) currentNode
390: .getUserObject();
391: // a branch node is a node that is not a leaf
392: boolean isBranchNode = !userObject.isLeaf();
393: boolean isExpanded = userObject.isExpanded();
394: boolean isLastChild = treeComponentRootNode.getLastLeaf() == currentNode;
395: boolean isCollapsedAndFinalBranch = false;
396: if (isBranchNode && !isExpanded) {
397: isCollapsedAndFinalBranch = isCollapsedAndFinalBranch(currentNode);
398: }
399: int level = currentNode.getLevel();
400: UIComponent myForm = findForm(treeComponent);
401: String formId = myForm.getClientId(facesContext);
402:
403: // if the root node was not rendered, then don't render the first
404: // column of lines extending down from the position where the root
405: // node would have been
406: if (hideRootNode) {
407: level--;
408: }
409: for (int i = 0; i < level; i++) {
410: //render the vertical line or blank
411: Element verticalLine = domContext
412: .createElement(HTML.IMG_ELEM);
413: verticalLine.setAttribute(HTML.ALT_ATTR, "");
414:
415: // use the level to check parentNodes
416: // to determine if we render a line or a blank
417: DefaultMutableTreeNode parentNode = null;
418: if ((i > 0) || (hideRootNode)) {
419: // start at 1 because we are making a call to getParent first
420: int j = 1;
421: parentNode = (DefaultMutableTreeNode) currentNode
422: .getParent();
423: while (j < (level - i)) {
424: parentNode = (DefaultMutableTreeNode) parentNode
425: .getParent();
426: j++;
427: }
428: }
429:
430: boolean renderBlank = false;
431:
432: if ((null != parentNode)
433: && (parentNode.getNextSibling() == null)) {
434: renderBlank = true;
435: }
436:
437: if (renderBlank) {
438: verticalLine.setAttribute(HTML.SRC_ATTR, treeComponent
439: .getLineBlankImage());
440: } else if ((i == 0) && (!hideRootNode)) {
441: verticalLine.setAttribute(HTML.SRC_ATTR, treeComponent
442: .getLineBlankImage());
443: } else if (isLastChild || isCollapsedAndFinalBranch) {
444: verticalLine.setAttribute(HTML.SRC_ATTR, treeComponent
445: .getLineBottomImage());
446: } else {
447: verticalLine.setAttribute(HTML.SRC_ATTR, treeComponent
448: .getLineVerticalImage());
449: }
450:
451: verticalLine.setAttribute(HTML.BORDER_ATTR, "0");
452: Text space = domContext.createTextNode(" ");
453: treeNodeDiv.appendChild(space);
454: treeNodeDiv.appendChild(verticalLine);
455: space = domContext.createTextNode(" ");
456: treeNodeDiv.appendChild(space);
457:
458: // startNode is used in conjunction with endNode as an alternative to streamWrite method
459: try {
460: domContext.startNode(facesContext, treeComponent,
461: verticalLine);
462: domContext.endNode(facesContext, treeComponent,
463: verticalLine);
464: } catch (IOException ioe) {
465: ioe.printStackTrace();
466: }
467:
468: }
469:
470: if (isBranchNode && !hideNavigation) {
471: Element navAnchor = domContext
472: .createElement(HTML.ANCHOR_ELEM);
473: navAnchor.setAttribute(HTML.HREF_ATTR, "#");
474: navAnchor.setAttribute(HTML.ID_ATTR, formId + ":"
475: + pathToCurrentRoot);
476: navAnchor.setAttribute(HTML.ONFOCUS_ATTR,
477: "setFocus(this.id);");
478: navAnchor.setAttribute(HTML.ONBLUR_ATTR, "setFocus('');");
479: String hiddenFieldName = CustomComponentUtils
480: .getHiddenTreeExpandFieldName(treeComponent
481: .getClientId(facesContext),
482: CustomComponentUtils.getFormName(
483: treeComponent, facesContext));
484:
485: String onclickString = "document.forms['" + formId + "']['"
486: + hiddenFieldName + "'].value=" + "'"
487: + pathToCurrentRoot + "';" + "iceSubmitPartial("
488: + " document.forms['" + formId + "'],"
489: + " this,event); " + "return false;";
490:
491: navAnchor.setAttribute(HTML.ONCLICK_ATTR, onclickString);
492: treeNodeDiv.appendChild(navAnchor);
493: // icon
494: Element iconImage = domContext.createElement(HTML.IMG_ELEM);
495: // Determine whether to render the top, middle, or bottom image:
496: // Encode the top image with no lines extending if this node is the
497: // root of the tree, has children, and is not expanded.
498: // Also render the top image with no lines extending if the root
499: // node is hidden and this node is the only child of the root and
500: // this node is not expanded.
501: // Encode the top image if this is the root of the entire tree
502: // or if the root is hidden and this is its first child
503: // Encode the bottom image if this node has children,
504: // is the last child of its parent, and is not expanded
505: // Encode the middle image by default
506: // *** cleanup replaced line images with blanks ***
507: if (currentNode.isRoot()
508: && !isExpanded
509: || hideRootNode
510: && currentNode.getNextSibling() == null
511: && currentNode == treeComponentRootNode
512: .getFirstChild()) {
513: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
514: .getNavOpenTopNoSiblingsImage());
515: } else if (currentNode.isRoot()
516: || hideRootNode
517: && treeComponentRootNode.getFirstChild() == currentNode) {
518: if (isExpanded) {
519: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
520: .getNavCloseTopNoSiblingsImage());
521: } else {
522: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
523: .getNavOpenTopNoSiblingsImage());
524: }
525: } else if (currentNode.getNextSibling() == null
526: && currentNode.getChildCount() > 0) {
527: if (isExpanded) {
528: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
529: .getNavCloseBottomImage());
530: } else {
531: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
532: .getNavOpenBottomImage());
533: }
534: } else {
535: if (isExpanded) {
536: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
537: .getNavCloseMiddleImage());
538: } else {
539: iconImage.setAttribute(HTML.SRC_ATTR, treeComponent
540: .getNavOpenMiddleImage());
541: }
542: }
543: iconImage.setAttribute(HTML.BORDER_ATTR, "0");
544: iconImage.setAttribute(HTML.ALT_ATTR, "");
545:
546: navAnchor.appendChild(iconImage);
547: // use startNode and endNode as an alternative to streamWrite method
548: try {
549: domContext.startNode(facesContext, treeComponent,
550: navAnchor);
551: domContext.startNode(facesContext, treeComponent,
552: iconImage);
553: domContext.endNode(facesContext, treeComponent,
554: iconImage);
555: domContext.endNode(facesContext, treeComponent,
556: navAnchor);
557: } catch (IOException ioe) {
558: ioe.printStackTrace();
559: }
560:
561: } else { // this is a leaf node
562: Element lineImage = domContext.createElement(HTML.IMG_ELEM);
563: Text space = domContext.createTextNode(" ");
564: treeNodeDiv.appendChild(space);
565:
566: treeNodeDiv.appendChild(lineImage);
567: lineImage.setAttribute(HTML.BORDER_ATTR, "0");
568: lineImage.setAttribute(HTML.ALT_ATTR, "");
569:
570: if (currentNode.getNextSibling() == null) {
571: // use lineBottomNode image
572: lineImage.setAttribute(HTML.SRC_ATTR, treeComponent
573: .getLineBottomImage());
574: } else {
575: // use lineMiddleNode image
576: lineImage.setAttribute(HTML.SRC_ATTR, treeComponent
577: .getLineMiddleImage());
578: }
579:
580: // use startNode and endNode as an alternative to streamWrite method
581: try {
582: domContext.startNode(facesContext, treeComponent,
583: lineImage);
584: domContext.endNode(facesContext, treeComponent,
585: lineImage);
586: } catch (IOException ioe) {
587: ioe.printStackTrace();
588: }
589: }
590:
591: String pathToNode = TreeRenderer.getPathAsString(currentNode,
592: (DefaultMutableTreeNode) treeComponent.getModel()
593: .getRoot());
594: treeNodeDiv.setAttribute(HTML.ID_ATTR, treeComponent
595: .getClientId(facesContext)
596: + "-div-" + pathToNode);
597:
598: try {
599: encodeParentAndChildren(facesContext, treeNode);
600: } catch (IOException e) {
601: e.printStackTrace();
602: }
603: // use endNode as an alternative to streamWrite method
604: try {
605: domContext
606: .endNode(facesContext, treeComponent, treeNodeDiv);
607: } catch (IOException ioe) {
608: ioe.printStackTrace();
609: }
610:
611: }
612:
613: /**
614: * @param facesContext
615: * @param uiComponent
616: * @throws IOException
617: */
618: public void encodeEnd(FacesContext facesContext,
619: UIComponent uiComponent) throws IOException {
620: // TODO refactor
621: // the adding of this hidden div ensures that Firefox loads all the
622: // (default) images for the tree so when a tree node is clicked and the
623: // first instance of an image is encountered for display we don't have to
624: // wait for it to be downloaded. The visual disruption that the downloading
625: // causes is only visible on firefox. Firefox lays out the page first
626: // without the image, and the text in the tree node appears farther left
627: // than it will be after the image is downloaded.
628: // Then, after the image is downloaded,
629: // the page is layed-out again and the text moves to the right
630: // to accomodate the image that has finally arrived.
631: validateParameters(facesContext, uiComponent, Tree.class);
632:
633: DOMContext domContext = DOMContext.getDOMContext(facesContext,
634: uiComponent);
635:
636: Element rootNode = (Element) domContext.getRootNode();
637:
638: Element imageLoaderDiv = domContext
639: .createElement(HTML.DIV_ELEM);
640: imageLoaderDiv.setAttribute(HTML.ID_ATTR, "imageCache");
641: imageLoaderDiv.setAttribute(HTML.STYLE_ATTR, "display:none;");
642: rootNode.appendChild(imageLoaderDiv);
643:
644: Element tree_document = domContext.createElement(HTML.IMG_ELEM);
645: Element tree_line_blank = domContext
646: .createElement(HTML.IMG_ELEM);
647: Element tree_line_vertical = domContext
648: .createElement(HTML.IMG_ELEM);
649: Element tree_nav_middle_close = domContext
650: .createElement(HTML.IMG_ELEM);
651: Element tree_nav_top_open = domContext
652: .createElement(HTML.IMG_ELEM);
653: Element tree_folder_close = domContext
654: .createElement(HTML.IMG_ELEM);
655: Element tree_line_last_node = domContext
656: .createElement(HTML.IMG_ELEM);
657: Element tree_nav_bottom_close = domContext
658: .createElement(HTML.IMG_ELEM);
659: Element tree_nav_middle_open = domContext
660: .createElement(HTML.IMG_ELEM);
661: Element tree_nav_top_open_no_siblings = domContext
662: .createElement(HTML.IMG_ELEM);
663: Element tree_folder_open = domContext
664: .createElement(HTML.IMG_ELEM);
665: Element tree_line_middle_node = domContext
666: .createElement(HTML.IMG_ELEM);
667: Element tree_nav_bottom_open = domContext
668: .createElement(HTML.IMG_ELEM);
669: Element tree_nav_top_close = domContext
670: .createElement(HTML.IMG_ELEM);
671: String appBase = CoreUtils.resolveResourceURL(facesContext,
672: "/xmlhttp/css/xp/css-images/");
673:
674: tree_document.setAttribute(HTML.SRC_ATTR, appBase
675: + "tree_document.gif");
676: tree_line_blank.setAttribute(HTML.SRC_ATTR, appBase
677: + "tree_line_blank.gif");
678: tree_line_vertical.setAttribute(HTML.SRC_ATTR, appBase
679: + "tree_line_vertical.gif");
680: tree_nav_middle_close.setAttribute(HTML.SRC_ATTR, appBase
681: + "tree_nav_middle_close.gif");
682: tree_nav_top_open.setAttribute(HTML.SRC_ATTR, appBase
683: + "tree_nav_top_open.gif");
684: tree_folder_close.setAttribute(HTML.SRC_ATTR, appBase
685: + "tree_folder_close.gif");
686: tree_line_last_node.setAttribute(HTML.SRC_ATTR, appBase
687: + "tree_line_last_node.gif");
688: tree_nav_bottom_close.setAttribute(HTML.SRC_ATTR, appBase
689: + "tree_nav_bottom_close.gif");
690: tree_nav_middle_open.setAttribute(HTML.SRC_ATTR, appBase
691: + "tree_nav_middle_open.gif");
692: tree_nav_top_open_no_siblings.setAttribute(HTML.SRC_ATTR,
693: appBase + "tree_nav_top_open_no_siblings.gif");
694: tree_folder_open.setAttribute(HTML.SRC_ATTR, appBase
695: + "tree_folder_open.gif");
696: tree_line_middle_node.setAttribute(HTML.SRC_ATTR, appBase
697: + "tree_line_middle_node.gif");
698: tree_nav_bottom_open.setAttribute(HTML.SRC_ATTR, appBase
699: + "tree_nav_bottom_open.gif");
700: tree_nav_top_close.setAttribute(HTML.SRC_ATTR, appBase
701: + "tree_nav_top_close.gif");
702:
703: imageLoaderDiv.appendChild(tree_document);
704: imageLoaderDiv.appendChild(tree_line_blank);
705: imageLoaderDiv.appendChild(tree_line_vertical);
706: imageLoaderDiv.appendChild(tree_nav_middle_close);
707: imageLoaderDiv.appendChild(tree_nav_top_open);
708: imageLoaderDiv.appendChild(tree_folder_close);
709: imageLoaderDiv.appendChild(tree_line_last_node);
710: imageLoaderDiv.appendChild(tree_nav_bottom_close);
711: imageLoaderDiv.appendChild(tree_nav_middle_open);
712: imageLoaderDiv.appendChild(tree_nav_top_open_no_siblings);
713: imageLoaderDiv.appendChild(tree_folder_open);
714: imageLoaderDiv.appendChild(tree_line_middle_node);
715: imageLoaderDiv.appendChild(tree_nav_bottom_open);
716: imageLoaderDiv.appendChild(tree_nav_top_close);
717:
718: // use endNode as an alternative to streamWrite method
719: // close the root node
720: domContext.endNode(facesContext, uiComponent, rootNode);
721:
722: domContext.stepOver();
723: }
724:
725: private boolean isCollapsedAndFinalBranch(
726: DefaultMutableTreeNode branch) {
727: javax.swing.tree.TreeNode[] path = branch.getPath();
728: for (int i = 0; i + 1 < path.length; i++) {
729: DefaultMutableTreeNode nextParent = (DefaultMutableTreeNode) path[i];
730: DefaultMutableTreeNode nextChild = (DefaultMutableTreeNode) path[i + 1];
731: if (!(nextParent.getLastChild() == nextChild)) {
732: return false;
733: }
734: }
735: return true;
736: }
737:
738: /**
739: * @param currentRoot
740: * @param treeComponentRootNode
741: * @return the path to the given currentRoot
742: */
743: public static String getPathAsString(
744: DefaultMutableTreeNode currentRoot,
745: DefaultMutableTreeNode treeComponentRootNode) {
746: if (currentRoot == treeComponentRootNode) {
747: // special case since there is no path to the root node
748: return "root";
749: }
750: StringBuffer convertedPath = new StringBuffer();
751: javax.swing.tree.TreeNode[] path = currentRoot.getPath();
752: int pathLength = path.length;
753: javax.swing.tree.TreeNode parent = treeComponentRootNode;
754: for (int i = 1; i < pathLength; i++) {
755: javax.swing.tree.TreeNode nextNodeInPath = path[i];
756: int indexOfNextNodeInPath = parent.getIndex(nextNodeInPath);
757: convertedPath.append(indexOfNextNodeInPath);
758: if (i + 1 < pathLength) {
759: convertedPath.append(PATH_DELIMITER);
760: }
761: parent = nextNodeInPath;
762: }
763: return convertedPath.toString();
764: }
765: }
|