0001: /*
0002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
0003: *
0004: * "The contents of this file are subject to the Mozilla Public License
0005: * Version 1.1 (the "License"); you may not use this file except in
0006: * compliance with the License. You may obtain a copy of the License at
0007: * http://www.mozilla.org/MPL/
0008: *
0009: * Software distributed under the License is distributed on an "AS IS"
0010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
0011: * License for the specific language governing rights and limitations under
0012: * the License.
0013: *
0014: * The Original Code is ICEfaces 1.5 open source software code, released
0015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
0016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
0017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
0018: *
0019: * Contributor(s): _____________________.
0020: *
0021: * Alternatively, the contents of this file may be used under the terms of
0022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
0023: * License), in which case the provisions of the LGPL License are
0024: * applicable instead of those above. If you wish to allow use of your
0025: * version of this file only under the terms of the LGPL License and not to
0026: * allow others to use your version of this file under the MPL, indicate
0027: * your decision by deleting the provisions above and replace them with
0028: * the notice and other provisions required by the LGPL License. If you do
0029: * not delete the provisions above, a recipient may use your version of
0030: * this file under either the MPL or the LGPL License."
0031: *
0032: */
0033:
0034: package com.icesoft.faces.component.tree;
0035:
0036: import com.icesoft.faces.component.CSS_DEFAULT;
0037: import com.icesoft.faces.component.ext.taglib.Util;
0038: import com.icesoft.faces.util.CoreUtils;
0039:
0040: import javax.faces.component.EditableValueHolder;
0041: import javax.faces.component.NamingContainer;
0042: import javax.faces.component.UICommand;
0043: import javax.faces.component.UIComponent;
0044: import javax.faces.context.FacesContext;
0045: import javax.faces.el.ValueBinding;
0046: import javax.faces.event.AbortProcessingException;
0047: import javax.faces.event.FacesEvent;
0048: import javax.faces.event.FacesListener;
0049: import javax.faces.event.PhaseId;
0050: import javax.faces.event.ActionEvent;
0051: import javax.swing.tree.DefaultMutableTreeNode;
0052: import javax.swing.tree.TreeModel;
0053: import java.io.Serializable;
0054: import java.util.HashMap;
0055: import java.util.Iterator;
0056: import java.util.Map;
0057:
0058: /**
0059: * Tree is a JSF component class that represent an ICEfaces tree.
0060: * <p/>
0061: * The tree component displays hierarchical data as a "tree" of branches and
0062: * leaf nodes. Optionally, the tree may also display navigation controls for the
0063: * dynamic expansion and collapse of branch nodes. Nodes may also support an
0064: * action event when clicked that can be used to respond to user click events.
0065: * <p/>
0066: * This component extends the JSF UICommand component and implemnents the JSF
0067: * NamingContainer interface.
0068: * <p/>
0069: * By default this component is rendered by the "com.icesoft.faces.View"
0070: * renderer type.
0071: *
0072: * @author Chris Brown
0073: * @author gmccleary
0074: * @version 1.1
0075: */
0076: public class Tree extends UICommand implements NamingContainer {
0077:
0078: // default style classes
0079: private static final String DEFAULT_CSSIMAGEDIR = "/xmlhttp/css/xp/css-images/";
0080:
0081: private static final String DEFAULT_NAV_OPEN_TOP_GIF = "tree_nav_top_open.gif";
0082:
0083: private static final String DEFAULT_NAV_CLOSE_TOP_GIF = "tree_nav_top_close.gif";
0084:
0085: private static final String DEFAULT_NAV_OPEN_TOP_NO_SIBLINGS_GIF = "tree_nav_top_open_no_siblings.gif";
0086:
0087: private static final String DEFAULT_NAV_CLOSE_TOP_NO_SIBLINGS_GIF = "tree_nav_top_close_no_siblings.gif";
0088:
0089: private static final String DEFAULT_NAV_OPEN_MIDDLE_GIF = "tree_nav_middle_open.gif";
0090:
0091: private static final String DEFAULT_NAV_CLOSE_MIDDLE_GIF = "tree_nav_middle_close.gif";
0092:
0093: private static final String DEFAULT_NAV_CLOSE_BOTTOM_GIF = "tree_nav_bottom_close.gif";
0094:
0095: private static final String DEFAULT_NAV_OPEN_BOTTOM_GIF = "tree_nav_bottom_open.gif";
0096:
0097: private static final String DEFAULT_LINE_MIDDLE_NODE_GIF = "tree_line_middle_node.gif";
0098:
0099: private static final String DEFAULT_LINE_VERTICAL_GIF = "tree_line_vertical.gif";
0100:
0101: private static final String DEFAULT_LINE_BLANK_GIF = "tree_line_blank.gif";
0102:
0103: private static final String DEFAULT_LINE_BOTTOM_NODE_GIF = "tree_line_last_node.gif";
0104:
0105: private static final String DEFAULT_DOCUMENT_GIF = "tree_document.gif";
0106:
0107: private static final String DEFAULT_FOLDER_GIF = "tree_folder_close.gif";
0108:
0109: private static final String DEFAULT_FOLDER_OPEN_GIF = "tree_folder_open.gif";
0110:
0111: /**
0112: * String constant for tree node collapse event.
0113: */
0114: public static final String NAVIGATION_EVENT_COLLAPSE = "collapse";
0115:
0116: /**
0117: * String constant for tree node expand event.
0118: */
0119: public static final String NAVIGATION_EVENT_EXPAND = "expand";
0120:
0121: /**
0122: * String constant for tree node id prefix.
0123: */
0124: public static final String ID_PREFIX = "n-";
0125:
0126: // private attributes
0127: private DefaultMutableTreeNode navigatedNode;
0128: private String navigationEventType;
0129: // images
0130: private String imageDir;
0131: private String navOpenTop;
0132: private String navOpenTopNoSiblings;
0133: private String navCloseTopNoSiblings;
0134: private String navCloseTop;
0135: private String navCloseMiddle;
0136: private String navOpenMiddle;
0137: private String lineMiddleNode;
0138: private String lineBottomNode;
0139: private String lineVertical;
0140: private String lineBlank;
0141: private String documentImage;
0142: private String folderImage;
0143: private String folderOpenImage;
0144: private String navCloseBottom;
0145: private String navOpenBottom;
0146: private String var;
0147: private String styleClass;
0148: private String style;
0149: private Boolean hideRootNode;
0150: private Boolean hideNavigation;
0151:
0152: private DefaultMutableTreeNode currentNode;
0153: private String nodePath;
0154:
0155: /**
0156: * default no args constructor
0157: */
0158: public Tree() {
0159:
0160: }
0161:
0162: /**
0163: * String constant specifying component type
0164: */
0165: public static final String COMPONENT_TYPE = "com.icesoft.faces.TreeView";
0166:
0167: /**
0168: * @return the renderer type of the tree component.
0169: */
0170: public String getRendererType() {
0171: return "com.icesoft.faces.View";
0172: }
0173:
0174: /**
0175: * @return the component type of the tree component.
0176: */
0177: public String getComponentType() {
0178: return COMPONENT_TYPE;
0179: }
0180:
0181: /*
0182: * (non-Javadoc)
0183: *
0184: * @see javax.faces.component.UIComponent#getFamily()
0185: */
0186: public String getFamily() {
0187: return "com.icesoft.faces.TreeView";
0188: }
0189:
0190: // accessors & modifiers aka getters and setters
0191:
0192: /**
0193: * @param currentNode
0194: */
0195: public void setCurrentNode(DefaultMutableTreeNode currentNode) {
0196: this .currentNode = currentNode;
0197: }
0198:
0199: /**
0200: * @return DefaultMutableTreeNode currentNode
0201: */
0202: public DefaultMutableTreeNode getCurrentNode() {
0203: return this .currentNode;
0204: }
0205:
0206: /**
0207: * @param nodePath
0208: */
0209: public void setNodePath(String nodePath) {
0210: FacesContext facesContext = getFacesContext();
0211: // save the state of the last node
0212: saveChildrenState(facesContext);
0213:
0214: this .nodePath = nodePath;
0215:
0216: // restore the state for current node
0217: restoreChildrenState(facesContext);
0218:
0219: // put the current node on the request map
0220: this .setCurrentVarToRequestMap(facesContext, getCurrentNode());
0221:
0222: }
0223:
0224: /**
0225: * @return String nodePath
0226: */
0227: public String getNodePath() {
0228: return this .nodePath;
0229: }
0230:
0231: /**
0232: * @return TreeModel model associated with tree
0233: */
0234: public TreeModel getModel() {
0235: ValueBinding vb = getValueBinding("value");
0236: return (TreeModel) vb.getValue(getFacesContext());
0237: }
0238:
0239: /**
0240: * @return TreeNode template
0241: * @throws MalformedTreeTagException
0242: */
0243: public TreeNode getTreeNodeTemplate()
0244: throws MalformedTreeTagException {
0245: TreeNode template = null;
0246: int childCount = this .getChildCount();
0247: if (childCount != 1) {
0248: throw new MalformedTreeTagException(
0249: "The tree tag requires a single treeNode child tag. Found ["
0250: + childCount + "] children");
0251: }
0252: UIComponent treeNodeTemplate = (UIComponent) getChildren().get(
0253: 0);
0254: if (treeNodeTemplate == null) {
0255: throw new MalformedTreeTagException(
0256: "The Tree requires a TreeNode child. None found.");
0257: }
0258:
0259: if (!(treeNodeTemplate instanceof TreeNode)) {
0260: throw new MalformedTreeTagException(
0261: "The Tree requires a TreeNode child. Found child of type ["
0262: + treeNodeTemplate.getClass() + "]");
0263: }
0264: return template;
0265: }
0266:
0267: /**
0268: * @param pathToSelectedNode
0269: * @return DefaultMutableTreeNode node at specified path
0270: */
0271: public DefaultMutableTreeNode getNodeAtPathsEnd(
0272: String pathToSelectedNode) {
0273: if (pathToSelectedNode.equalsIgnoreCase("root")) {
0274: return (DefaultMutableTreeNode) getModel().getRoot();
0275: }
0276: String[] indices = pathToSelectedNode
0277: .split(TreeRenderer.PATH_DELIMITER);
0278: DefaultMutableTreeNode parent = (DefaultMutableTreeNode) getModel()
0279: .getRoot();
0280: for (int i = 0; i < indices.length; i++) {
0281: parent = (DefaultMutableTreeNode) parent.getChildAt(Integer
0282: .parseInt(indices[i]));
0283: }
0284: return parent;
0285: }
0286:
0287: // image paths
0288:
0289: /**
0290: * @return String imageDir
0291: */
0292: public String getImageDir() {
0293: if (imageDir != null) {
0294: return imageDir;
0295: }
0296: ValueBinding vb = getValueBinding("imageDir");
0297: return CoreUtils.resolveResourceURL(getFacesContext(),
0298: vb != null ? (String) vb.getValue(getFacesContext())
0299: : DEFAULT_CSSIMAGEDIR);
0300: }
0301:
0302: /**
0303: * <p>Set the value of the <code>styleClass</code> property.</p>
0304: *
0305: * @return String style class property value.
0306: */
0307: public String getStyleClass() {
0308: return Util.getQualifiedStyleClass(this , styleClass,
0309: CSS_DEFAULT.TREE_DEFAULT_STYLE_CLASS, "styleClass");
0310: }
0311:
0312: /**
0313: * <p>Set the value of the <code>styleClass</code> property.</p>
0314: *
0315: * @param styleClass
0316: */
0317: public void setStyleClass(String styleClass) {
0318: this .styleClass = styleClass;
0319: }
0320:
0321: /**
0322: * <p>Set the value of the <code>style</code> property.</p>
0323: *
0324: * @return String style property value.
0325: */
0326: public String getStyle() {
0327: if (style != null) {
0328: return style;
0329: }
0330: ValueBinding vb = getValueBinding("style");
0331: return vb != null ? (String) vb.getValue(getFacesContext())
0332: : "";
0333: }
0334:
0335: /**
0336: * <p>Set the value of the <code>style</code> property.</p>
0337: *
0338: * @param style
0339: */
0340: public void setStyle(String style) {
0341: this .style = style;
0342: }
0343:
0344: String getTreeRowStyleClass() {
0345: return Util.getQualifiedStyleClass(this ,
0346: CSS_DEFAULT.STYLE_TREEROW);
0347: }
0348:
0349: /**
0350: * @param imageProperty
0351: * @param bindingName
0352: * @param defaultImage
0353: * @return String img src
0354: */
0355: public String getImage(String imageProperty, String bindingName,
0356: String defaultImage) {
0357: if (imageProperty != null) {
0358: return imageProperty;
0359: }
0360: ValueBinding vb = getValueBinding(bindingName);
0361: if (vb != null) {
0362: return (String) vb.getValue(getFacesContext());
0363: }
0364: return getImageDir() + defaultImage;
0365:
0366: }
0367:
0368: /**
0369: * @return String folder img src
0370: */
0371: public String getFolderImage() {
0372: return getImage(folderImage, "folderImage", DEFAULT_FOLDER_GIF);
0373: }
0374:
0375: /**
0376: * @return String folder open img src
0377: */
0378: public String getFolderOpenImage() {
0379: return getImage(folderOpenImage, "folderOpenImage",
0380: DEFAULT_FOLDER_OPEN_GIF);
0381: }
0382:
0383: /**
0384: * @return String document img src
0385: */
0386: public String getDocumentImage() {
0387: return getImage(documentImage, "documentImage",
0388: DEFAULT_DOCUMENT_GIF);
0389: }
0390:
0391: /**
0392: * @return String line bottom img src
0393: */
0394: public String getLineBottomImage() {
0395: return getImage(lineBottomNode, "lineBottom",
0396: DEFAULT_LINE_BOTTOM_NODE_GIF);
0397: }
0398:
0399: /**
0400: * @return String line vertical img src
0401: */
0402: public String getLineVerticalImage() {
0403: return getImage(lineVertical, "lineVertical",
0404: DEFAULT_LINE_VERTICAL_GIF);
0405: }
0406:
0407: /**
0408: * @return String line middle img src
0409: */
0410: public String getLineMiddleImage() {
0411: return getImage(lineMiddleNode, "lineMiddle",
0412: DEFAULT_LINE_MIDDLE_NODE_GIF);
0413: }
0414:
0415: /**
0416: * @return String navigation close middle img src
0417: */
0418: public String getNavCloseMiddleImage() {
0419: return getImage(navCloseMiddle, "navCloseMiddleImage",
0420: DEFAULT_NAV_CLOSE_MIDDLE_GIF);
0421: }
0422:
0423: /**
0424: * @return String navigation open middle img src
0425: */
0426: public String getNavOpenMiddleImage() {
0427: return getImage(navOpenMiddle, "navOpenMiddle",
0428: DEFAULT_NAV_OPEN_MIDDLE_GIF);
0429: }
0430:
0431: /**
0432: * @return String navigation close top img src
0433: */
0434: public String getNavCloseTopImage() {
0435: return getImage(navCloseTop, "navCloseTop",
0436: DEFAULT_NAV_CLOSE_TOP_GIF);
0437: }
0438:
0439: /**
0440: * @return String navigation open top img src
0441: */
0442: public String getNavOpenTopImage() {
0443: return getImage(navOpenTop, "navOpenTopImage",
0444: DEFAULT_NAV_OPEN_TOP_GIF);
0445: }
0446:
0447: /**
0448: * @return String navigation open top img src
0449: */
0450: public String getNavOpenTopNoSiblingsImage() {
0451: return getImage(navOpenTopNoSiblings,
0452: "navOpenTopNoSiblingsImage",
0453: DEFAULT_NAV_OPEN_TOP_NO_SIBLINGS_GIF);
0454: }
0455:
0456: /**
0457: * @return String navigation close top img src
0458: */
0459: public String getNavCloseTopNoSiblingsImage() {
0460: return getImage(navCloseTopNoSiblings,
0461: "navCloseTopNoSiblingsImage",
0462: DEFAULT_NAV_CLOSE_TOP_NO_SIBLINGS_GIF);
0463: }
0464:
0465: /**
0466: * @return String navigation close bottom img src
0467: */
0468: public String getNavCloseBottomImage() {
0469: return getImage(navCloseBottom, "navCloseBottomImage",
0470: DEFAULT_NAV_CLOSE_BOTTOM_GIF);
0471: }
0472:
0473: /**
0474: * @return String navigation open bottom img src
0475: */
0476: public String getNavOpenBottomImage() {
0477: return getImage(navOpenBottom, "navOpenBottomImage",
0478: DEFAULT_NAV_OPEN_BOTTOM_GIF);
0479: }
0480:
0481: /**
0482: * @return String blank img src
0483: */
0484: public String getLineBlankImage() {
0485: return getImage(lineBlank, "lineBlank", DEFAULT_LINE_BLANK_GIF);
0486: }
0487:
0488: /**
0489: * @return String line bottom node
0490: */
0491: public String getLineBottomNode() {
0492: return lineBottomNode;
0493: }
0494:
0495: /**
0496: * @param lineBottomNode
0497: */
0498: public void setLineBottomNode(String lineBottomNode) {
0499: this .lineBottomNode = lineBottomNode;
0500: }
0501:
0502: /**
0503: * @return String line middle node
0504: */
0505: public String getLineMiddleNode() {
0506: return lineMiddleNode;
0507: }
0508:
0509: /**
0510: * @param lineMiddleNode
0511: */
0512: public void setLineMiddleNode(String lineMiddleNode) {
0513: this .lineMiddleNode = lineMiddleNode;
0514: }
0515:
0516: /**
0517: * @return String line vertical
0518: */
0519: public String getLineVertical() {
0520: return lineVertical;
0521: }
0522:
0523: /**
0524: * @param lineVertical
0525: */
0526: public void setLineVertical(String lineVertical) {
0527: this .lineVertical = lineVertical;
0528: }
0529:
0530: /**
0531: * @return String navigation expand middle
0532: */
0533: public String getNavExpandedMiddle() {
0534: return navCloseMiddle;
0535: }
0536:
0537: /**
0538: * @param navExpandedMiddle
0539: */
0540: public void setNavExpandedMiddle(String navExpandedMiddle) {
0541: this .navCloseMiddle = navExpandedMiddle;
0542: }
0543:
0544: /**
0545: * @return String navigation expanded top
0546: */
0547: public String getNavExpandedTop() {
0548: return navOpenTop;
0549: }
0550:
0551: /**
0552: * @param navExpandedTop
0553: */
0554: public void setNavExpandedTop(String navExpandedTop) {
0555: this .navOpenTop = navExpandedTop;
0556: }
0557:
0558: /**
0559: * @param imageDir
0560: */
0561: public void setImageDir(String imageDir) {
0562: this .imageDir = imageDir;
0563: }
0564:
0565: /**
0566: * @param documentImage
0567: */
0568: public void setDocumentImage(String documentImage) {
0569: this .documentImage = documentImage;
0570: }
0571:
0572: /**
0573: * @param folderImage
0574: */
0575: public void setFolderImage(String folderImage) {
0576: this .folderImage = folderImage;
0577: }
0578:
0579: /**
0580: * @return String navigation close top
0581: */
0582: public String getNavCloseTop() {
0583: return navCloseTop;
0584: }
0585:
0586: /**
0587: * @param navCloseTop
0588: */
0589: public void setNavCloseTop(String navCloseTop) {
0590: this .navCloseTop = navCloseTop;
0591: }
0592:
0593: /**
0594: * @return String navigation open top
0595: */
0596: public String getNavOpenTop() {
0597: return navOpenTop;
0598: }
0599:
0600: /**
0601: * @param navOpenTop
0602: */
0603: public void setNavOpenTop(String navOpenTop) {
0604: this .navOpenTop = navOpenTop;
0605: }
0606:
0607: /**
0608: * @return String navigation open top
0609: */
0610: public String getNavOpenTopNoSiblings() {
0611: return navOpenTopNoSiblings;
0612: }
0613:
0614: /**
0615: * @param navOpenTopNoSiblings
0616: */
0617: public void setNavOpenTopNoSiblings(String navOpenTopNoSiblings) {
0618: this .navOpenTopNoSiblings = navOpenTopNoSiblings;
0619: }
0620:
0621: /**
0622: * @return String navigation close top
0623: */
0624: public String getNavCloseTopNoSiblings() {
0625: return navCloseTopNoSiblings;
0626: }
0627:
0628: /**
0629: * @param navCloseTopNoSiblings
0630: */
0631: public void setNavCloseTopNoSiblings(String navCloseTopNoSiblings) {
0632: this .navCloseTopNoSiblings = navCloseTopNoSiblings;
0633: }
0634:
0635: /**
0636: * @param folderOpenImage
0637: */
0638: public void setFolderOpenImage(String folderOpenImage) {
0639: this .folderOpenImage = folderOpenImage;
0640: }
0641:
0642: /**
0643: * @return String navigation close bottom
0644: */
0645: public String getNavCloseBottom() {
0646: return navCloseBottom;
0647: }
0648:
0649: /**
0650: * @param navCloseBottom
0651: */
0652: public void setNavCloseBottom(String navCloseBottom) {
0653: this .navCloseBottom = navCloseBottom;
0654: }
0655:
0656: /**
0657: * @return String navigation close middle
0658: */
0659: public String getNavCloseMiddle() {
0660: return navCloseMiddle;
0661: }
0662:
0663: /**
0664: * @param navCloseMiddle
0665: */
0666: public void setNavCloseMiddle(String navCloseMiddle) {
0667: this .navCloseMiddle = navCloseMiddle;
0668: }
0669:
0670: /**
0671: * @return String navigation open bottom
0672: */
0673: public String getNavOpenBottom() {
0674: return navOpenBottom;
0675: }
0676:
0677: /**
0678: * @param navOpenBottom
0679: */
0680: public void setNavOpenBottom(String navOpenBottom) {
0681: this .navOpenBottom = navOpenBottom;
0682: }
0683:
0684: /**
0685: * @return String navigation open middle
0686: */
0687: public String getNavOpenMiddle() {
0688: return navOpenMiddle;
0689: }
0690:
0691: /**
0692: * @param navOpenMiddle
0693: */
0694: public void setNavOpenMiddle(String navOpenMiddle) {
0695: this .navOpenMiddle = navOpenMiddle;
0696: }
0697:
0698: /**
0699: * @return String var
0700: */
0701: public String getVar() {
0702: return var;
0703: }
0704:
0705: /**
0706: * @param var
0707: */
0708: public void setVar(String var) {
0709: this .var = var;
0710: }
0711:
0712: /**
0713: * @return String lineBlank
0714: */
0715: public String getLineBlank() {
0716: return lineBlank;
0717: }
0718:
0719: /**
0720: * @param lineBlank
0721: */
0722: public void setLineBlank(String lineBlank) {
0723: this .lineBlank = lineBlank;
0724: }
0725:
0726: /**
0727: * @return DefaultMutableTreeNode navigatedNode
0728: */
0729: public DefaultMutableTreeNode getNavigatedNode() {
0730: return navigatedNode;
0731: }
0732:
0733: /**
0734: * @param navigatedNode
0735: */
0736: public void setNavigatedNode(DefaultMutableTreeNode navigatedNode) {
0737: this .navigatedNode = navigatedNode;
0738: }
0739:
0740: /**
0741: * @param string
0742: */
0743: public void setNavigationEventType(String string) {
0744: this .navigationEventType = string;
0745: }
0746:
0747: /**
0748: * @return String navigationEventType
0749: */
0750: public String getNavigationEventType() {
0751: return navigationEventType;
0752: }
0753:
0754: // StateHolder Methods
0755:
0756: /**
0757: * save the tree component state
0758: *
0759: * @param context
0760: * @return Object values[]
0761: */
0762: public Object saveState(FacesContext context) {
0763:
0764: Object values[] = new Object[26];
0765: values[0] = super .saveState(context);
0766: values[1] = navigatedNode;
0767: values[2] = navigationEventType;
0768: values[3] = imageDir;
0769: values[4] = navOpenTop;
0770: values[5] = navOpenTopNoSiblings;
0771: values[6] = navCloseTopNoSiblings;
0772: values[7] = navCloseTop;
0773: values[8] = navCloseMiddle;
0774: values[9] = navOpenMiddle;
0775: values[10] = lineMiddleNode;
0776: values[11] = lineBottomNode;
0777: values[12] = lineVertical;
0778: values[13] = lineBlank;
0779: values[14] = documentImage;
0780: values[15] = folderImage;
0781: values[16] = folderOpenImage;
0782: values[17] = navCloseBottom;
0783: values[18] = navOpenBottom;
0784: values[19] = var;
0785: values[20] = styleClass;
0786: values[21] = style;
0787: values[22] = hideRootNode;
0788: values[23] = hideNavigation;
0789: values[24] = currentNode;
0790: values[25] = nodePath;
0791:
0792: return (values);
0793:
0794: }
0795:
0796: /**
0797: * restore the tree component state
0798: *
0799: * @param context
0800: * @param state
0801: */
0802: public void restoreState(FacesContext context, Object state) {
0803:
0804: Object values[] = (Object[]) state;
0805: super .restoreState(context, values[0]);
0806: navigatedNode = (DefaultMutableTreeNode) values[1];
0807: navigationEventType = (String) values[2];
0808: imageDir = (String) values[3];
0809: navOpenTop = (String) values[4];
0810: navOpenTopNoSiblings = (String) values[5];
0811: navCloseTopNoSiblings = (String) values[6];
0812: navCloseTop = (String) values[7];
0813: navCloseMiddle = (String) values[8];
0814: navOpenMiddle = (String) values[9];
0815: lineMiddleNode = (String) values[10];
0816: lineBottomNode = (String) values[11];
0817: lineVertical = (String) values[12];
0818: lineBlank = (String) values[13];
0819: documentImage = (String) values[14];
0820: folderImage = (String) values[15];
0821: folderOpenImage = (String) values[16];
0822: navCloseBottom = (String) values[17];
0823: navOpenBottom = (String) values[18];
0824: var = (String) values[19];
0825: styleClass = (String) values[20];
0826: style = (String) values[21];
0827: hideRootNode = (Boolean) values[22];
0828: hideNavigation = (Boolean) values[23];
0829: currentNode = (DefaultMutableTreeNode) values[24];
0830: nodePath = (String) values[25];
0831: }
0832:
0833: /*
0834: * (non-Javadoc)
0835: *
0836: * @see javax.faces.component.UIComponent#processDecodes(javax.faces.context.FacesContext)
0837: */
0838: public void processDecodes(FacesContext context) {
0839: if (context == null) {
0840: throw new NullPointerException("context");
0841: }
0842: if (!isRendered()) {
0843: return;
0844: }
0845:
0846: savedChildren = new HashMap();
0847:
0848: this .processTreeNodes((DefaultMutableTreeNode) getModel()
0849: .getRoot(), PhaseId.APPLY_REQUEST_VALUES, context);
0850:
0851: try {
0852: this .setNodePath(null);
0853: this .setCurrentNode(null);
0854: decode(context);
0855: } catch (RuntimeException e) {
0856: context.renderResponse();
0857: throw e;
0858: }
0859: }
0860:
0861: // see superclass for documentation
0862: /* (non-Javadoc)
0863: * @see javax.faces.component.UIComponentBase#processValidators(javax.faces.context.FacesContext)
0864: */
0865: public void processValidators(FacesContext context) {
0866: if (context == null) {
0867: throw new NullPointerException("context");
0868: }
0869: if (!isRendered()) {
0870: return;
0871: }
0872:
0873: this .processTreeNodes((DefaultMutableTreeNode) getModel()
0874: .getRoot(), PhaseId.PROCESS_VALIDATIONS, context);
0875:
0876: this .setNodePath(null);
0877: this .setCurrentNode(null);
0878: }
0879:
0880: // see superclass for documentation
0881: /* (non-Javadoc)
0882: * @see javax.faces.component.UIComponentBase#processUpdates(javax.faces.context.FacesContext)
0883: */
0884: public void processUpdates(FacesContext context) {
0885: if (context == null) {
0886: throw new NullPointerException("context");
0887: }
0888: if (!isRendered()) {
0889: return;
0890: }
0891:
0892: this .processTreeNodes((DefaultMutableTreeNode) getModel()
0893: .getRoot(), PhaseId.UPDATE_MODEL_VALUES, context);
0894:
0895: this .setNodePath(null);
0896: this .setCurrentNode(null);
0897: }
0898:
0899: /**
0900: * Recursively process all TreeNodes starting at the currentNode. TreeNodes
0901: * will be process according the the phaseId
0902: *
0903: * @param currentNode
0904: * @param phaseId
0905: * @param context
0906: */
0907: private void processTreeNodes(DefaultMutableTreeNode currentNode,
0908: Object phaseId, FacesContext context) {
0909: // set currentNode on tree
0910: this .setCurrentNode(currentNode);
0911:
0912: TreeNode treeNodeTemplate = (TreeNode) this .getChildren()
0913: .get(0);
0914: String pathToCurrentNode = TreeRenderer.getPathAsString(
0915: currentNode, (DefaultMutableTreeNode) getModel()
0916: .getRoot());
0917: treeNodeTemplate.setMutable(currentNode);
0918: treeNodeTemplate.setId(ID_PREFIX + pathToCurrentNode);
0919: treeNodeTemplate.setParent(this );
0920:
0921: this .setNodePath(pathToCurrentNode);
0922:
0923: // get TreeNode facets from treeNodeTemplate
0924: UIComponent iconFacet;
0925: UIComponent contentFacet;
0926:
0927: iconFacet = treeNodeTemplate.getIcon();
0928: contentFacet = treeNodeTemplate.getContent();
0929:
0930: // call appropriate phase handler
0931: if (phaseId == PhaseId.APPLY_REQUEST_VALUES) {
0932: if (iconFacet != null) {
0933: iconFacet.processDecodes(context);
0934: }
0935: if (contentFacet != null) {
0936: contentFacet.processDecodes(context);
0937: }
0938: } else if (phaseId == PhaseId.PROCESS_VALIDATIONS) {
0939: if (iconFacet != null) {
0940: iconFacet.processValidators(context);
0941: }
0942: if (contentFacet != null) {
0943: contentFacet.processValidators(context);
0944: }
0945:
0946: } else if (phaseId == PhaseId.UPDATE_MODEL_VALUES) {
0947: if (iconFacet != null) {
0948: iconFacet.processUpdates(context);
0949: }
0950: if (contentFacet != null) {
0951: contentFacet.processUpdates(context);
0952: }
0953:
0954: }
0955:
0956: // recurse currentRoot's children
0957: IceUserObject userObject = (IceUserObject) currentNode
0958: .getUserObject();
0959: if (userObject.isExpanded()) {
0960: int childCount = currentNode.getChildCount();
0961: for (int childIndex = 0; childIndex < childCount; childIndex++) {
0962: DefaultMutableTreeNode nextNode = (DefaultMutableTreeNode) currentNode
0963: .getChildAt(childIndex);
0964:
0965: processTreeNodes(nextNode, phaseId, context);
0966: }
0967: }
0968: }
0969:
0970: /*
0971: * (non-Javadoc)
0972: *
0973: * @see javax.faces.component.UIComponent#queueEvent(javax.faces.event.FacesEvent)
0974: */
0975: public void queueEvent(FacesEvent event) {
0976: UIComponent eventComponent = event.getComponent();
0977: UIComponent parentTreeNode = eventComponent.getParent();
0978: while (parentTreeNode != null
0979: && !(parentTreeNode instanceof TreeNode)) {
0980: parentTreeNode = parentTreeNode.getParent();
0981: }
0982: if (parentTreeNode != null) {
0983: event = new NodeEvent(this , event,
0984: ((TreeNode) parentTreeNode).getMutable());
0985: }
0986: // ICE-1956 UICommand subclasses shouldn't call super.queueEvent
0987: // on ActionEvents or else the immediate flag is ignored
0988: // Shouldn't really be an issue for Tree though, since it tries
0989: // to wrap event in NodeEvent, which doesn't extend ActionEvent,
0990: // but we might as well still have this code so we're not brittle
0991: if ((event instanceof ActionEvent)
0992: && !this .equals(event.getComponent())
0993: && getParent() != null) {
0994: getParent().queueEvent(event);
0995: } else
0996: super .queueEvent(event);
0997: }
0998:
0999: /*
1000: * (non-Javadoc)
1001: *
1002: * @see javax.faces.component.UIComponent#broadcast(javax.faces.event.FacesEvent)
1003: */
1004: public void broadcast(FacesEvent event)
1005: throws AbortProcessingException {
1006:
1007: if (!(event instanceof NodeEvent)) {
1008: super .broadcast(event);
1009: return;
1010: }
1011:
1012: // Set up the correct context and fire our wrapped event
1013: NodeEvent wrapperEvent = (NodeEvent) event;
1014: DefaultMutableTreeNode eventNode = wrapperEvent.getNode();
1015: this .setCurrentNode(eventNode);
1016: this .setNodePath(TreeRenderer.getPathAsString(eventNode,
1017: (DefaultMutableTreeNode) getModel().getRoot()));
1018:
1019: FacesEvent facesEvent = wrapperEvent.getFacesEvent();
1020: facesEvent.getComponent().broadcast(facesEvent);
1021: }
1022:
1023: /**
1024: * @param context
1025: * @param currentVar
1026: */
1027: private void setCurrentVarToRequestMap(FacesContext context,
1028: DefaultMutableTreeNode currentVar) {
1029: Map requestMap = context.getExternalContext().getRequestMap();
1030: String varAttribute = getVar();
1031: if (currentVar != null) {
1032: requestMap.put(varAttribute, currentVar);
1033: }
1034: }
1035:
1036: /**
1037: * @return String hideNavigation
1038: */
1039: public String getHideNavigation() {
1040:
1041: if (hideNavigation != null) {
1042: return hideNavigation.toString();
1043: }
1044: ValueBinding vb = getValueBinding("hideNavigation");
1045: if (vb != null) {
1046: return vb.getValue(getFacesContext()).toString();
1047: }
1048: return String.valueOf(false);
1049:
1050: }
1051:
1052: /**
1053: * @param b
1054: */
1055: public void setHideNavigation(String b) {
1056: hideNavigation = new Boolean(b);
1057: }
1058:
1059: /**
1060: * @return String hideRootNode
1061: */
1062: public String getHideRootNode() {
1063:
1064: if (hideRootNode != null) {
1065: return hideRootNode.toString();
1066: }
1067: ValueBinding vb = getValueBinding("hideRootNode");
1068: if (vb != null) {
1069: return vb.getValue(getFacesContext()).toString();
1070: }
1071: return String.valueOf(false);
1072: }
1073:
1074: /**
1075: * @param b
1076: */
1077: public void setHideRootNode(String b) {
1078: hideRootNode = new Boolean(b);
1079: }
1080:
1081: // This class wraps TreeNode events
1082: // the TreeNode generates an event and the Tree.queueEvent()
1083: // wraps the event in a NodeEvent which the Tree.broadcast
1084: // recieves and passes on to the TreeNode.
1085: class NodeEvent extends FacesEvent {
1086:
1087: /**
1088: *
1089: */
1090: private static final long serialVersionUID = 1L;
1091:
1092: private FacesEvent event = null;
1093:
1094: private DefaultMutableTreeNode node = null;
1095:
1096: /**
1097: * @param component
1098: * @param event
1099: * @param node
1100: */
1101: public NodeEvent(UIComponent component, FacesEvent event,
1102: DefaultMutableTreeNode node) {
1103: super (component);
1104: this .event = event;
1105: this .node = node;
1106: }
1107:
1108: /**
1109: * @return DefaultMutableTreeNode node
1110: */
1111: public DefaultMutableTreeNode getNode() {
1112: return node;
1113: }
1114:
1115: /**
1116: * @param node
1117: */
1118: public void setNode(DefaultMutableTreeNode node) {
1119: this .node = node;
1120: }
1121:
1122: /**
1123: * @return FacesEvent event
1124: */
1125: public FacesEvent getFacesEvent() {
1126: return (this .event);
1127: }
1128:
1129: /* (non-Javadoc)
1130: * @see javax.faces.event.FacesEvent#getPhaseId()
1131: */
1132: public PhaseId getPhaseId() {
1133: return (this .event.getPhaseId());
1134: }
1135:
1136: /* (non-Javadoc)
1137: * @see javax.faces.event.FacesEvent#setPhaseId(javax.faces.event.PhaseId)
1138: */
1139: public void setPhaseId(PhaseId phaseId) {
1140: this .event.setPhaseId(phaseId);
1141: }
1142:
1143: /* (non-Javadoc)
1144: * @see javax.faces.event.FacesEvent#isAppropriateListener(javax.faces.event.FacesListener)
1145: */
1146: public boolean isAppropriateListener(FacesListener listener) {
1147: return (false);
1148: }
1149:
1150: /* (non-Javadoc)
1151: * @see javax.faces.event.FacesEvent#processListener(javax.faces.event.FacesListener)
1152: */
1153: public void processListener(FacesListener listener) {
1154: throw new IllegalStateException();
1155: }
1156:
1157: }
1158:
1159: /**
1160: * <p>This map contains <code>ChildState</code> instances for each child
1161: * component, keyed by the client id of the child.</p>
1162: */
1163: protected Map savedChildren = new HashMap();
1164:
1165: /**
1166: * <p>Restore state information for all child components.</p>
1167: *
1168: * @param context
1169: */
1170: protected void restoreChildrenState(FacesContext context) {
1171: Iterator kids = getChildren().iterator();
1172: while (kids.hasNext()) {
1173: UIComponent kid = (UIComponent) kids.next();
1174: restoreChildState(kid, context);
1175: }
1176: }
1177:
1178: /**
1179: * <p>Restore state information for the given child component.</p>
1180: *
1181: * @param component
1182: * @param context
1183: */
1184: protected void restoreChild(UIComponent component,
1185: FacesContext context) {
1186: // Restore state for this component (if it is a EditableValueHolder)
1187: if (component instanceof EditableValueHolder) {
1188: EditableValueHolder input = (EditableValueHolder) component;
1189: String clientId = component.getClientId(context);
1190: ChildState state = (ChildState) savedChildren.get(clientId);
1191: if (state == null) {
1192: state = new ChildState();
1193: }
1194: input.setValue(state.getValue());
1195: input.setValid(state.isValid());
1196: input.setSubmittedValue(state.getSubmittedValue());
1197: input.setLocalValueSet(state.isLocalValueSet());
1198: }
1199: }
1200:
1201: /**
1202: * <p>Restore state information for the given child component and its
1203: * children.</p>
1204: *
1205: * @param component
1206: * @param context
1207: */
1208: private void restoreChildState(UIComponent component,
1209: FacesContext context) {
1210:
1211: // Reset the client identifier for this component
1212: String id = component.getId();
1213: component.setId(id); // Forces client id to be reset
1214: // restore state for child component
1215: restoreChild(component, context);
1216:
1217: // Restore state for children of this component
1218: Iterator kids = component.getFacetsAndChildren();
1219: while (kids.hasNext()) {
1220: restoreChildState((UIComponent) kids.next(), context);
1221: }
1222: }
1223:
1224: /**
1225: * <p>Save state information for all children of this component.</p>
1226: *
1227: * @param context
1228: */
1229: protected void saveChildrenState(FacesContext context) {
1230:
1231: Iterator kids = getChildren().iterator();
1232: while (kids.hasNext()) {
1233: UIComponent kid = (UIComponent) kids.next();
1234: saveChildState(kid, context);
1235: }
1236: }
1237:
1238: /**
1239: * <p>Save state information for the given child component.</p>
1240: *
1241: * @param component
1242: * @param context
1243: */
1244: protected void saveChild(UIComponent component, FacesContext context) {
1245: // Save state for this component (if it is a EditableValueHolder)
1246: if (component instanceof EditableValueHolder) {
1247: EditableValueHolder input = (EditableValueHolder) component;
1248: String clientId = component.getClientId(context);
1249: ChildState state = (ChildState) savedChildren.get(clientId);
1250: if (state == null) {
1251: state = new ChildState();
1252: savedChildren.put(clientId, state);
1253: }
1254: state.setValue(input.getLocalValue());
1255: state.setValid(input.isValid());
1256: state.setSubmittedValue(input.getSubmittedValue());
1257: state.setLocalValueSet(input.isLocalValueSet());
1258: }
1259: }
1260:
1261: /**
1262: * <p>Save state information for the given child component and its
1263: * children.</p>
1264: *
1265: * @param component
1266: * @param context
1267: */
1268: protected void saveChildState(UIComponent component,
1269: FacesContext context) {
1270: // Save state for this child
1271: saveChild(component, context);
1272: // Save state for children of this component including facets as tree nodes are made up of facets
1273: Iterator kids = component.getFacetsAndChildren();
1274: while (kids.hasNext()) {
1275: saveChildState((UIComponent) kids.next(), context);
1276: }
1277: }
1278: }
1279:
1280: // Private class to represent saved state information for the children of the Tree component
1281:
1282: class ChildState implements Serializable {
1283:
1284: /**
1285: *
1286: */
1287: private static final long serialVersionUID = 1L;
1288: private Object submittedValue;
1289: private boolean valid = true;
1290: private Object value;
1291: private boolean localValueSet;
1292:
1293: Object getSubmittedValue() {
1294: return (this .submittedValue);
1295: }
1296:
1297: void setSubmittedValue(Object submittedValue) {
1298: this .submittedValue = submittedValue;
1299: }
1300:
1301: boolean isValid() {
1302: return (this .valid);
1303: }
1304:
1305: void setValid(boolean valid) {
1306: this .valid = valid;
1307: }
1308:
1309: Object getValue() {
1310: return (this .value);
1311: }
1312:
1313: /**
1314: * @param value
1315: */
1316: public void setValue(Object value) {
1317: this .value = value;
1318: }
1319:
1320: boolean isLocalValueSet() {
1321: return (this .localValueSet);
1322: }
1323:
1324: /**
1325: * @param localValueSet
1326: */
1327: public void setLocalValueSet(boolean localValueSet) {
1328: this.localValueSet = localValueSet;
1329: }
1330: }
|