View Javadoc

1   /**
2    * Copyright 2005-2012 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 org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.uif.component.Component;
20  import org.kuali.rice.krad.uif.component.ComponentBase;
21  import org.kuali.rice.krad.uif.field.FieldGroup;
22  import org.kuali.rice.krad.uif.field.InputField;
23  import org.kuali.rice.krad.uif.field.ErrorsField;
24  import org.kuali.rice.krad.uif.field.HeaderField;
25  import org.kuali.rice.krad.uif.field.MessageField;
26  import org.kuali.rice.krad.uif.layout.LayoutManager;
27  import org.kuali.rice.krad.uif.util.ComponentUtils;
28  import org.kuali.rice.krad.uif.view.View;
29  import org.kuali.rice.krad.uif.widget.Help;
30  
31  import java.util.ArrayList;
32  import java.util.List;
33  
34  /**
35   * Base <code>Container</code> implementation which container implementations
36   * can extend
37   * 
38   * <p>
39   * Provides properties for the basic <code>Container</code> functionality in
40   * addition to default implementation of the lifecycle methods including some
41   * setup of the header, items list, and layout manager
42   * </p>
43   * 
44   * @author Kuali Rice Team (rice.collab@kuali.org)
45   */
46  public abstract class ContainerBase extends ComponentBase implements Container {
47  	private static final long serialVersionUID = -4182226230601746657L;
48  
49  	private int itemOrderingSequence;
50  
51  	private String additionalMessageKeys;
52  	private ErrorsField errorsField;
53  
54  	private Help help;
55  	private LayoutManager layoutManager;
56  
57  	private HeaderField header;
58  	private Group footer;
59  
60  	private String instructionalText;
61  	private MessageField instructionalMessageField;
62  
63  	private boolean fieldContainer;
64  
65  	/**
66  	 * Default Constructor
67  	 */
68  	public ContainerBase() {
69  		itemOrderingSequence = 1;
70  	}
71  
72  	/**
73  	 * The following initialization is performed:
74  	 * 
75  	 * <ul>
76  	 * <li>Sorts the containers list of components</li>
77  	 * <li>Initializes LayoutManager</li>
78  	 * </ul>
79  	 * 
80  	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
81  	 */
82  	@SuppressWarnings("unchecked")
83  	@Override
84  	public void performInitialization(View view, Object model) {
85  		super.performInitialization(view, model);
86  
87  		// sort items list by the order property
88  		List<? extends Component> sortedItems = (List<? extends Component>) ComponentUtils.sort(getItems(),
89  				itemOrderingSequence);
90  		setItems(sortedItems);
91  
92  		if (layoutManager != null) {
93  			layoutManager.performInitialization(view, model, this);
94  		}
95  	}
96  
97  	/**
98  	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
99  	 *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
100 	 */
101 	@Override
102 	public void performApplyModel(View view, Object model, Component parent) {
103 		super.performApplyModel(view, model, parent);
104 
105 		if (layoutManager != null) {
106 			layoutManager.performApplyModel(view, model, this);
107 		}
108 	}
109 
110 	/**
111 	 * The following finalization is performed:
112 	 * 
113 	 * <ul>
114 	 * <li>Sets the headerText of the header Group if it is blank</li>
115 	 * <li>Set the messageText of the summary MessageField if it is blank</li>
116 	 * <li>Finalizes LayoutManager</li>
117 	 * </ul>
118 	 * 
119 	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
120 	 *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
121 	 */
122 	@Override
123 	public void performFinalize(View view, Object model, Component parent) {
124 		super.performFinalize(view, model, parent);
125 
126 		// if header title not given, use the container title
127 		if (header != null && StringUtils.isBlank(header.getHeaderText())) {
128 			header.setHeaderText(this.getTitle());
129 		}
130 
131 		// setup summary message field if necessary
132 		if (instructionalMessageField != null && StringUtils.isBlank(instructionalMessageField.getMessageText())) {
133 			instructionalMessageField.setMessageText(instructionalText);
134 		}
135 
136 		if (layoutManager != null) {
137 			layoutManager.performFinalize(view, model, this);
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(header);
149 		components.add(footer);
150 		components.add(errorsField);
151 		components.add(help);
152 		components.add(instructionalMessageField);
153 
154 		for (Component component : getItems()) {
155 			components.add(component);
156 		}
157 
158 		if (layoutManager != null) {
159 			components.addAll(layoutManager.getComponentsForLifecycle());
160 		}
161 
162 		return components;
163 	}
164 
165     /**
166      * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
167      */
168     @Override
169     public List<Component> getComponentPrototypes() {
170         List<Component> components = super.getComponentPrototypes();
171 
172         if (layoutManager != null) {
173             components.addAll(layoutManager.getComponentPrototypes());
174         }
175 
176         return components;
177     }
178 
179 	/**
180 	 * Additional keys that should be matching on when gathering errors or other
181 	 * messages for the <code>Container</code>
182 	 * 
183 	 * <p>
184 	 * Messages associated with the container will be displayed with the
185 	 * container grouping in the user interface. Typically, these are a result
186 	 * of problems with the containers fields or some other business logic
187 	 * associated with the containers information. The framework will by default
188 	 * include all the error keys for fields in the container, and also an
189 	 * errors associated with the containers id. Keys given here will be matched
190 	 * in addition to those defaults.
191 	 * </p>
192 	 * 
193 	 * <p>
194 	 * Multple keys can be given using the comma delimiter, the * wildcard is
195 	 * also allowed in the message key
196 	 * </p>
197 	 * 
198 	 * @return String additional message key string
199 	 */
200 	public String getAdditionalMessageKeys() {
201 		return this.additionalMessageKeys;
202 	}
203 
204 	/**
205 	 * Setter for the components additional message key string
206 	 * 
207 	 * @param additionalMessageKeys
208 	 */
209 	public void setAdditionalMessageKeys(String additionalMessageKeys) {
210 		this.additionalMessageKeys = additionalMessageKeys;
211 	}
212 
213 	/**
214 	 * @see org.kuali.rice.krad.uif.container.Container#getErrorsField()
215 	 */
216 	@Override
217 	public ErrorsField getErrorsField() {
218 		return this.errorsField;
219 	}
220 
221 	/**
222 	 * @see org.kuali.rice.krad.uif.container.Container#setErrorsField(org.kuali.rice.krad.uif.field.ErrorsField)
223 	 */
224 	@Override
225 	public void setErrorsField(ErrorsField errorsField) {
226 		this.errorsField = errorsField;
227 	}
228 
229 	/**
230 	 * @see org.kuali.rice.krad.uif.container.Container#getHelp()
231 	 */
232 	@Override
233 	public Help getHelp() {
234 		return this.help;
235 	}
236 
237 	/**
238 	 * @see org.kuali.rice.krad.uif.container.Container#setHelp(org.kuali.rice.krad.uif.widget.Help)
239 	 */
240 	@Override
241 	public void setHelp(Help help) {
242 		this.help = help;
243 	}
244 
245 	/**
246 	 * @see org.kuali.rice.krad.uif.container.Container#getItems()
247 	 */
248 	@Override
249 	public abstract List<? extends Component> getItems();
250 
251 	/**
252 	 * Setter for the containers list of components
253 	 * 
254 	 * @param items
255 	 */
256 	public abstract void setItems(List<? extends Component> items);
257 
258 	/**
259 	 * For <code>Component</code> instances in the container's items list that
260 	 * do not have an order set, a default order number will be assigned using
261 	 * this property. The first component found in the list without an order
262 	 * will be assigned the configured initial value, and incremented by one for
263 	 * each component (without an order) found afterwards
264 	 * 
265 	 * @return int order sequence
266 	 */
267 	public int getItemOrderingSequence() {
268 		return this.itemOrderingSequence;
269 	}
270 
271 	/**
272 	 * Setter for the container's item ordering sequence number (initial value)
273 	 * 
274 	 * @param itemOrderingSequence
275 	 */
276 	public void setItemOrderingSequence(int itemOrderingSequence) {
277 		this.itemOrderingSequence = itemOrderingSequence;
278 	}
279 
280 	/**
281 	 * @see org.kuali.rice.krad.uif.container.Container#getLayoutManager()
282 	 */
283 	@Override
284 	public LayoutManager getLayoutManager() {
285 		return this.layoutManager;
286 	}
287 
288 	/**
289 	 * @see org.kuali.rice.krad.uif.container.Container#setLayoutManager(org.kuali.rice.krad.uif.layout.LayoutManager)
290 	 */
291 	@Override
292 	public void setLayoutManager(LayoutManager layoutManager) {
293 		this.layoutManager = layoutManager;
294 	}
295 
296 	/**
297 	 * @see org.kuali.rice.krad.uif.container.Container#getHeader()
298 	 */
299 	@Override
300 	public HeaderField getHeader() {
301 		return this.header;
302 	}
303 
304 	/**
305 	 * @see org.kuali.rice.krad.uif.container.Container#setHeader(org.kuali.rice.krad.uif.field.HeaderField)
306 	 */
307 	@Override
308 	public void setHeader(HeaderField header) {
309 		this.header = header;
310 	}
311 
312 	/**
313 	 * @see org.kuali.rice.krad.uif.container.Container#getFooter()
314 	 */
315 	@Override
316 	public Group getFooter() {
317 		return this.footer;
318 	}
319 
320 	/**
321 	 * @see org.kuali.rice.krad.uif.container.Container#setFooter(org.kuali.rice.krad.uif.container.Group)
322 	 */
323 	@Override
324 	public void setFooter(Group footer) {
325 		this.footer = footer;
326 	}
327 
328 	/**
329 	 * Convenience setter for configuration to turn rendering of the header
330 	 * on/off
331 	 * 
332 	 * <p>
333 	 * For nested groups (like Field Groups) it is often necessary to only show
334 	 * the container body (the contained components). This method allows the
335 	 * header to not be displayed
336 	 * </p>
337 	 * 
338 	 * @param renderHeader
339 	 */
340 	public void setRenderHeader(boolean renderHeader) {
341 		if (header != null) {
342 			header.setRender(renderHeader);
343 		}
344 	}
345 
346 	/**
347 	 * Convenience setter for configuration to turn rendering of the footer
348 	 * on/off
349 	 * 
350 	 * <p>
351 	 * For nested groups it is often necessary to only show the container body
352 	 * (the contained components). This method allows the footer to not be
353 	 * displayed
354 	 * </p>
355 	 * 
356 	 * @param renderFooter
357 	 */
358 	public void setRenderFooter(boolean renderFooter) {
359 		if (footer != null) {
360 			footer.setRender(renderFooter);
361 		}
362 	}
363 
364     /**
365      * Text explaining how complete the group inputs, including things like what values should be selected
366      * in certain cases, what fields should be completed and so on (instructions)
367      *
368      * @return String instructional message
369      */
370 	public String getInstructionalText() {
371 		return this.instructionalText;
372 	}
373 
374     /**
375      * Setter for the instructional message
376      *
377      * @param instructionalText
378      */
379 	public void setInstructionalText(String instructionalText) {
380 		this.instructionalText = instructionalText;
381 	}
382 
383     /**
384      * Message field that displays instructional text
385      *
386      * <p>
387      * This message field can be configured to for adjusting how the instructional text will display. Generally
388      * the styleClasses property will be of most interest
389      * </p>
390      *
391      * @return MessageField instructional message field
392      */
393 	public MessageField getInstructionalMessageField() {
394 		return this.instructionalMessageField;
395 	}
396 
397     /**
398      * Setter for the instructional text message field
399      *
400      * <p>
401      * Note this is the setter for the field that will render the instructional text. The actual text can be
402      * set on the field but can also be set using {@link #setInstructionalText(String)}
403      * </p>
404      *
405      * @param instructionalMessageField
406      */
407 	public void setInstructionalMessageField(MessageField instructionalMessageField) {
408 		this.instructionalMessageField = instructionalMessageField;
409 	}
410 
411 	/**
412 	 * Gets only the data fields that are nested in this container.  This is a subset of
413 	 * what getComponentsForLifecycle() returns
414 	 * 
415 	 * @return
416 	 */
417 	public List<InputField> getInputFields(){
418 		List<InputField> inputFields = new ArrayList<InputField>();
419 		for(Component c: this.getComponentsForLifecycle()){
420 			if(c instanceof InputField){
421 				inputFields.add((InputField)c);
422 			}
423 		}
424 		return inputFields;
425 		
426 	}
427 
428     /**
429      * getAllInputFields gets all the input fields contained in this container, but also in
430      * every sub-container that is a child of this container.  When called from the top level
431      * View this will be every InputField across all pages.
432      * @return every InputField that is a child at any level of this container
433      */
434     public List<InputField> getAllInputFields(){
435         List<InputField> inputFields = new ArrayList<InputField>();
436         for(Component c: this.getComponentsForLifecycle()){
437             if(c instanceof InputField){
438                 inputFields.add((InputField)c);
439             }
440             else if(c instanceof ContainerBase){
441                 inputFields.addAll( ((ContainerBase) c).getAllInputFields());
442             }
443             else if(c instanceof FieldGroup){
444                 ContainerBase cb = ((FieldGroup) c).getGroup();
445                 inputFields.addAll(cb.getAllInputFields());
446             }
447         }
448         return inputFields;    
449     }
450 
451 	/**
452 	 * This property is true if the container is used to display a group of fields that is visually a single
453 	 * field.
454 	 * @return the fieldContainer
455 	 */
456 	public boolean isFieldContainer() {
457 		return this.fieldContainer;
458 	}
459 
460 	/**
461 	 * @param fieldContainer the fieldContainer to set
462 	 */
463 	public void setFieldContainer(boolean fieldContainer) {
464 		this.fieldContainer = fieldContainer;
465 	}
466 
467 }