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 }