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.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", parent = "Uif-DialogGroup"), 65 @BeanTag(name = "sensitiveData-dialogGroup", parent = "Uif-SensitiveData-DialogGroup"), 66 @BeanTag(name = "ok-cancel-dialogGroup", parent = "Uif-OK-Cancel-DialogGroup"), 67 @BeanTag(name = "yes-no-dialogGroup", parent = "Uif-Yes-No-DialogGroup"), 68 @BeanTag(name = "true-false-dialogGroup", parent = "Uif-True-False-DialogGroup"), 69 @BeanTag(name = "checkbox-dialogGroup", parent = "Uif-Checkbox-DialogGroup"), 70 @BeanTag(name = "radioButton-dialogGroup", 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 }