001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.krad.uif.container;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.krad.uif.component.Component;
020import org.kuali.rice.krad.uif.component.DataBinding;
021import org.kuali.rice.krad.uif.component.ComponentSecurity;
022import org.kuali.rice.krad.uif.field.Field;
023import org.kuali.rice.krad.uif.field.FieldGroup;
024import org.kuali.rice.krad.uif.view.View;
025import org.kuali.rice.krad.uif.widget.Disclosure;
026
027import java.util.ArrayList;
028import java.util.HashSet;
029import java.util.List;
030import java.util.Set;
031
032/**
033 * Container that holds a list of <code>Field</code> or other <code>Group</code>
034 * instances
035 * 
036 * <p>
037 * Groups can exist at different levels of the <code>View</code>, providing
038 * conceptual groupings such as the page, section, and group. In addition, other
039 * group types can be created to add behavior like collection support
040 * </p>
041 * 
042 * <p>
043 * <code>Group</code> implementation has properties for defaulting the binding
044 * information (such as the parent object path and a binding prefix) for the
045 * fields it contains. During the phase these properties (if given) are set on
046 * the fields contained in the <code>Group</code> that implement
047 * <code>DataBinding</code>, unless they have already been set on the field.
048 * </p>
049 * 
050 * @author Kuali Rice Team (rice.collab@kuali.org)
051 */
052public class Group extends ContainerBase {
053        private static final long serialVersionUID = 7953641325356535509L;
054
055        private String fieldBindByNamePrefix;
056        private String fieldBindingObjectPath;
057
058        private Disclosure disclosure;
059
060        private List<? extends Component> items;
061
062        /**
063         * Default Constructor
064         */
065        public Group() {
066                items = new ArrayList<Component>();
067        }
068
069        /**
070         * The following actions are performed:
071         * 
072         * <ul>
073         * <li>Sets the bindByNamePrefix if blank on any InputField and
074         * FieldGroup instances within the items List</li>
075         * </ul>
076         * 
077         * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
078         */
079    @Override
080    public void performInitialization(View view, Object model) {
081        super.performInitialization(view, model);
082
083        for (Component component : getItems()) {
084            // append group's field bind by name prefix (if set) to each
085            // attribute field's binding prefix
086            if (component instanceof DataBinding) {
087                DataBinding dataBinding = (DataBinding) component;
088
089                if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
090                    String bindByNamePrefixToSet = getFieldBindByNamePrefix();
091
092                    if (StringUtils.isNotBlank(dataBinding.getBindingInfo().getBindByNamePrefix())) {
093                        bindByNamePrefixToSet += "." + dataBinding.getBindingInfo().getBindByNamePrefix();
094                    }
095                    dataBinding.getBindingInfo().setBindByNamePrefix(bindByNamePrefixToSet);
096                }
097
098                if (StringUtils.isNotBlank(fieldBindingObjectPath) &&
099                        StringUtils.isBlank(dataBinding.getBindingInfo().getBindingObjectPath())) {
100                    dataBinding.getBindingInfo().setBindingObjectPath(fieldBindingObjectPath);
101                }
102            }
103            // set on FieldGroup's group to recursively set AttributeFields
104            else if (component instanceof FieldGroup) {
105                FieldGroup fieldGroup = (FieldGroup) component;
106
107                if (fieldGroup.getGroup() != null) {
108                    if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindByNamePrefix())) {
109                        fieldGroup.getGroup().setFieldBindByNamePrefix(fieldBindByNamePrefix);
110                    }
111                    if (StringUtils.isBlank(fieldGroup.getGroup().getFieldBindingObjectPath())) {
112                        fieldGroup.getGroup().setFieldBindingObjectPath(fieldBindingObjectPath);
113                    }
114                }
115            } else if (component instanceof Group) {
116                Group subGroup = (Group) component;
117                if (StringUtils.isNotBlank(getFieldBindByNamePrefix())) {
118                    if (StringUtils.isNotBlank(subGroup.getFieldBindByNamePrefix())) {
119                        subGroup.setFieldBindByNamePrefix(
120                                getFieldBindByNamePrefix() + "." + subGroup.getFieldBindByNamePrefix());
121                    } else {
122                        subGroup.setFieldBindByNamePrefix(getFieldBindByNamePrefix());
123                    }
124                }
125                if (StringUtils.isNotBlank(getFieldBindingObjectPath())) {
126                    if (StringUtils.isNotBlank(subGroup.getFieldBindingObjectPath())) {
127                        subGroup.setFieldBindingObjectPath(
128                                getFieldBindingObjectPath() + "." + subGroup.getFieldBindingObjectPath());
129                    } else {
130                        subGroup.setFieldBindingObjectPath(getFieldBindingObjectPath());
131                    }
132                }
133            }
134        }
135    }
136
137        /**
138         * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
139         */
140        @Override
141        public List<Component> getComponentsForLifecycle() {
142                List<Component> components = super.getComponentsForLifecycle();
143
144                components.add(disclosure);
145
146                return components;
147        }
148
149        /**
150         * @see org.kuali.rice.krad.web.view.container.ContainerBase#getSupportedComponents()
151         */
152        @Override
153        public Set<Class<? extends Component>> getSupportedComponents() {
154                Set<Class<? extends Component>> supportedComponents = new HashSet<Class<? extends Component>>();
155                supportedComponents.add(Field.class);
156                supportedComponents.add(Group.class);
157
158                return supportedComponents;
159        }
160
161        /**
162         * @see org.kuali.rice.krad.uif.component.Component#getComponentTypeName()
163         */
164        @Override
165        public final String getComponentTypeName() {
166                return "group";
167        }
168
169        /**
170         * Binding prefix string to set on each of the groups <code>DataField</code> instances
171     *
172         * <p>
173         * As opposed to setting the bindingPrefix on each attribute field instance,
174         * it can be set here for the group. During initialize the string will then
175         * be set on each attribute field instance if the bindingPrefix is blank and
176         * not a form field
177         * </p>
178         * 
179         * @return String binding prefix to set
180         */
181        public String getFieldBindByNamePrefix() {
182                return this.fieldBindByNamePrefix;
183        }
184
185        /**
186         * Setter for the field binding prefix
187         * 
188         * @param fieldBindByNamePrefix
189         */
190        public void setFieldBindByNamePrefix(String fieldBindByNamePrefix) {
191                this.fieldBindByNamePrefix = fieldBindByNamePrefix;
192        }
193
194        /**
195         * Object binding path to set on each of the group's
196         * <code>InputField</code> instances
197         * 
198         * <p>
199         * When the attributes of the group belong to a object whose path is
200         * different from the default then this property can be given to set each of
201         * the attributes instead of setting the model path on each one. The object
202         * path can be overridden at the attribute level. The object path is set to
203         * the fieldBindingObjectPath during the initialize phase.
204         * </p>
205         * 
206         * @return String model path to set
207         * @see org.kuali.rice.krad.uif.BindingInfo.getBindingObjectPath()
208         */
209        public String getFieldBindingObjectPath() {
210                return this.fieldBindingObjectPath;
211        }
212
213        /**
214         * Setter for the field object binding path
215         * 
216         * @param fieldBindingObjectPath
217         */
218        public void setFieldBindingObjectPath(String fieldBindingObjectPath) {
219                this.fieldBindingObjectPath = fieldBindingObjectPath;
220        }
221
222        /**
223         * Disclosure widget that provides collapse/expand functionality for the
224         * group
225         * 
226         * @return Accordion instance
227         */
228        public Disclosure getDisclosure() {
229                return this.disclosure;
230        }
231
232        /**
233         * Setter for the group's disclosure instance
234         * 
235         * @param disclosure
236         */
237        public void setDisclosure(Disclosure disclosure) {
238                this.disclosure = disclosure;
239        }
240
241    /**
242         * @see org.kuali.rice.krad.uif.container.ContainerBase#getItems()
243         */
244        @Override
245        public List<? extends Component> getItems() {
246                return this.items;
247        }
248
249        /**
250         * Setter for the Group's list of components
251         * 
252         * @param items
253         */
254        @Override
255        public void setItems(List<? extends Component> items) {
256                this.items = items;
257        }
258
259}