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 org.kuali.rice.core.api.util.KeyValue;
19 import org.kuali.rice.krad.datadictionary.parse.BeanTag;
20 import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21 import org.kuali.rice.krad.datadictionary.parse.BeanTags;
22 import org.kuali.rice.krad.uif.component.Component;
23 import org.kuali.rice.krad.uif.control.MultiValueControl;
24 import org.kuali.rice.krad.uif.element.Message;
25 import org.kuali.rice.krad.uif.field.InputField;
26 import org.kuali.rice.krad.uif.field.MessageField;
27 import org.kuali.rice.krad.uif.view.View;
28
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.List;
32
33 /**
34 * Special type of <code>Group</code> that presents a the content for a modal dialog
35 *
36 * <p>
37 * This type of group will be hidden when the main view is displayed. It will be used as
38 * content inside the LightBox widget when the modal dialog is displayed.
39 * For convenience, this group contains a standard set of components for commonly used modal dialogs
40 * <ul>
41 * <li>a prompt to display in the lightbox</li>
42 * <li>an optional explanation <code>InputField</code> for holding the user's textual response</li>
43 * <li>a set of response options for the user to choose from</li>
44 * </ul>
45 *
46 * <p>
47 * The DialogGroup may also serve as a base class for more complex dialogs.
48 * The default settings for this DialogGroup is to display a prompt message
49 * with two buttons labeled OK and Cancel.
50 * The optional explanation <code>TextAreaControl</code> is hidden by default.
51 * </p>
52 *
53 * <p>
54 * The prompt text, number of user options and their corresponding label are configurable.
55 * The <code>InputField</code> for the explanation is <code>TextAreaControl</code> by default.
56 * It may be configured to other types of InputFields.
57 * The Component for ResponseInputField is a <code>HorizontalCheckboxGroup</code> by default.
58 * JQuery styling is then used to style the checkboxes as buttons. The ResponseInputField may
59 * be configured to other <code>InputField</code> types.
60 * </p>
61 *
62 * @author Kuali Rice Team (rice.collab@kuali.org)
63 */
64 @BeanTags({@BeanTag(name = "dialogGroup-bean", parent = "Uif-DialogGroup"),
65 @BeanTag(name = "sensitiveData-dialogGroup-bean", parent = "Uif-SensitiveData-DialogGroup"),
66 @BeanTag(name = "ok-cancel-dialogGroup-bean", parent = "Uif-OK-Cancel-DialogGroup"),
67 @BeanTag(name = "yes-no-dialogGroup-bean", parent = "Uif-Yes-No-DialogGroup"),
68 @BeanTag(name = "true-false-dialogGroup-bean", parent = "Uif-True-False-DialogGroup"),
69 @BeanTag(name = "checkbox-dialogGroup-bean", parent = "Uif-Checkbox-DialogGroup"),
70 @BeanTag(name = "radioButton-dialogGroup-bean", parent = "Uif-RadioButton-DialogGroup")})
71 public class DialogGroup extends Group {
72 private static final long serialVersionUID = 1L;
73
74 private String promptText;
75 private List<KeyValue> availableResponses;
76
77 private MessageField prompt;
78 private InputField explanation;
79 private InputField responseInputField;
80
81 private boolean reverseButtonOrder = false;
82 private boolean displayExplanation = false;
83 private boolean useAjaxCallForContent = false;
84
85 public DialogGroup() {
86 super();
87 }
88
89 /**
90 * Process rich message content that may be in the options, by creating and initializing the richOptions
91 *
92 * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
93 * java.lang.Object, org.kuali.rice.krad.uif.component.Component)
94 */
95 @Override
96 public void performApplyModel(View view, Object model, Component parent) {
97 super.performApplyModel(view, model, parent);
98
99 // set the messageTest to the promptText
100 prompt.setMessageText(promptText);
101
102 // hide or show explanation
103 explanation.setRender(displayExplanation);
104
105 // add options to checkbox
106 if (responseInputField.getControl() != null && responseInputField.getControl() instanceof MultiValueControl) {
107 MultiValueControl multiValueControl = (MultiValueControl) responseInputField.getControl();
108
109 if (reverseButtonOrder) {
110 // reverse the button order (without changing original list)
111 List<KeyValue> buttonList = new ArrayList<KeyValue>(availableResponses);
112 Collections.reverse(buttonList);
113 multiValueControl.setOptions(buttonList);
114 } else {
115 multiValueControl.setOptions(availableResponses);
116 }
117 }
118 }
119
120 /**
121 * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
122 */
123 @Override
124 public List<Component> getComponentsForLifecycle() {
125 List<Component> components = super.getComponentsForLifecycle();
126
127 components.add(prompt);
128 components.add(explanation);
129 components.add(responseInputField);
130
131 return components;
132 }
133
134 /**
135 * The following actions are performed:
136 *
137 * <ul>
138 * <li>Move custom dialogGroup properties prompt, explanation, and responseInputField into items collection if they
139 * are not already present</li>
140 * </ul>
141 *
142 * @see org.kuali.rice.krad.uif.component.ComponentBase#performInitialization(org.kuali.rice.krad.uif.view.View,
143 * java.lang.Object)
144 */
145 @Override
146 public void performInitialization(View view, Object model) {
147 super.performInitialization(view, model);
148
149 // move dialogGroup custom properties into the items property.
150 // where they will be rendered by group.jsp
151 List<Component> newItems = new ArrayList<Component>();
152 List<? extends Component> items = getItems();
153
154 // do not add the custom properties if they are already present
155 if (!(items.contains(prompt))) {
156 newItems.add(prompt);
157 }
158
159 if (!(items.contains(explanation))) {
160 newItems.add(explanation);
161 }
162
163 newItems.addAll(getItems());
164
165 if (!(items.contains(responseInputField))) {
166 newItems.add(responseInputField);
167 }
168
169 this.setItems(newItems);
170 }
171
172 /**
173 * Performs the final phase of the component lifecycle.
174 *
175 * <p>For this DialogGroup component, perform the following:
176 * <ul>
177 * <li>set the promptText in the message</li>
178 * <li>sets whether to render explanation field</li>
179 * <li>set the options for the checkbox control to the availableResponses KeyValue property of
180 * this dialogGroup</li>
181 * <li>orders response buttons</li>
182 * </ul>
183 * </p>
184 *
185 * @param view - view instance that should be finalized for rendering
186 * @param model - top level object containing the data
187 * @param parent - parent component
188 */
189 @Override
190 public void performFinalize(View view, Object model, Component parent) {
191 super.performFinalize(view, model, parent);
192
193 // if ajax, just render a placeholder
194 if (useAjaxCallForContent) {
195 setProgressiveRenderViaAJAX(useAjaxCallForContent);
196 setProgressiveRender("");
197 setRender(false);
198 }
199 }
200
201 // Getters and Setters
202
203 /**
204 * Returns the text to be displayed as the prompt or main message in this simple dialog
205 *
206 * @return String containing the prompt text
207 */
208
209 @BeanTagAttribute(name = "promptText")
210 public String getPromptText() {
211 return promptText;
212 }
213
214 /**
215 * Sets the text String to display as the main message in this dialog
216 *
217 * @param promptText - the String to be displayed as the main message
218 */
219 public void setPromptText(String promptText) {
220 this.promptText = promptText;
221 }
222
223 /**
224 * Retrieves the Message element for this dialog
225 *
226 * @return Message - the text element containing the message string
227 */
228 @BeanTagAttribute(name = "prompt", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
229 public MessageField getPrompt() {
230 return prompt;
231 }
232
233 /**
234 * Sets the prompt Message for this dialog
235 *
236 * @param prompt - The Message element for this dialog
237 */
238 public void setPrompt(MessageField prompt) {
239 this.prompt = prompt;
240 }
241
242 /**
243 * Retrieves the explanation InputField used to gather user input text from the dialog
244 *
245 * <p>
246 * By default, the control for this input is configured as a TextAreaControl. It may be configured for
247 * other types of input fields.
248 * </p>
249 *
250 * @return InputField component
251 */
252 @BeanTagAttribute(name = "explanation", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
253 public InputField getExplanation() {
254 return explanation;
255 }
256
257 /**
258 * Sets the InputField for gathering user text input
259 *
260 * @param explanation - InputField
261 */
262 public void setExplanation(InputField explanation) {
263 this.explanation = explanation;
264 }
265
266 /**
267 * determines if the explanation InputField is to be displayed in this dialog
268 *
269 * <p>
270 * False by default.
271 * </p>
272 *
273 * @return boolean - true if this user input is to be rendered, false if not.
274 */
275 @BeanTagAttribute(name = "displayExplanation")
276 public boolean isDisplayExplanation() {
277 return displayExplanation;
278 }
279
280 /**
281 * Sets whether to display the Explanation InputField on this dialog
282 *
283 * @param displayExplanation - true if explanation control is to be displayed, false if not
284 */
285 public void setDisplayExplanation(boolean displayExplanation) {
286 this.displayExplanation = displayExplanation;
287 }
288
289 /**
290 * Gets the choices provided for user response.
291 *
292 * <p>
293 * A List of KeyValue pairs for each of the choices provided on this dialog.
294 * </p>
295 *
296 * @return the List of response actions to provide the user.
297 */
298 @BeanTagAttribute(name = "availableResponses", type = BeanTagAttribute.AttributeType.LISTBEAN)
299 public List<KeyValue> getAvailableResponses() {
300 return availableResponses;
301 }
302
303 /**
304 * Sets the list of user responses to provide on this dialog
305 *
306 * @param availableResponses - a List of KeyValue pairs representing the user response choices
307 */
308 public void setAvailableResponses(List<KeyValue> availableResponses) {
309 this.availableResponses = availableResponses;
310 }
311
312 /**
313 * Retrieves the InputField containing the choices displayed in this dialog
314 *
315 * <p>
316 * By default, this InputField is configured to be a HorizontalCheckboxControl.
317 * Styling is then used to make the checkboxes appear to be buttons.
318 * The values of the availableResponses List are used as labels for the "buttons".
319 * </p>
320 *
321 * @return InputField component within this dialog
322 */
323 @BeanTagAttribute(name = "responseInputField", type = BeanTagAttribute.AttributeType.SINGLEBEAN)
324 public InputField getResponseInputField() {
325 return responseInputField;
326 }
327
328 /**
329 * Sets the type of InputField used to display the user choices in this dialog
330 *
331 * @param responseInputField - A component used to display the response choices
332 */
333 public void setResponseInputField(InputField responseInputField) {
334 this.responseInputField = responseInputField;
335 }
336
337 /**
338 * Determines the positioning order of the choices displayed on this dialog
339 *
340 * <p>
341 * Some page designers like the positive choice on the left and the negative choice on the right.
342 * Others, prefer just the opposite. This allows the order to easily be switched.
343 * </p>
344 *
345 * @return - true if choices left to right
346 * false if choices right to left
347 */
348 @BeanTagAttribute(name = "reverseButtonOrder")
349 public boolean isReverseButtonOrder() {
350 return reverseButtonOrder;
351 }
352
353 /**
354 * Sets the display order of the choices displayed on this dialog
355 *
356 * <p>
357 * By default, the choices are displayed left to right
358 * </p>
359 *
360 * @param reverseButtonOrder - true if buttons displayed left to right, false if right to left
361 */
362 public void setReverseButtonOrder(boolean reverseButtonOrder) {
363 this.reverseButtonOrder = reverseButtonOrder;
364 }
365
366 /**
367 * Indicates which approach is used to fill the lightbox content for this dialog.
368 *
369 * <p>
370 * Two techniques are used for filling the content of the lightbox when displaying this dialog.
371 * <ul>
372 * <li>a hidden group on the page is used as content</li>
373 * <li>an ajax call is made to the server to get the content</li>
374 * </ul>
375 * The default approach is to use a hidden form.
376 * </p>
377 *
378 * @return boolean
379 */
380 @BeanTagAttribute(name = "useAjaxCallForContent")
381 public boolean isUseAjaxCallForContent() {
382 return useAjaxCallForContent;
383 }
384
385 /**
386 * Sets whether the content for the dialog will be filled via ajax call or hidden group
387 *
388 * @param useAjaxCallForContent - boolean set to true if ajax call is used to get content,
389 * false if hidden group is used for content.
390 */
391 public void setUseAjaxCallForContent(boolean useAjaxCallForContent) {
392 this.useAjaxCallForContent = useAjaxCallForContent;
393 }
394
395 }