001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.uif.container;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.kuali.rice.krad.datadictionary.validator.ErrorReport;
020    import org.kuali.rice.krad.datadictionary.validator.RDValidator;
021    import org.kuali.rice.krad.datadictionary.validator.TracerToken;
022    import org.kuali.rice.krad.uif.component.Component;
023    import org.kuali.rice.krad.uif.component.DataBinding;
024    import org.kuali.rice.krad.uif.field.Field;
025    import org.kuali.rice.krad.uif.field.FieldGroup;
026    import org.kuali.rice.krad.uif.view.View;
027    import org.kuali.rice.krad.uif.widget.Scrollpane;
028    import org.kuali.rice.krad.uif.widget.Disclosure;
029    
030    import java.util.ArrayList;
031    import java.util.HashSet;
032    import java.util.List;
033    import java.util.Set;
034    
035    /**
036     * Container that holds a list of <code>Field</code> or other <code>Group</code>
037     * instances
038     * 
039     * <p>
040     * Groups can exist at different levels of the <code>View</code>, providing
041     * conceptual groupings such as the page, section, and group. In addition, other
042     * group types can be created to add behavior like collection support
043     * </p>
044     * 
045     * <p>
046     * <code>Group</code> implementation has properties for defaulting the binding
047     * information (such as the parent object path and a binding prefix) for the
048     * fields it contains. During the phase these properties (if given) are set on
049     * the fields contained in the <code>Group</code> that implement
050     * <code>DataBinding</code>, unless they have already been set on the field.
051     * </p>
052     * 
053     * @author Kuali Rice Team (rice.collab@kuali.org)
054     */
055    public class Group extends ContainerBase {
056            private static final long serialVersionUID = 7953641325356535509L;
057    
058            private String fieldBindByNamePrefix;
059            private String fieldBindingObjectPath;
060    
061            private Disclosure disclosure;
062        private Scrollpane scrollpane;
063    
064            private List<? extends Component> items;
065    
066            /**
067             * Default Constructor
068             */
069            public Group() {
070                    items = new ArrayList<Component>();
071            }
072    
073            /**
074             * The following actions are performed:
075             * 
076             * <ul>
077             * <li>Sets the bindByNamePrefix if blank on any InputField and
078             * FieldGroup instances within the items List</li>
079             * </ul>
080             * 
081             * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
082             */
083        @Override
084        public void performInitialization(View view, Object model) {
085            super.performInitialization(view, model);
086    
087            for (Component component : getItems()) {
088                // append group's field bind by name prefix (if set) to each
089                // attribute field's binding prefix
090                if (component instanceof DataBinding) {
091                    DataBinding dataBinding = (DataBinding) component;
092    
093                    if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
094                        String bindByNamePrefixToSet = getFieldBindByNamePrefix();
095    
096                        if (StringUtils.isNotBlank(dataBinding.getBindingInfo().getBindByNamePrefix())) {
097                            bindByNamePrefixToSet += "." + dataBinding.getBindingInfo().getBindByNamePrefix();
098                        }
099                        dataBinding.getBindingInfo().setBindByNamePrefix(bindByNamePrefixToSet);
100                    }
101    
102                    if (StringUtils.isNotBlank(fieldBindingObjectPath) &&
103                            StringUtils.isBlank(dataBinding.getBindingInfo().getBindingObjectPath())) {
104                        dataBinding.getBindingInfo().setBindingObjectPath(fieldBindingObjectPath);
105                    }
106                }
107                // set on FieldGroup's group to recursively set AttributeFields
108                else if (component instanceof FieldGroup) {
109                    FieldGroup fieldGroup = (FieldGroup) component;
110    
111                    if (fieldGroup.getGroup() != null) {
112                        if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindByNamePrefix())) {
113                            fieldGroup.getGroup().setFieldBindByNamePrefix(fieldBindByNamePrefix);
114                        }
115                        if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindingObjectPath())) {
116                            fieldGroup.getGroup().setFieldBindingObjectPath(fieldBindingObjectPath);
117                        }
118                    }
119                } else if (component instanceof Group) {
120                    Group subGroup = (Group) component;
121                    if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
122                        if (StringUtils.isNotBlank(subGroup.getFieldBindByNamePrefix())) {
123                            subGroup.setFieldBindByNamePrefix(
124                                    getFieldBindByNamePrefix() + "." + subGroup.getFieldBindByNamePrefix());
125                        } else {
126                            subGroup.setFieldBindByNamePrefix(getFieldBindByNamePrefix());
127                        }
128                    }
129                    if (StringUtils.isNotBlank(getFieldBindingObjectPath())) {
130                        if (StringUtils.isNotBlank(subGroup.getFieldBindingObjectPath())) {
131                            subGroup.setFieldBindingObjectPath(
132                                    getFieldBindingObjectPath() + "." + subGroup.getFieldBindingObjectPath());
133                        } else {
134                            subGroup.setFieldBindingObjectPath(getFieldBindingObjectPath());
135                        }
136                    }
137                }
138            }
139        }
140    
141            /**
142             * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
143             */
144            @Override
145            public List<Component> getComponentsForLifecycle() {
146                    List<Component> components = super.getComponentsForLifecycle();
147    
148                    components.add(disclosure);
149            components.add(scrollpane);
150    
151                    return components;
152            }
153    
154            /**
155             * @see org.kuali.rice.krad.uif.container.Container#getSupportedComponents()
156             */
157            @Override
158            public Set<Class<? extends Component>> getSupportedComponents() {
159                    Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>();
160                    supportedComponents.add(Field.class);
161                    supportedComponents.add(Group.class);
162    
163                    return supportedComponents;
164            }
165    
166            /**
167             * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName()
168             */
169            @Override
170            public String getComponentTypeName() {
171                    return "group";
172            }
173    
174            /**
175             * Binding prefix string to set on each of the groups <code>DataField</code> instances
176         *
177             * <p>
178             * As opposed to setting the bindingPrefix on each attribute field instance,
179             * it can be set here for the group. During initialize the string will then
180             * be set on each attribute field instance if the bindingPrefix is blank and
181             * not a form field
182             * </p>
183             * 
184             * @return String binding prefix to set
185             */
186            public String getFieldBindByNamePrefix() {
187                    return this.fieldBindByNamePrefix;
188            }
189    
190            /**
191             * Setter for the field binding prefix
192             * 
193             * @param fieldBindByNamePrefix
194             */
195            public void setFieldBindByNamePrefix(String fieldBindByNamePrefix) {
196                    this.fieldBindByNamePrefix = fieldBindByNamePrefix;
197            }
198    
199            /**
200             * Object binding path to set on each of the group's
201             * <code>InputField</code> instances
202             * 
203             * <p>
204             * When the attributes of the group belong to a object whose path is
205             * different from the default then this property can be given to set each of
206             * the attributes instead of setting the model path on each one. The object
207             * path can be overridden at the attribute level. The object path is set to
208             * the fieldBindingObjectPath during the initialize phase.
209             * </p>
210             * 
211             * @return String model path to set
212             * @see org.kuali.rice.krad.uif.component.BindingInfo#getBindingObjectPath()
213             */
214            public String getFieldBindingObjectPath() {
215                    return this.fieldBindingObjectPath;
216            }
217    
218            /**
219             * Setter for the field object binding path
220             * 
221             * @param fieldBindingObjectPath
222             */
223            public void setFieldBindingObjectPath(String fieldBindingObjectPath) {
224                    this.fieldBindingObjectPath = fieldBindingObjectPath;
225            }
226    
227            /**
228             * Disclosure widget that provides collapse/expand functionality for the
229             * group
230             * 
231             * @return Disclosure instance
232             */
233            public Disclosure getDisclosure() {
234                    return this.disclosure;
235            }
236    
237            /**
238             * Setter for the group's disclosure instance
239             * 
240             * @param disclosure
241             */
242            public void setDisclosure(Disclosure disclosure) {
243                    this.disclosure = disclosure;
244            }
245    
246        /**
247         * Scrollpane widget that provides scrolling functionality for the
248         * group
249         *
250         * @return Scrollpane instance
251         */
252        public Scrollpane getScrollpane() {
253            return this.scrollpane;
254        }
255    
256        /**
257         * Setter for the group's scrollpane instance
258         *
259         * @param scrollpane
260         */
261        public void setScrollpane(Scrollpane scrollpane) {
262            this.scrollpane = scrollpane;
263        }
264    
265        /**
266             * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems()
267             */
268            @Override
269            public List<? extends Component> getItems() {
270                    return this.items;
271            }
272    
273            /**
274             * Setter for the Group's list of components
275             * 
276             * @param items
277             */
278            @Override
279            public void setItems(List<? extends Component> items) {
280                    this.items = items;
281            }
282    
283        /**
284         * @see org.kuali.rice.krad.uif.component.Component#completeValidation
285         */
286        @Override
287        public ArrayList<ErrorReport> completeValidation(TracerToken tracer){
288            ArrayList<ErrorReport> reports=new ArrayList<ErrorReport>();
289            tracer.addBean(this);
290    
291            // Checks that no invalid items are present
292            for(int i=0;i<getItems().size();i++){
293                if(getItems().get(i).getClass()==PageGroup.class || getItems().get(i).getClass()==NavigationGroup.class){
294                    ErrorReport error = ErrorReport.createError("Items in Group cannot be PageGroup or NaviagtionGroup",tracer);
295                    error.addCurrentValue("item("+i+").class ="+getItems().get(i).getClass());
296                    reports.add(error);
297                }
298            }
299    
300            // Checks that the layout manager is set
301            if(getLayoutManager()==null){
302                if(RDValidator.checkExpressions(this,"layoutManager")){
303                    ErrorReport error = ErrorReport.createError("LayoutManager must be set",tracer);
304                    error.addCurrentValue("layoutManager = "+getLayoutManager());
305                    reports.add(error);
306                }
307            }
308    
309            reports.addAll(super.completeValidation(tracer.getCopy()));
310    
311            return reports;
312        }
313    }