1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.krad.uif.container;
17
18 import com.google.common.collect.Maps;
19 import org.apache.commons.lang.StringUtils;
20 import org.kuali.rice.core.api.util.tree.Node;
21 import org.kuali.rice.core.api.util.tree.Tree;
22 import org.kuali.rice.krad.datadictionary.parse.BeanTag;
23 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
24 import org.kuali.rice.krad.datadictionary.parse.BeanTags;
25 import org.kuali.rice.krad.uif.UifConstants;
26 import org.kuali.rice.krad.uif.component.BindingInfo;
27 import org.kuali.rice.krad.uif.component.Component;
28 import org.kuali.rice.krad.uif.component.DataBinding;
29 import org.kuali.rice.krad.uif.element.Message;
30 import org.kuali.rice.krad.uif.util.ComponentUtils;
31 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
32 import org.kuali.rice.krad.uif.view.View;
33
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Map;
37
38
39
40
41
42
43
44 @BeanTags({@BeanTag(name = "treeGroup-bean", parent = "Uif-TreeGroup"),
45 @BeanTag(name = "treeSection-bean", parent = "Uif-TreeSection"),
46 @BeanTag(name = "treeSubSection-bean", parent = "Uif-TreeSubSection")})
47 public class TreeGroup extends Group implements DataBinding {
48 private static final long serialVersionUID = 5841343037089286740L;
49
50 private String propertyName;
51 private BindingInfo bindingInfo;
52
53 private Map<Class<?>, NodePrototype> nodePrototypeMap;
54 private NodePrototype defaultNodePrototype;
55
56 private Tree<Group, Message> treeGroups;
57
58 private org.kuali.rice.krad.uif.widget.Tree tree;
59
60 public TreeGroup() {
61 super();
62
63 treeGroups = new Tree<Group, Message>();
64 }
65
66
67
68
69
70
71
72
73
74
75
76 @Override
77 public void performInitialization(View view, Object model) {
78 setFieldBindingObjectPath(getBindingInfo().getBindingObjectPath());
79
80 super.performInitialization(view, model);
81
82 if (bindingInfo != null) {
83 bindingInfo.setDefaults(view, getPropertyName());
84 }
85
86
87 }
88
89 @Override
90 public void performApplyModel(View view, Object model, Component parent) {
91 super.performApplyModel(view, model, parent);
92
93 buildTreeGroups(view, model);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 protected void buildTreeGroups(View view, Object model) {
111
112 Tree<Object, String> treeData = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath());
113
114
115 Tree<Group, Message> treeGroups = new Tree<Group, Message>();
116
117 String bindingPrefix = getBindingInfo().getBindingPrefixForNested();
118 Node<Group, Message> rootNode = buildTreeNode(treeData.getRootElement(),
119 bindingPrefix +
120 treeGroups.setRootElement(rootNode);
121
122 setTreeGroups(treeGroups);
123 }
124
125 protected Node<Group, Message> buildTreeNode(Node<Object, String> nodeData, String bindingPrefix,
126 String parentNode) {
127 if (nodeData == null) {
128 return null;
129 }
130
131 Node<Group, Message> node = new Node<Group, Message>();
132 node.setNodeType(nodeData.getNodeType());
133
134 NodePrototype prototype = getNodePrototype(nodeData);
135
136 Message message = ComponentUtils.copy(prototype.getLabelPrototype(), parentNode);
137 ComponentUtils.pushObjectToContext(message, UifConstants.ContextVariableNames.NODE, nodeData);
138 message.setMessageText(nodeData.getNodeLabel());
139 node.setNodeLabel(message);
140
141 Group nodeGroup = ComponentUtils.copyComponent(prototype.getDataGroupPrototype(), bindingPrefix + ".data",
142 parentNode);
143 ComponentUtils.pushObjectToContext(nodeGroup, UifConstants.ContextVariableNames.NODE, nodeData);
144
145 String nodePath = bindingPrefix + ".data";
146 if (StringUtils.isNotBlank(getBindingInfo().getBindingObjectPath())) {
147 nodePath = getBindingInfo().getBindingObjectPath() + "." + nodePath;
148 }
149 ComponentUtils.pushObjectToContext(nodeGroup, UifConstants.ContextVariableNames.NODE_PATH, nodePath);
150 node.setData(nodeGroup);
151
152 List<Node<Group, Message>> nodeChildren = new ArrayList<Node<Group, Message>>();
153
154 int childIndex = 0;
155 for (Node<Object, String> childDataNode : nodeData.getChildren()) {
156 String nextBindingPrefix = bindingPrefix + ".children[" + childIndex + "]";
157 Node<Group, Message> childNode = buildTreeNode(childDataNode, nextBindingPrefix,
158 "_node_" + childIndex + ("root".equals(parentNode) ? "_parent_" : "_parent") + parentNode);
159
160 nodeChildren.add(childNode);
161
162
163 ++childIndex;
164 }
165 node.setChildren(nodeChildren);
166
167 return node;
168 }
169
170
171
172
173 private NodePrototype getNodePrototype(Node<Object, String> nodeData) {
174 NodePrototype result = null;
175 if (nodeData != null && nodeData.getData() != null) {
176 Class<?> dataClass = nodeData.getData().getClass();
177 result = nodePrototypeMap.get(dataClass);
178
179
180
181 if (result == null) {
182 for (Map.Entry<Class<?>, NodePrototype> prototypeEntry : nodePrototypeMap.entrySet()) {
183 if (prototypeEntry.getKey().isAssignableFrom(dataClass)) {
184 result = prototypeEntry.getValue();
185 break;
186 }
187 }
188 }
189 }
190
191 if (result == null) {
192 result = defaultNodePrototype;
193 }
194
195 return result;
196 }
197
198
199
200
201 @Override
202 public List<Component> getComponentsForLifecycle() {
203 List<Component> components = super.getComponentsForLifecycle();
204
205 components.add(tree);
206 addNodeComponents(treeGroups.getRootElement(), components);
207
208 return components;
209 }
210
211
212
213
214 @Override
215 public List<Component> getComponentPrototypes() {
216 List<Component> components = super.getComponentPrototypes();
217
218 if (defaultNodePrototype != null) {
219 components.add(defaultNodePrototype.getLabelPrototype());
220 components.add(defaultNodePrototype.getDataGroupPrototype());
221 }
222
223 if (nodePrototypeMap != null) {
224 for (Map.Entry<Class<?>, NodePrototype> prototypeEntry : nodePrototypeMap.entrySet()) {
225 NodePrototype prototype = prototypeEntry.getValue();
226 if (prototype != null) {
227 components.add(prototype.getLabelPrototype());
228 components.add(prototype.getDataGroupPrototype());
229 }
230 }
231 }
232
233 return components;
234 }
235
236
237
238
239
240
241
242
243 protected void addNodeComponents(Node<Group, Message> node, List<Component> components) {
244 if (node != null) {
245 components.add(node.getNodeLabel());
246 components.add(node.getData());
247
248 for (Node<Group, Message> nodeChild : node.getChildren()) {
249 addNodeComponents(nodeChild, components);
250 }
251 }
252 }
253
254 @BeanTagAttribute(name = "propertyName")
255 public String getPropertyName() {
256 return propertyName;
257 }
258
259 public void setPropertyName(String propertyName) {
260 this.propertyName = propertyName;
261 }
262
263 @BeanTagAttribute(name = "bindingInfo", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
264 public BindingInfo getBindingInfo() {
265 return bindingInfo;
266 }
267
268 public void setBindingInfo(BindingInfo bindingInfo) {
269 this.bindingInfo = bindingInfo;
270 }
271
272
273
274
275 @BeanTagAttribute(name = "defaultNodePrototype", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
276 public NodePrototype getDefaultNodePrototype() {
277 return this.defaultNodePrototype;
278 }
279
280
281
282
283 public void setDefaultNodePrototype(NodePrototype defaultNodePrototype) {
284 this.defaultNodePrototype = defaultNodePrototype;
285 }
286
287
288
289
290 @BeanTagAttribute(name = "NodePrototypeMap", type = BeanTagAttribute.AttributeType.MAPBEAN)
291 public Map<Class<?>, NodePrototype> getNodePrototypeMap() {
292 return this.nodePrototypeMap;
293 }
294
295
296
297
298 public void setNodePrototypeMap(Map<Class<?>, NodePrototype> nodePrototypeMap) {
299 this.nodePrototypeMap = nodePrototypeMap;
300 }
301
302 @BeanTagAttribute(name = "treeGroups", type = BeanTagAttribute.AttributeType.MAP2BEAN)
303 public Tree<Group, Message> getTreeGroups() {
304 return treeGroups;
305 }
306
307 public void setTreeGroups(Tree<Group, Message> treeGroups) {
308 this.treeGroups = treeGroups;
309 }
310
311 @BeanTagAttribute(name = "tree", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
312 public org.kuali.rice.krad.uif.widget.Tree getTree() {
313 return tree;
314 }
315
316 public void setTree(org.kuali.rice.krad.uif.widget.Tree tree) {
317 this.tree = tree;
318 }
319
320
321
322
323 @Override
324 protected <T> void copyProperties(T component) {
325 super.copyProperties(component);
326 TreeGroup treeGroupCopy = (TreeGroup) component;
327 treeGroupCopy.setPropertyName(this.propertyName);
328
329 if (this.bindingInfo != null) {
330 treeGroupCopy.setBindingInfo((BindingInfo) this.bindingInfo.copy());
331 }
332
333 if (this.defaultNodePrototype != null) {
334 treeGroupCopy.setDefaultNodePrototype((NodePrototype) this.defaultNodePrototype.copy());
335 }
336
337 if (this.treeGroups != null) {
338 Tree<Group, Message> treeGroupsCopy = new Tree<Group, Message>();
339 treeGroupsCopy.setRootElement(copyNode(this.treeGroups.getRootElement()));
340
341 treeGroupCopy.setTreeGroups(treeGroupsCopy);
342 }
343
344 if (this.tree != null) {
345 treeGroupCopy.setTree((org.kuali.rice.krad.uif.widget.Tree) this.tree.copy());
346 }
347
348 if (this.nodePrototypeMap != null) {
349 Map<Class<?>, NodePrototype> nodePrototypeMapCopy = Maps.newHashMapWithExpectedSize(
350 this.getNodePrototypeMap().size());
351 for (Map.Entry<Class<?>, NodePrototype> nodePrototypeMapEntry : nodePrototypeMap.entrySet()) {
352 NodePrototype prototypeCopy = nodePrototypeMapEntry.getValue().copy();
353 nodePrototypeMapCopy.put(nodePrototypeMapEntry.getKey(), prototypeCopy);
354 }
355
356 treeGroupCopy.setNodePrototypeMap(nodePrototypeMapCopy);
357 }
358 }
359
360
361
362
363
364
365
366 protected Node<Group, Message> copyNode(Node<Group, Message> node) {
367 Node<Group, Message> nodeCopy = new Node<Group, Message>();
368
369 if (node == null) {
370 return null;
371 }
372
373 if (node.getData() != null) {
374 nodeCopy.setData((Group) node.getData().copy());
375 }
376
377 if (node.getNodeLabel() != null) {
378 nodeCopy.setNodeLabel((Message) node.getNodeLabel().copy());
379 }
380
381 if (node.getChildren() != null) {
382 List<Node<Group, Message>> childrenCopy = new ArrayList<Node<Group, Message>>();
383 for (Node<Group, Message> childNode : node.getChildren()) {
384 childrenCopy.add(copyNode(childNode));
385 }
386
387 nodeCopy.setChildren(childrenCopy);
388 }
389
390 return nodeCopy;
391 }
392 }