001 /* 002 * Copyright 2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 1.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/ecl1.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.uif.component.Component; 020 import org.kuali.rice.krad.uif.component.ComponentBase; 021 import org.kuali.rice.krad.uif.field.AttributeField; 022 import org.kuali.rice.krad.uif.field.ErrorsField; 023 import org.kuali.rice.krad.uif.field.HeaderField; 024 import org.kuali.rice.krad.uif.field.MessageField; 025 import org.kuali.rice.krad.uif.layout.LayoutManager; 026 import org.kuali.rice.krad.uif.util.ComponentUtils; 027 import org.kuali.rice.krad.uif.view.View; 028 import org.kuali.rice.krad.uif.widget.Help; 029 030 import java.util.ArrayList; 031 import java.util.List; 032 033 /** 034 * Base <code>Container</code> implementation which container implementations 035 * can extend 036 * 037 * <p> 038 * Provides properties for the basic <code>Container</code> functionality in 039 * addition to default implementation of the lifecycle methods including some 040 * setup of the header, items list, and layout manager 041 * </p> 042 * 043 * @author Kuali Rice Team (rice.collab@kuali.org) 044 */ 045 public abstract class ContainerBase extends ComponentBase implements Container { 046 private static final long serialVersionUID = -4182226230601746657L; 047 048 private int itemOrderingSequence; 049 050 private String additionalMessageKeys; 051 private ErrorsField errorsField; 052 053 private Help help; 054 private LayoutManager layoutManager; 055 056 private HeaderField header; 057 private Group footer; 058 059 private String summary; 060 private MessageField summaryMessageField; 061 062 private boolean fieldContainer; 063 064 /** 065 * Default Constructor 066 */ 067 public ContainerBase() { 068 itemOrderingSequence = 1; 069 } 070 071 /** 072 * The following initialization is performed: 073 * 074 * <ul> 075 * <li>Sorts the containers list of components</li> 076 * <li>Initializes LayoutManager</li> 077 * </ul> 078 * 079 * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View) 080 */ 081 @SuppressWarnings("unchecked") 082 @Override 083 public void performInitialization(View view) { 084 super.performInitialization(view); 085 086 // sort items list by the order property 087 List<? extends Component> sortedItems = (List<? extends Component>) ComponentUtils.sort(getItems(), 088 itemOrderingSequence); 089 setItems(sortedItems); 090 091 if (layoutManager != null) { 092 layoutManager.performInitialization(view, this); 093 } 094 } 095 096 /** 097 * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View, 098 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 099 */ 100 @Override 101 public void performApplyModel(View view, Object model, Component parent) { 102 super.performApplyModel(view, model, parent); 103 104 if (layoutManager != null) { 105 layoutManager.performApplyModel(view, model, this); 106 } 107 } 108 109 /** 110 * The following finalization is performed: 111 * 112 * <ul> 113 * <li>Sets the headerText of the header Group if it is blank</li> 114 * <li>Set the messageText of the summary MessageField if it is blank</li> 115 * <li>Finalizes LayoutManager</li> 116 * </ul> 117 * 118 * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View, 119 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 120 */ 121 @Override 122 public void performFinalize(View view, Object model, Component parent) { 123 super.performFinalize(view, model, parent); 124 125 // if header title not given, use the container title 126 if (header != null && StringUtils.isBlank(header.getHeaderText())) { 127 header.setHeaderText(this.getTitle()); 128 } 129 130 // setup summary message field if necessary 131 if (summaryMessageField != null && StringUtils.isBlank(summaryMessageField.getMessageText())) { 132 summaryMessageField.setMessageText(summary); 133 } 134 135 if (layoutManager != null) { 136 layoutManager.performFinalize(view, model, this); 137 } 138 } 139 140 /** 141 * @see org.kuali.rice.krad.uif.component.ComponentBase#getNestedComponents() 142 */ 143 @Override 144 public List<Component> getNestedComponents() { 145 List<Component> components = super.getNestedComponents(); 146 147 components.add(header); 148 components.add(footer); 149 components.add(errorsField); 150 components.add(help); 151 components.add(summaryMessageField); 152 153 for (Component component : getItems()) { 154 components.add(component); 155 } 156 157 if (layoutManager != null) { 158 components.addAll(layoutManager.getNestedComponents()); 159 } 160 161 return components; 162 } 163 164 /** 165 * Additional keys that should be matching on when gathering errors or other 166 * messages for the <code>Container</code> 167 * 168 * <p> 169 * Messages associated with the container will be displayed with the 170 * container grouping in the user interface. Typically, these are a result 171 * of problems with the containers fields or some other business logic 172 * associated with the containers information. The framework will by default 173 * include all the error keys for fields in the container, and also an 174 * errors associated with the containers id. Keys given here will be matched 175 * in addition to those defaults. 176 * </p> 177 * 178 * <p> 179 * Multple keys can be given using the comma delimiter, the * wildcard is 180 * also allowed in the message key 181 * </p> 182 * 183 * @return String additional message key string 184 */ 185 public String getAdditionalMessageKeys() { 186 return this.additionalMessageKeys; 187 } 188 189 /** 190 * Setter for the components additional message key string 191 * 192 * @param additionalMessageKeys 193 */ 194 public void setAdditionalMessageKeys(String additionalMessageKeys) { 195 this.additionalMessageKeys = additionalMessageKeys; 196 } 197 198 /** 199 * @see org.kuali.rice.krad.uif.container.Container#getErrorsField() 200 */ 201 @Override 202 public ErrorsField getErrorsField() { 203 return this.errorsField; 204 } 205 206 /** 207 * @see org.kuali.rice.krad.uif.container.Container#setErrorsField(org.kuali.rice.krad.uif.field.ErrorsField) 208 */ 209 @Override 210 public void setErrorsField(ErrorsField errorsField) { 211 this.errorsField = errorsField; 212 } 213 214 /** 215 * @see org.kuali.rice.krad.uif.container.Container#getHelp() 216 */ 217 @Override 218 public Help getHelp() { 219 return this.help; 220 } 221 222 /** 223 * @see org.kuali.rice.krad.uif.container.Container#setHelp(org.kuali.rice.krad.uif.widget.Help) 224 */ 225 @Override 226 public void setHelp(Help help) { 227 this.help = help; 228 } 229 230 /** 231 * @see org.kuali.rice.krad.uif.container.Container#getItems() 232 */ 233 @Override 234 public abstract List<? extends Component> getItems(); 235 236 /** 237 * Setter for the containers list of components 238 * 239 * @param items 240 */ 241 public abstract void setItems(List<? extends Component> items); 242 243 /** 244 * For <code>Component</code> instances in the container's items list that 245 * do not have an order set, a default order number will be assigned using 246 * this property. The first component found in the list without an order 247 * will be assigned the configured initial value, and incremented by one for 248 * each component (without an order) found afterwards 249 * 250 * @return int order sequence 251 */ 252 public int getItemOrderingSequence() { 253 return this.itemOrderingSequence; 254 } 255 256 /** 257 * Setter for the container's item ordering sequence number (initial value) 258 * 259 * @param itemOrderingSequence 260 */ 261 public void setItemOrderingSequence(int itemOrderingSequence) { 262 this.itemOrderingSequence = itemOrderingSequence; 263 } 264 265 /** 266 * @see org.kuali.rice.krad.uif.container.Container#getLayoutManager() 267 */ 268 @Override 269 public LayoutManager getLayoutManager() { 270 return this.layoutManager; 271 } 272 273 /** 274 * @see org.kuali.rice.krad.uif.container.Container#setLayoutManager(org.kuali.rice.krad.uif.layout.LayoutManager) 275 */ 276 @Override 277 public void setLayoutManager(LayoutManager layoutManager) { 278 this.layoutManager = layoutManager; 279 } 280 281 /** 282 * @see org.kuali.rice.krad.uif.container.Container#getHeader() 283 */ 284 @Override 285 public HeaderField getHeader() { 286 return this.header; 287 } 288 289 /** 290 * @see org.kuali.rice.krad.uif.container.Container#setHeader(org.kuali.rice.krad.uif.field.HeaderField) 291 */ 292 @Override 293 public void setHeader(HeaderField header) { 294 this.header = header; 295 } 296 297 /** 298 * @see org.kuali.rice.krad.uif.container.Container#getFooter() 299 */ 300 @Override 301 public Group getFooter() { 302 return this.footer; 303 } 304 305 /** 306 * @see org.kuali.rice.krad.uif.container.Container#setFooter(org.kuali.rice.krad.uif.container.Group) 307 */ 308 @Override 309 public void setFooter(Group footer) { 310 this.footer = footer; 311 } 312 313 /** 314 * Convenience setter for configuration to turn rendering of the header 315 * on/off 316 * 317 * <p> 318 * For nested groups (like Field Groups) it is often necessary to only show 319 * the container body (the contained components). This method allows the 320 * header to not be displayed 321 * </p> 322 * 323 * @param renderHeader 324 */ 325 public void setRenderHeader(boolean renderHeader) { 326 if (header != null) { 327 header.setRender(renderHeader); 328 } 329 } 330 331 /** 332 * Convenience setter for configuration to turn rendering of the footer 333 * on/off 334 * 335 * <p> 336 * For nested groups it is often necessary to only show the container body 337 * (the contained components). This method allows the footer to not be 338 * displayed 339 * </p> 340 * 341 * @param renderFooter 342 */ 343 public void setRenderFooter(boolean renderFooter) { 344 if (footer != null) { 345 footer.setRender(renderFooter); 346 } 347 } 348 349 /** 350 * Summary text for the container which will be used to set the summary 351 * message field 352 * 353 * @return String summary text 354 * @see org.kuali.rice.krad.uif.container.Container#getSummaryMessageField() 355 */ 356 public String getSummary() { 357 return this.summary; 358 } 359 360 /** 361 * Setter for the containers summary text 362 * 363 * @param summary 364 */ 365 public void setSummary(String summary) { 366 this.summary = summary; 367 } 368 369 /** 370 * @see org.kuali.rice.krad.uif.container.Container#getSummaryMessageField() 371 */ 372 @Override 373 public MessageField getSummaryMessageField() { 374 return this.summaryMessageField; 375 } 376 377 /** 378 * @see org.kuali.rice.krad.uif.container.Container#setSummaryMessageField(org.kuali.rice.krad.uif.field.MessageField) 379 */ 380 @Override 381 public void setSummaryMessageField(MessageField summaryMessageField) { 382 this.summaryMessageField = summaryMessageField; 383 } 384 385 /** 386 * Gets only the attribute fields that are nested in this container. This is a subset of 387 * what getNestedComponents() returns. 388 * 389 * @return 390 */ 391 public List<AttributeField> getAttributeFields(){ 392 List<AttributeField> attributeFields = new ArrayList<AttributeField>(); 393 for(Component c: this.getNestedComponents()){ 394 if(c instanceof AttributeField){ 395 attributeFields.add((AttributeField)c); 396 } 397 } 398 return attributeFields; 399 400 } 401 402 /** 403 * This property is true if the container is used to display a group of fields that is visually a single 404 * field. 405 * @return the fieldContainer 406 */ 407 public boolean isFieldContainer() { 408 return this.fieldContainer; 409 } 410 411 /** 412 * @param fieldContainer the fieldContainer to set 413 */ 414 public void setFieldContainer(boolean fieldContainer) { 415 this.fieldContainer = fieldContainer; 416 } 417 418 }