View Javadoc

1   /**
2    * Copyright 2005-2013 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.datadictionary.parse.BeanTagAttribute;
20  import org.kuali.rice.krad.datadictionary.validator.ErrorReport;
21  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
22  import org.kuali.rice.krad.uif.component.Component;
23  import org.kuali.rice.krad.uif.component.ComponentBase;
24  import org.kuali.rice.krad.uif.element.Header;
25  import org.kuali.rice.krad.uif.element.Message;
26  import org.kuali.rice.krad.uif.element.ValidationMessages;
27  import org.kuali.rice.krad.uif.layout.LayoutManager;
28  import org.kuali.rice.krad.uif.util.ComponentFactory;
29  import org.kuali.rice.krad.uif.util.ComponentUtils;
30  import org.kuali.rice.krad.uif.view.View;
31  import org.kuali.rice.krad.uif.widget.Help;
32  import org.kuali.rice.krad.uif.widget.Tooltip;
33  
34  import java.util.ArrayList;
35  import java.util.List;
36  
37  /**
38   * Base <code>Container</code> implementation which container implementations
39   * can extend
40   *
41   * <p>
42   * Provides properties for the basic <code>Container</code> functionality in
43   * addition to default implementation of the lifecycle methods including some
44   * setup of the header, items list, and layout manager
45   * </p>
46   *
47   * @author Kuali Rice Team (rice.collab@kuali.org)
48   */
49  public abstract class ContainerBase extends ComponentBase implements Container {
50  	private static final long serialVersionUID = -4182226230601746657L;
51  
52  	private int defaultItemPosition;
53  
54  	private Help help;
55  	private LayoutManager layoutManager;
56  
57  	private Header header;
58  	private Group footer;
59  
60  	private String instructionalText;
61  	private Message instructionalMessage;
62  
63      private ValidationMessages validationMessages;
64  
65  	/**
66  	 * Default Constructor
67  	 */
68  	public ContainerBase() {
69  		defaultItemPosition = 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 the instructional field if necessary</li>
78  	 * <li>Initializes LayoutManager</li>
79  	 * </ul>
80  	 *
81  	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View, java.lang.Object)
82  	 */
83  	@SuppressWarnings("unchecked")
84  	@Override
85  	public void performInitialization(View view, Object model) {
86  		super.performInitialization(view, model);
87  
88          sortItems(view, model);
89  
90          if ((StringUtils.isNotBlank(instructionalText) || (getPropertyExpression("instructionalText") != null)) && (
91                  instructionalMessage == null)) {
92              instructionalMessage = ComponentFactory.getInstructionalMessage();
93              view.assignComponentIds(instructionalMessage);
94          }
95  
96  		if (layoutManager != null) {
97  			layoutManager.performInitialization(view, model, this);
98  		}
99  	}
100 
101 	/**
102 	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
103 	 *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
104 	 */
105 	@Override
106 	public void performApplyModel(View view, Object model, Component parent) {
107 		super.performApplyModel(view, model, parent);
108 
109 		// setup summary message field if necessary
110 		if (instructionalMessage != null && StringUtils.isBlank(instructionalMessage.getMessageText())) {
111 			instructionalMessage.setMessageText(instructionalText);
112 		}
113 
114 		if (layoutManager != null) {
115 			layoutManager.performApplyModel(view, model, this);
116 		}
117 	}
118 
119 	/**
120 	 * The following finalization is performed:
121 	 *
122 	 * <ul>
123 	 * <li>Sets the headerText of the header Group if it is blank</li>
124 	 * <li>Set the messageText of the summary Message if it is blank</li>
125 	 * <li>Finalizes LayoutManager</li>
126 	 * </ul>
127 	 *
128 	 * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
129 	 *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
130 	 */
131 	@Override
132 	public void performFinalize(View view, Object model, Component parent) {
133 		super.performFinalize(view, model, parent);
134 
135         if(header != null){
136             header.addDataAttribute("headerFor", this.getId());
137         }
138 
139 		if (layoutManager != null) {
140 			layoutManager.performFinalize(view, model, this);
141 		}
142 
143 	}
144 
145 	/**
146 	 * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
147 	 */
148 	@Override
149 	public List<Component> getComponentsForLifecycle() {
150 		List<Component> components = super.getComponentsForLifecycle();
151 
152 		components.add(header);
153 		components.add(footer);
154 		components.add(validationMessages);
155 		components.add(help);
156 		components.add(instructionalMessage);
157 
158 		for (Component component : getItems()) {
159 			components.add(component);
160 		}
161 
162 		if (layoutManager != null) {
163 			components.addAll(layoutManager.getComponentsForLifecycle());
164 		}
165 
166 		return components;
167 	}
168 
169     /**
170      * @see org.kuali.rice.krad.uif.component.Component#getComponentPrototypes()
171      */
172     @Override
173     public List<Component> getComponentPrototypes() {
174         List<Component> components = super.getComponentPrototypes();
175 
176         if (layoutManager != null) {
177             components.addAll(layoutManager.getComponentPrototypes());
178         }
179 
180         return components;
181     }
182 
183     /**
184      * Performs sorting of the container items based on the order property
185      *
186      * @param view view instance containing the container
187      * @param model model object containing the view data
188      */
189     protected void sortItems(View view, Object model) {
190         // sort items list by the order property
191         List<? extends Component> sortedItems = (List<? extends Component>) ComponentUtils.sort(getItems(),
192                 defaultItemPosition);
193         setItems(sortedItems);
194     }
195 
196 	/**
197 	 * @see org.kuali.rice.krad.uif.container.Container#getValidationMessages()
198 	 */
199 	@Override
200     @BeanTagAttribute(name="validationMessages",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
201 	public ValidationMessages getValidationMessages() {
202 		return this.validationMessages;
203 	}
204 
205 	/**
206 	 * @see org.kuali.rice.krad.uif.container.Container#setValidationMessages(org.kuali.rice.krad.uif.element.ValidationMessages)
207 	 */
208 	@Override
209 	public void setValidationMessages(ValidationMessages validationMessages) {
210 		this.validationMessages = validationMessages;
211 	}
212 
213 	/**
214 	 * @see org.kuali.rice.krad.uif.widget.Helpable#getHelp()
215 	 */
216 	@Override
217     @BeanTagAttribute(name="help",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
218 	public Help getHelp() {
219 		return this.help;
220 	}
221 
222 	/**
223 	 * @see org.kuali.rice.krad.uif.widget.Helpable#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      * For containers the help tooltip is placed on the header.
232      *
233      * @see org.kuali.rice.krad.uif.widget.Helpable#setTooltipOfComponent(org.kuali.rice.krad.uif.widget.Tooltip)
234      */
235     @Override
236     public void setTooltipOfComponent(Tooltip tooltip) {
237         getHeader().setToolTip(tooltip);
238     }
239 
240     /**
241      * Return the container header text for the help title
242      *
243      * @return container title
244      *
245      * @see org.kuali.rice.krad.uif.widget.Helpable#setTooltipOfComponent(org.kuali.rice.krad.uif.widget.Tooltip)
246      */
247     @Override
248     public String getHelpTitle() {
249         return this.getHeader().getHeaderText();
250     }
251 
252     /**
253 	 * @see org.kuali.rice.krad.uif.container.Container#getItems()
254 	 */
255 	@Override
256     @BeanTagAttribute(name="items",type= BeanTagAttribute.AttributeType.LISTBEAN)
257 	public abstract List<? extends Component> getItems();
258 
259 	/**
260 	 * Setter for the containers list of components
261 	 *
262 	 * @param items
263 	 */
264 	public abstract void setItems(List<? extends Component> items);
265 
266 	/**
267 	 * For <code>Component</code> instances in the container's items list that
268 	 * do not have an order set, a default order number will be assigned using
269 	 * this property. The first component found in the list without an order
270 	 * will be assigned the configured initial value, and incremented by one for
271 	 * each component (without an order) found afterwards
272 	 *
273 	 * @return int order sequence
274 	 */
275     @BeanTagAttribute(name="defaultItemPosition")
276 	public int getDefaultItemPosition() {
277 		return this.defaultItemPosition;
278 	}
279 
280 	/**
281 	 * Setter for the container's item ordering sequence number (initial value)
282 	 *
283 	 * @param defaultItemPosition
284 	 */
285 	public void setDefaultItemPosition(int defaultItemPosition) {
286 		this.defaultItemPosition = defaultItemPosition;
287 	}
288 
289 	/**
290 	 * @see org.kuali.rice.krad.uif.container.Container#getLayoutManager()
291 	 */
292 	@Override
293     @BeanTagAttribute(name="layoutManager",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
294 	public LayoutManager getLayoutManager() {
295 		return this.layoutManager;
296 	}
297 
298 	/**
299 	 * @see org.kuali.rice.krad.uif.container.Container#setLayoutManager(org.kuali.rice.krad.uif.layout.LayoutManager)
300 	 */
301 	@Override
302 	public void setLayoutManager(LayoutManager layoutManager) {
303 		this.layoutManager = layoutManager;
304 	}
305 
306 	/**
307 	 * @see org.kuali.rice.krad.uif.container.Container#getHeader()
308 	 */
309 	@Override
310     @BeanTagAttribute(name="header",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
311 	public Header getHeader() {
312 		return this.header;
313 	}
314 
315 	/**
316 	 * @see org.kuali.rice.krad.uif.container.Container#setHeader(org.kuali.rice.krad.uif.element.Header)
317 	 */
318 	@Override
319 	public void setHeader(Header header) {
320 		this.header = header;
321 	}
322 
323 	/**
324 	 * @see org.kuali.rice.krad.uif.container.Container#getFooter()
325 	 */
326 	@Override
327     @BeanTagAttribute(name="footer",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
328 	public Group getFooter() {
329 		return this.footer;
330 	}
331 
332 	/**
333 	 * @see org.kuali.rice.krad.uif.container.Container#setFooter(org.kuali.rice.krad.uif.container.Group)
334 	 */
335 	@Override
336 	public void setFooter(Group footer) {
337 		this.footer = footer;
338 	}
339 
340 	/**
341 	 * Convenience setter for configuration to turn rendering of the header
342 	 * on/off
343 	 *
344 	 * <p>
345 	 * For nested groups (like Field Groups) it is often necessary to only show
346 	 * the container body (the contained components). This method allows the
347 	 * header to not be displayed
348 	 * </p>
349 	 *
350 	 * @param renderHeader
351 	 */
352 	public void setRenderHeader(boolean renderHeader) {
353 		if (header != null) {
354 			header.setRender(renderHeader);
355 		}
356 	}
357 
358     /**
359      * Convenience getter for the header text
360      *
361      * @return The text that should be displayed on the header
362      */
363     @BeanTagAttribute(name="headertext")
364     public String getHeaderText () {
365         if (header != null && header.getHeaderText() != null) {
366             return header.getHeaderText();
367         } else {
368             return "";
369         }
370     }
371 
372     /**
373      * Convenience setter for configuration to set the header text
374      *
375      * @param headerText  the text that should be displayed on the header.
376      */
377     public void setHeaderText (String headerText) {
378         if (header != null) {
379             header.setHeaderText(headerText);
380         }
381     }
382 
383 	/**
384 	 * Convenience setter for configuration to turn rendering of the footer
385 	 * on/off
386 	 *
387 	 * <p>
388 	 * For nested groups it is often necessary to only show the container body
389 	 * (the contained components). This method allows the footer to not be
390 	 * displayed
391 	 * </p>
392 	 *
393 	 * @param renderFooter
394 	 */
395 	public void setRenderFooter(boolean renderFooter) {
396 		if (footer != null) {
397 			footer.setRender(renderFooter);
398 		}
399 	}
400 
401     /**
402      * Text explaining how complete the group inputs, including things like what values should be selected
403      * in certain cases, what fields should be completed and so on (instructions)
404      *
405      * @return String instructional message
406      */
407     @BeanTagAttribute(name="instructionalText")
408 	public String getInstructionalText() {
409 		return this.instructionalText;
410 	}
411 
412     /**
413      * Setter for the instructional message
414      *
415      * @param instructionalText
416      */
417 	public void setInstructionalText(String instructionalText) {
418 		this.instructionalText = instructionalText;
419 	}
420 
421     /**
422      * Message field that displays instructional text
423      *
424      * <p>
425      * This message field can be configured to for adjusting how the instructional text will display. Generally
426      * the styleClasses property will be of most interest
427      * </p>
428      *
429      * @return Message instructional message field
430      */
431     @BeanTagAttribute(name="instructionalMessage",type= BeanTagAttribute.AttributeType.SINGLEBEAN)
432 	public Message getInstructionalMessage() {
433 		return this.instructionalMessage;
434 	}
435 
436     /**
437      * Setter for the instructional text message field
438      *
439      * <p>
440      * Note this is the setter for the field that will render the instructional text. The actual text can be
441      * set on the field but can also be set using {@link #setInstructionalText(String)}
442      * </p>
443      *
444      * @param instructionalMessage
445      */
446 	public void setInstructionalMessage(Message instructionalMessage) {
447 		this.instructionalMessage = instructionalMessage;
448 	}
449 
450     /**
451      * @see org.kuali.rice.krad.uif.component.Component#completeValidation
452      */
453     @Override
454     public void completeValidation(ValidationTrace tracer){
455         tracer.addBean(this);
456 
457         // Checks for over writing of the instructional text or message
458         if(getInstructionalText()!=null && getInstructionalMessage()!=null){
459             String currentValues [] = {"instructionalMessage.text = "+getInstructionalMessage().getMessageText(),"instructionalText = "+getInstructionalText()};
460             tracer.createWarning("InstructionalMessage will override instructioanlText",currentValues);
461         }
462 
463         super.completeValidation(tracer.getCopy());
464     }
465 }