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