1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 package org.apache.myfaces.custom.tree2;
21
22 import org.apache.commons.lang.StringUtils;
23 import java.util.Stack;
24
25 /**
26 * A base implementation of the {@link TreeWalker} interface. Uses a simple node naming
27 * scheme of "0" for the root node, "0:0" for the first child, "0:1" for the second child, etc.
28 */
29 public class TreeWalkerBase implements TreeWalker
30 {
31 private String ROOT_NODE_ID = "0";
32 private String TREE_NODE_SEPARATOR = ":";
33
34 private Tree tree;
35 private Stack nodeStack = new Stack();
36 private Stack idStack = new Stack();
37 private boolean checkState = true;
38 private boolean startedWalking = false;
39
40 // see interface
41 public void setTree(Tree tree)
42 {
43 this.tree = tree;
44 }
45
46 // see interface
47 public boolean isCheckState()
48 {
49 return checkState;
50 }
51
52 // see interface
53 public void setCheckState(boolean checkState)
54 {
55 this.checkState = checkState;
56 }
57
58 // see interface
59 public boolean next()
60 {
61 if (!startedWalking)
62 {
63 // the first next() call just needs to set the root node and push it onto the stack
64 idStack.push(ROOT_NODE_ID);
65 tree.setNodeId(ROOT_NODE_ID);
66 nodeStack.push(tree.getNode());
67
68 startedWalking = true;
69 return true;
70 }
71
72 if (nodeStack.isEmpty())
73 {
74 return false;
75 }
76
77 TreeNode prevNode = (TreeNode)nodeStack.peek();
78 String prevNodeId = (String)idStack.peek();
79
80 if (prevNode.isLeaf())
81 {
82 nodeStack.pop();
83 idStack.pop();
84
85 return next();
86 }
87 else
88 {
89 TreeNode nextNode = null;
90 String nextNodeId = null;
91
92 if (prevNodeId.equals(tree.getNodeId()))
93 {
94 /**
95 * We know there is at least one child b/c otherwise we would have popped the node after
96 * checking isLeaf. Basically we need to keep drilling down until we reach the deepest
97 * node that is available for "walking." Then we'll return to the parent and render its
98 * siblings and walk back up the tree.
99 */
100 nextNodeId = prevNodeId + TREE_NODE_SEPARATOR + "0";
101
102 // don't render any children if the node is not expanded
103 if (checkState)
104 {
105 if (!tree.getDataModel().getTreeState().isNodeExpanded(prevNodeId))
106 {
107 nodeStack.pop();
108 idStack.pop();
109
110 return next();
111 }
112 }
113 }
114 else
115 {
116 // get the parent node
117 String currentNodeId = tree.getNodeId();
118 String parentNodeId = StringUtils.substringBeforeLast(currentNodeId, TREE_NODE_SEPARATOR);
119 tree.setNodeId(parentNodeId);
120 TreeNode parentNode = tree.getNode();
121
122 int siblingCount = Integer.parseInt(currentNodeId.substring(parentNodeId.length()+1));
123 siblingCount++;
124
125 if (siblingCount == parentNode.getChildCount())
126 {
127 // no more siblings
128 nodeStack.pop();
129 idStack.pop();
130
131 return next();
132 }
133
134 nextNodeId = parentNodeId + TREE_NODE_SEPARATOR + siblingCount;
135 }
136
137 tree.setNodeId(nextNodeId);
138 nextNode = tree.getNode();
139
140 nodeStack.push(nextNode);
141 idStack.push(nextNodeId);
142
143 return true;
144 }
145 }
146
147 // see interface
148 public String getRootNodeId()
149 {
150 return ROOT_NODE_ID;
151 }
152
153 // see interface
154 public void reset()
155 {
156 nodeStack.empty();
157 idStack.empty();
158 startedWalking = false;
159 }
160 }