View Javadoc

1   package org.kuali.rice.kns.uif.container;
2   
3   import org.kuali.rice.core.util.Node;
4   import org.kuali.rice.core.util.Tree;
5   import org.kuali.rice.kns.uif.UifConstants;
6   import org.kuali.rice.kns.uif.core.BindingInfo;
7   import org.kuali.rice.kns.uif.core.Component;
8   import org.kuali.rice.kns.uif.field.MessageField;
9   import org.kuali.rice.kns.uif.util.ComponentUtils;
10  import org.kuali.rice.kns.uif.util.ObjectPropertyUtils;
11  import org.kuali.rice.kns.uif.widget.TreeWidget;
12  
13  import java.util.ArrayList;
14  import java.util.HashMap;
15  import java.util.List;
16  import java.util.Map;
17  
18  /**
19   * Group component that is backed by a <code>Tree</code> data structure and typically
20   * rendered as a tree in the user interface
21   *
22   * @author Kuali Rice Team (rice.collab@kuali.org)
23   */
24  public class TreeGroup extends Group {
25      private static final long serialVersionUID = 5841343037089286740L;
26  
27      private String propertyName;
28      private BindingInfo bindingInfo;
29  
30      private Group dataGroupPrototype;
31  
32      private MessageField nodeLabelPrototype;
33      private Map<String, String> nodeTypeStyleClasses;
34  
35      private Tree<Group, MessageField> treeGroups;
36  
37      private TreeWidget treeWidget;
38  
39      public TreeGroup() {
40          super();
41  
42          nodeTypeStyleClasses = new HashMap<String, String>();
43          treeGroups = new Tree<Group, MessageField>();
44      }
45  
46      /**
47       * The following actions are performed:
48       *
49       * <ul>
50       * <li>Set fieldBindModelPath to the collection model path (since the fields
51       * have to belong to the same model as the collection)</li>
52       * <li>Set defaults for binding</li>
53       * <li>Calls view helper service to initialize prototypes</li>
54       * </ul>
55       *
56       * @see org.kuali.rice.kns.uif.core.ComponentBase#performInitialization(org.kuali.rice.kns.uif.container.View)
57       */
58      @Override
59      public void performInitialization(View view) {
60          setFieldBindingObjectPath(getBindingInfo().getBindingObjectPath());
61  
62          super.performInitialization(view);
63  
64          if (bindingInfo != null) {
65              bindingInfo.setDefaults(view, getPropertyName());
66          }
67  
68          // TODO: set object path for prototypes equal to the tree group object path?
69  
70          view.getViewHelperService().performComponentInitialization(view, nodeLabelPrototype);
71          view.getViewHelperService().performComponentInitialization(view, dataGroupPrototype);
72      }
73  
74      /**
75       * @see org.kuali.rice.kns.uif.container.ContainerBase#performApplyModel(org.kuali.rice.kns.uif.container.View,
76       *      java.lang.Object)
77       */
78      @Override
79      public void performApplyModel(View view, Object model) {
80          super.performApplyModel(view, model);
81  
82          buildTreeGroups(view, model);
83      }
84  
85      /**
86       * Builds the components that will be rendered as part of the tree group
87       *
88       * <p>
89       *  The component tree group mirrors the tree data structure on the model. For each node of
90       *  the data structure, a corresponding <code>MessageField</code>  will be created for the node
91       *  label, and a <code>Group</code> component for the node data. These are placed into a new
92       *  node for the component tree. After the tree is built it is set as a property on the tree group
93       *  to be read by the renderer
94       * </p>
95       *
96       * @param view - view instance the tree group belongs to
97       * @param model - object containing the view data from which the tree data will be retrieved
98       */
99      protected void buildTreeGroups(View view, Object model) {
100         // get Tree data property
101         Tree<Object, String> treeData = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath());
102 
103         // build component tree that corresponds with tree data
104         Tree<Group, MessageField> treeGroups = new Tree<Group, MessageField>();
105 
106         String bindingPrefix = getBindingInfo().getBindingPrefixForNested();
107         Node<Group, MessageField> rootNode = buildTreeNode(treeData.getRootElement(), bindingPrefix, 0);
108         treeGroups.setRootElement(rootNode);
109 
110         setTreeGroups(treeGroups);
111     }
112 
113     protected Node<Group, MessageField> buildTreeNode(Node<Object, String> nodeData, String bindingPrefix, int nodeCounter) {
114         Node<Group, MessageField> node = new Node<Group, MessageField>();
115 
116         String idSuffix = "_n" + nodeCounter;
117 
118         MessageField messageField = ComponentUtils.copy(this.nodeLabelPrototype, idSuffix);
119         ComponentUtils.pushObjectToContext(messageField, UifConstants.ContextVariableNames.NODE, nodeData);
120         messageField.setMessageText(nodeData.getNodeLabel());
121         node.setNodeLabel(messageField);
122 
123         Group nodeGroup = ComponentUtils.copyComponent(this.dataGroupPrototype, bindingPrefix + ".data", idSuffix);
124         ComponentUtils.pushObjectToContext(nodeGroup, UifConstants.ContextVariableNames.NODE, nodeData);
125         node.setData(nodeGroup);
126 
127         List<Node<Group, MessageField>> nodeChildren = new ArrayList<Node<Group, MessageField>>();
128 
129         int childIndex = -1;
130         for (Node<Object, String> childDataNode : nodeData.getChildren()) {
131             String nextBindingPrefix = bindingPrefix + ".children[" + childIndex + "]";
132             Node<Group, MessageField> childNode = buildTreeNode(childDataNode, nextBindingPrefix, nodeCounter++);
133 
134             nodeChildren.add(childNode);
135         }
136         node.setChildren(nodeChildren);
137 
138         return node;
139     }
140 
141     /**
142      * @see org.kuali.rice.kns.uif.container.ContainerBase#getNestedComponents()
143      */
144     @Override
145     public List<Component> getNestedComponents() {
146         List<Component> components = super.getNestedComponents();
147 
148         components.add(treeWidget);
149         addNodeComponents(treeGroups.getRootElement(), components);
150 
151         return components;
152     }
153 
154     /**
155      * Retrieves the <code>Component</code> instances from the node for building the nested
156      * components list
157      *
158      * @param node - node to pull components from
159      * @param components - list to add components to
160      */
161     protected void addNodeComponents(Node<Group, MessageField> node, List<Component> components) {
162         if (node != null) {
163             components.add(node.getNodeLabel());
164             components.add(node.getData());
165 
166             for (Node<Group, MessageField> nodeChild : node.getChildren()) {
167                 addNodeComponents(nodeChild, components);
168             }
169         }
170     }
171 
172     public String getPropertyName() {
173         return propertyName;
174     }
175 
176     public void setPropertyName(String propertyName) {
177         this.propertyName = propertyName;
178     }
179 
180     public BindingInfo getBindingInfo() {
181         return bindingInfo;
182     }
183 
184     public void setBindingInfo(BindingInfo bindingInfo) {
185         this.bindingInfo = bindingInfo;
186     }
187 
188     public Group getDataGroupPrototype() {
189         return dataGroupPrototype;
190     }
191 
192     public void setDataGroupPrototype(Group dataGroupPrototype) {
193         this.dataGroupPrototype = dataGroupPrototype;
194     }
195 
196     public MessageField getNodeLabelPrototype() {
197         return nodeLabelPrototype;
198     }
199 
200     public void setNodeLabelPrototype(MessageField nodeLabelPrototype) {
201         this.nodeLabelPrototype = nodeLabelPrototype;
202     }
203 
204     public Map<String, String> getNodeTypeStyleClasses() {
205         return nodeTypeStyleClasses;
206     }
207 
208     public void setNodeTypeStyleClasses(Map<String, String> nodeTypeStyleClasses) {
209         this.nodeTypeStyleClasses = nodeTypeStyleClasses;
210     }
211 
212     public Tree<Group, MessageField> getTreeGroups() {
213         return treeGroups;
214     }
215 
216     public void setTreeGroups(Tree<Group, MessageField> treeGroups) {
217         this.treeGroups = treeGroups;
218     }
219 
220     public TreeWidget getTreeWidget() {
221         return treeWidget;
222     }
223 
224     public void setTreeWidget(TreeWidget treeWidget) {
225         this.treeWidget = treeWidget;
226     }
227 }