View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.container;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
22  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
23  import org.kuali.rice.krad.datadictionary.validator.Validator;
24  import org.kuali.rice.krad.uif.component.Component;
25  import org.kuali.rice.krad.uif.component.DataBinding;
26  import org.kuali.rice.krad.uif.field.Field;
27  import org.kuali.rice.krad.uif.field.FieldGroup;
28  import org.kuali.rice.krad.uif.view.View;
29  import org.kuali.rice.krad.uif.widget.Disclosure;
30  import org.kuali.rice.krad.uif.widget.Scrollpane;
31  
32  import java.util.ArrayList;
33  import java.util.HashSet;
34  import java.util.List;
35  import java.util.Set;
36  
37  /**
38   * Container that holds a list of <code>Field</code> or other <code>Group</code>
39   * instances
40   *
41   * <p>
42   * Groups can exist at different levels of the <code>View</code>, providing
43   * conceptual groupings such as the page, section, and group. In addition, other
44   * group types can be created to add behavior like collection support
45   * </p>
46   *
47   * <p>
48   * <code>Group</code> implementation has properties for defaulting the binding
49   * information (such as the parent object path and a binding prefix) for the
50   * fields it contains. During the phase these properties (if given) are set on
51   * the fields contained in the <code>Group</code> that implement
52   * <code>DataBinding</code>, unless they have already been set on the field.
53   * </p>
54   *
55   * @author Kuali Rice Team (rice.collab@kuali.org)
56   */
57  @BeanTags({@BeanTag(name = "group-bean", parent = "Uif-GroupBase"),
58          @BeanTag(name = "boxGroupBase-bean", parent = "Uif-BoxGroupBase"),
59          @BeanTag(name = "verticalBoxGroup-bean", parent = "Uif-VerticalBoxGroup"),
60          @BeanTag(name = "verticalBoxSection-bean", parent = "Uif-VerticalBoxSection"),
61          @BeanTag(name = "verticalBoxSubSection-bean", parent = "Uif-VerticalBoxSubSection"),
62          @BeanTag(name = "disclosure-verticalBoxSection-bean", parent = "Uif-Disclosure-VerticalBoxSection"),
63          @BeanTag(name = "disclosure-verticalBoxSubSection-bean", parent = "Uif-Disclosure-VerticalBoxSubSection"),
64          @BeanTag(name = "horizontalBoxGroup-bean", parent = "Uif-HorizontalBoxGroup"),
65          @BeanTag(name = "horizontalBoxSection-bean", parent = "Uif-HorizontalBoxSection"),
66          @BeanTag(name = "horizontalBoxSubSection-bean", parent = "Uif-HorizontalBoxSubSection"),
67          @BeanTag(name = "disclosure-horizontalBoxSection-bean", parent = "Uif-Disclosure-HorizontalBoxSection"),
68          @BeanTag(name = "disclosure-horizontalBoxSubSection-bean", parent = "Uif-Disclosure-HorizontalBoxSubSection"),
69          @BeanTag(name = "gridGroup-bean", parent = "Uif-GridGroup"),
70          @BeanTag(name = "gridSection-bean", parent = "Uif-GridSection"),
71          @BeanTag(name = "gridSubSection-bean", parent = "Uif-GridSubSection"),
72          @BeanTag(name = "disclosure-gridSection-bean", parent = "Uif-Disclosure-GridSection"),
73          @BeanTag(name = "disclosure-gridSubSection-bean", parent = "Uif-Disclosure-GridSubSection"),
74          @BeanTag(name = "listGroup-bean", parent = "Uif-ListGroup"),
75          @BeanTag(name = "listSection-bean", parent = "Uif-ListSection"),
76          @BeanTag(name = "listSubSection-bean", parent = "Uif-ListSubSection"),
77          @BeanTag(name = "disclosure-listSection-bean", parent = "Uif-Disclosure-ListSection"),
78          @BeanTag(name = "disclosure-listSubSection-bean", parent = "Uif-Disclosure-ListSubSection"),
79          @BeanTag(name = "collectionGridItem-bean", parent = "Uif-CollectionGridItem"),
80          @BeanTag(name = "collectionVerticalBoxItem-bean", parent = "Uif-CollectionVerticalBoxItem"),
81          @BeanTag(name = "collectionHorizontalBoxItem-bean", parent = "Uif-CollectionHorizontalBoxItem"),
82          @BeanTag(name = "headerUpperGroup-bean", parent = "Uif-HeaderUpperGroup"),
83          @BeanTag(name = "headerRightGroup-bean", parent = "Uif-HeaderRightGroup"),
84          @BeanTag(name = "headerLowerGroup-bean", parent = "Uif-HeaderLowerGroup"),
85          @BeanTag(name = "footer-bean", parent = "Uif-FooterBase"),
86          @BeanTag(name = "formFooter-bean", parent = "Uif-FormFooter"),
87          @BeanTag(name = "actionsGroup-bean", parent = "Uif-ActionsGroup"),
88          @BeanTag(name = "disclosureActionsGroup-bean", parent = "Uif-DisclosureActionsGroup"),
89          @BeanTag(name = "disclosureActions-reqMessageGroup-bean", parent = "Uif-DisclosureActions-ReqMessageGroup"),
90          @BeanTag(name = "inactiveItemsActionsGroup-bean", parent = "Uif-InactiveItemsActionsGroup"),
91          @BeanTag(name = "documentInfoGroup-bean", parent = "Uif-DocumentInfoGroup"),
92          @BeanTag(name = "documentOverviewSection-bean", parent = "Uif-DocumentOverviewSection"),
93          @BeanTag(name = "documentAdHocRecipientsSection-bean", parent = "Uif-DocumentAdHocRecipientsSection"),
94          @BeanTag(name = "documentRouteLogSection-bean", parent = "Uif-DocumentRouteLogSection"),
95          @BeanTag(name = "documentPageFooter-bean", parent = "Uif-DocumentPageFooter"),
96          @BeanTag(name = "incidentDetailGroup-bean", parent = "Uif-IncidentDetailGroup"),
97          @BeanTag(name = "incidentStackTraceGroup-bean", parent = "Uif-IncidentStackTraceGroup"),
98          @BeanTag(name = "incidentReportFooter-bean", parent = "Uif-IncidentReportFooter"),
99          @BeanTag(name = "initiatedDocumentFooter-bean", parent = "InitiatedDocumentFooter"),
100         @BeanTag(name = "inquiryFooter-bean", parent = "Uif-InquiryFooter"),
101         @BeanTag(name = "lookupCriteriaGroup-bean", parent = "Uif-LookupCriteriaGroup"),
102         @BeanTag(name = "lookupPageHeaderGroup-bean", parent = "Uif-LookupPageHeaderGroup"),
103         @BeanTag(name = "lookupCriteriaFooter-bean", parent = "Uif-LookupCriteriaFooter"),
104         @BeanTag(name = "lookupResultsFooter-bean", parent = "Uif-LookupResultsFooter"),
105         @BeanTag(name = "maintenanceGridGroup-bean", parent = "Uif-MaintenanceGridGroup"),
106         @BeanTag(name = "maintenanceHorizontalBoxGroup-bean", parent = "Uif-MaintenanceHorizontalBoxGroup"),
107         @BeanTag(name = "maintenanceVerticalBoxGroup-bean", parent = "Uif-MaintenanceVerticalBoxGroup"),
108         @BeanTag(name = "maintenanceGridSection-bean", parent = "Uif-MaintenanceGridSection"),
109         @BeanTag(name = "maintenanceGridSubSection-bean", parent = "Uif-MaintenanceGridSubSection"),
110         @BeanTag(name = "maintenanceHorizontalBoxSection-bean", parent = "Uif-MaintenanceHorizontalBoxSection"),
111         @BeanTag(name = "maintenanceVerticalBoxSection-bean", parent = "Uif-MaintenanceVerticalBoxSection"),
112         @BeanTag(name = "maintenanceHorizontalBoxSubSection-bean", parent = "Uif-MaintenanceHorizontalBoxSubSection"),
113         @BeanTag(name = "maintenanceVerticalBoxSubSection-bean", parent = "Uif-MaintenanceVerticalBoxSubSection")
114 })
115 public class Group extends ContainerBase {
116     private static final long serialVersionUID = 7953641325356535509L;
117 
118     private String fieldBindByNamePrefix;
119     private String fieldBindingObjectPath;
120 
121     private Disclosure disclosure;
122     private Scrollpane scrollpane;
123 
124     private List<? extends Component> items;
125 
126     /**
127      * Default Constructor
128      */
129     public Group() {
130         items = new ArrayList<Component>();
131     }
132 
133     /**
134      * The following actions are performed:
135      *
136      * <ul>
137      * <li>Sets the bindByNamePrefix if blank on any InputField and
138      * FieldGroup instances within the items List</li>
139      * </ul>
140      *
141      * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View,
142      *      java.lang.Object)
143      */
144     @Override
145     public void performInitialization(View view, Object model) {
146         super.performInitialization(view, model);
147 
148         for (Component component : getItems()) {
149             // append group's field bind by name prefix (if set) to each
150             // attribute field's binding prefix
151             if (component instanceof DataBinding) {
152                 DataBinding dataBinding = (DataBinding) component;
153 
154                 if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
155                     String bindByNamePrefixToSet = getFieldBindByNamePrefix();
156 
157                     if (StringUtils.isNotBlank(dataBinding.getBindingInfo().getBindByNamePrefix())) {
158                         bindByNamePrefixToSet += "." + dataBinding.getBindingInfo().getBindByNamePrefix();
159                     }
160                     dataBinding.getBindingInfo().setBindByNamePrefix(bindByNamePrefixToSet);
161                 }
162 
163                 if (StringUtils.isNotBlank(fieldBindingObjectPath) && StringUtils.isBlank(
164                         dataBinding.getBindingInfo().getBindingObjectPath())) {
165                     dataBinding.getBindingInfo().setBindingObjectPath(fieldBindingObjectPath);
166                 }
167             }
168             // set on FieldGroup's group to recursively set AttributeFields
169             else if (component instanceof FieldGroup) {
170                 FieldGroup fieldGroup = (FieldGroup) component;
171 
172                 if (fieldGroup.getGroup() != null) {
173                     if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindByNamePrefix())) {
174                         fieldGroup.getGroup().setFieldBindByNamePrefix(fieldBindByNamePrefix);
175                     }
176                     if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindingObjectPath())) {
177                         fieldGroup.getGroup().setFieldBindingObjectPath(fieldBindingObjectPath);
178                     }
179                 }
180             } else if (component instanceof Group) {
181                 Group subGroup = (Group) component;
182                 if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
183                     if (StringUtils.isNotBlank(subGroup.getFieldBindByNamePrefix())) {
184                         subGroup.setFieldBindByNamePrefix(
185                                 getFieldBindByNamePrefix() + "." + subGroup.getFieldBindByNamePrefix());
186                     } else {
187                         subGroup.setFieldBindByNamePrefix(getFieldBindByNamePrefix());
188                     }
189                 }
190                 if (StringUtils.isNotBlank(getFieldBindingObjectPath())) {
191                     if (StringUtils.isNotBlank(subGroup.getFieldBindingObjectPath())) {
192                         subGroup.setFieldBindingObjectPath(
193                                 getFieldBindingObjectPath() + "." + subGroup.getFieldBindingObjectPath());
194                     } else {
195                         subGroup.setFieldBindingObjectPath(getFieldBindingObjectPath());
196                     }
197                 }
198             }
199         }
200     }
201 
202     /**
203      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
204      */
205     @Override
206     public List<Component> getComponentsForLifecycle() {
207         List<Component> components = super.getComponentsForLifecycle();
208 
209         components.add(disclosure);
210         components.add(scrollpane);
211 
212         return components;
213     }
214 
215     /**
216      * @see org.kuali.rice.krad.uif.container.Container#getSupportedComponents()
217      */
218     @Override
219     public Set<Class<? extends Component>> getSupportedComponents() {
220         Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>();
221         supportedComponents.add(Field.class);
222         supportedComponents.add(Group.class);
223 
224         return supportedComponents;
225     }
226 
227     /**
228      * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName()
229      */
230     @Override
231     public String getComponentTypeName() {
232         return "group";
233     }
234 
235     /**
236      * Binding prefix string to set on each of the groups <code>DataField</code> instances
237      *
238      * <p>
239      * As opposed to setting the bindingPrefix on each attribute field instance,
240      * it can be set here for the group. During initialize the string will then
241      * be set on each attribute field instance if the bindingPrefix is blank and
242      * not a form field
243      * </p>
244      *
245      * @return String binding prefix to set
246      */
247     @BeanTagAttribute(name = "fieldBindByNamePrefix")
248     public String getFieldBindByNamePrefix() {
249         return this.fieldBindByNamePrefix;
250     }
251 
252     /**
253      * Setter for the field binding prefix
254      *
255      * @param fieldBindByNamePrefix
256      */
257     public void setFieldBindByNamePrefix(String fieldBindByNamePrefix) {
258         this.fieldBindByNamePrefix = fieldBindByNamePrefix;
259     }
260 
261     /**
262      * Object binding path to set on each of the group's
263      * <code>InputField</code> instances
264      *
265      * <p>
266      * When the attributes of the group belong to a object whose path is
267      * different from the default then this property can be given to set each of
268      * the attributes instead of setting the model path on each one. The object
269      * path can be overridden at the attribute level. The object path is set to
270      * the fieldBindingObjectPath during the initialize phase.
271      * </p>
272      *
273      * @return String model path to set
274      * @see org.kuali.rice.krad.uif.component.BindingInfo#getBindingObjectPath()
275      */
276     @BeanTagAttribute(name = "fieldBindingObjectPath")
277     public String getFieldBindingObjectPath() {
278         return this.fieldBindingObjectPath;
279     }
280 
281     /**
282      * Setter for the field object binding path
283      *
284      * @param fieldBindingObjectPath
285      */
286     public void setFieldBindingObjectPath(String fieldBindingObjectPath) {
287         this.fieldBindingObjectPath = fieldBindingObjectPath;
288     }
289 
290     /**
291      * Disclosure widget that provides collapse/expand functionality for the
292      * group
293      *
294      * @return Disclosure instance
295      */
296     @BeanTagAttribute(name = "Disclosure", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
297     public Disclosure getDisclosure() {
298         return this.disclosure;
299     }
300 
301     /**
302      * Setter for the group's disclosure instance
303      *
304      * @param disclosure
305      */
306     public void setDisclosure(Disclosure disclosure) {
307         this.disclosure = disclosure;
308     }
309 
310     /**
311      * Scrollpane widget that provides scrolling functionality for the
312      * group
313      *
314      * @return Scrollpane instance
315      */
316     @BeanTagAttribute(name = "scrollpane", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
317     public Scrollpane getScrollpane() {
318         return this.scrollpane;
319     }
320 
321     /**
322      * Setter for the group's scrollpane instance
323      *
324      * @param scrollpane
325      */
326     public void setScrollpane(Scrollpane scrollpane) {
327         this.scrollpane = scrollpane;
328     }
329 
330     /**
331      * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems()
332      */
333     @Override
334     @BeanTagAttribute(name = "items", type = BeanTagAttribute.AttributeType.LISTBEAN)
335     public List<? extends Component> getItems() {
336         return this.items;
337     }
338 
339     /**
340      * Setter for the Group's list of components
341      *
342      * @param items
343      */
344     @Override
345     public void setItems(List<? extends Component> items) {
346         this.items = items;
347     }
348 
349     /**
350      * @see org.kuali.rice.krad.uif.component.Component#completeValidation
351      */
352     @Override
353     public void completeValidation(ValidationTrace tracer) {
354         tracer.addBean(this);
355 
356         // Checks that no invalid items are present
357         for (int i = 0; i < getItems().size(); i++) {
358             if (getItems().get(i).getClass() == PageGroup.class || getItems().get(i).getClass()
359                     == NavigationGroup.class) {
360                 String currentValues[] = {"item(" + i + ").class =" + getItems().get(i).getClass()};
361                 tracer.createError("Items in Group cannot be PageGroup or NaviagtionGroup", currentValues);
362             }
363         }
364 
365         // Checks that the layout manager is set
366         if (getLayoutManager() == null) {
367             if (Validator.checkExpressions(this, "layoutManager")) {
368                 String currentValues[] = {"layoutManager = " + getLayoutManager()};
369                 tracer.createError("LayoutManager must be set", currentValues);
370             }
371         }
372 
373         super.completeValidation(tracer.getCopy());
374     }
375 }