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