001/** 002 * Copyright 2005-2015 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.field; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.util.ConcreteKeyValue; 020import org.kuali.rice.krad.datadictionary.AttributeDefinition; 021import org.kuali.rice.krad.datadictionary.parse.BeanTag; 022import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute; 023import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 024import org.kuali.rice.krad.uif.UifConstants; 025import org.kuali.rice.krad.uif.component.Component; 026import org.kuali.rice.krad.uif.control.CheckboxControl; 027import org.kuali.rice.krad.uif.control.Control; 028import org.kuali.rice.krad.uif.control.FilterableLookupCriteriaControl; 029import org.kuali.rice.krad.uif.control.MultiValueControl; 030import org.kuali.rice.krad.uif.control.RadioGroupControl; 031import org.kuali.rice.krad.uif.control.TextAreaControl; 032import org.kuali.rice.krad.uif.element.Message; 033import org.kuali.rice.krad.uif.util.ComponentFactory; 034import org.kuali.rice.krad.uif.util.ComponentUtils; 035import org.kuali.rice.krad.uif.util.KeyMessage; 036import org.kuali.rice.krad.uif.view.View; 037import org.kuali.rice.krad.util.KRADConstants; 038import org.kuali.rice.krad.util.KRADPropertyConstants; 039 040import java.util.Map; 041 042/** 043 * Custom <code>InputField</code> for search fields within a lookup view 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047@BeanTag(name = "lookupCriteriaInputField-bean", parent = "Uif-LookupCriteriaInputField") 048public class LookupInputField extends InputField { 049 private static final long serialVersionUID = -8294275596836322699L; 050 051 public static final String CHECKBOX_CONVERTED_RADIO_CONTROL = "Uif-CheckboxConvertedRadioControl"; 052 053 private boolean disableWildcardsAndOperators; 054 private boolean addControlSelectAllOption; 055 private boolean triggerOnChange; 056 private boolean ranged; 057 058 public LookupInputField() { 059 super(); 060 061 disableWildcardsAndOperators = false; 062 addControlSelectAllOption = false; 063 setTriggerOnChange(false); 064 } 065 066 /** 067 * The following actions are performed: 068 * 069 * <ul> 070 * <li>Add all option if enabled and control is multi-value</li> 071 * </ul> 072 * 073 * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View, 074 * java.lang.Object, org.kuali.rice.krad.uif.component.Component) 075 */ 076 @Override 077 public void performFinalize(View view, Object model, Component parent) { 078 super.performFinalize(view, model, parent); 079 080 // if enabled add option to select all values 081 if (addControlSelectAllOption && (getControl() != null) && getControl() instanceof MultiValueControl) { 082 String allOptionText = KRADServiceLocatorWeb.getMessageService().getMessageText( 083 UifConstants.MessageKeys.OPTION_ALL); 084 085 MultiValueControl multiValueControl = (MultiValueControl) getControl(); 086 if (multiValueControl.getOptions() != null) { 087 multiValueControl.getOptions().add(0, new ConcreteKeyValue("", allOptionText)); 088 } 089 090 if (multiValueControl.getRichOptions() != null) { 091 Message message = ComponentFactory.getMessage(); 092 093 view.assignComponentIds(message); 094 message.setMessageText(allOptionText); 095 message.setGenerateSpan(false); 096 097 multiValueControl.getRichOptions().add(0, new KeyMessage("", allOptionText, message)); 098 } 099 } 100 } 101 102 /** 103 * Override of InputField copy to setup properties necessary to make the field usable for inputting 104 * search criteria 105 * 106 * @param attributeDefinition AttributeDefinition instance the property values should be copied from 107 * @see DataField#copyFromAttributeDefinition(org.kuali.rice.krad.uif.view.View, 108 * org.kuali.rice.krad.datadictionary.AttributeDefinition) 109 */ 110 @Override 111 public void copyFromAttributeDefinition(View view, AttributeDefinition attributeDefinition) { 112 // label 113 if (StringUtils.isEmpty(getLabel())) { 114 setLabel(attributeDefinition.getLabel()); 115 } 116 117 // short label 118 if (StringUtils.isEmpty(getShortLabel())) { 119 setShortLabel(attributeDefinition.getShortLabel()); 120 } 121 122 // security 123 if (getDataFieldSecurity().getAttributeSecurity() == null) { 124 getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity()); 125 } 126 127 // options 128 if (getOptionsFinder() == null) { 129 setOptionsFinder(attributeDefinition.getOptionsFinder()); 130 } 131 132 // TODO: what about formatter? 133 134 // use control from dictionary if not specified and convert for searching 135 if (getControl() == null) { 136 Control control = convertControlToLookupControl(attributeDefinition); 137 view.assignComponentIds(control); 138 139 setControl(control); 140 } 141 142 // overwrite maxLength to allow for wildcards and ranges 143 setMaxLength(100); 144 145 // set default value for active field to true 146 if (StringUtils.isEmpty(getDefaultValue())) { 147 if ((StringUtils.equals(getPropertyName(), KRADPropertyConstants.ACTIVE))) { 148 setDefaultValue(KRADConstants.YES_INDICATOR_VALUE); 149 } 150 } 151 152 /* 153 * TODO delyea: FieldUtils.createAndPopulateFieldsForLookup used to allow for a set of property names to be passed in via the URL 154 * parameters of the lookup url to set fields as 'read only' 155 */ 156 157 } 158 159 /** 160 * If control definition is defined on the given attribute definition, converts to an appropriate control for 161 * searching (if necessary) and returns a copy for setting on the field 162 * 163 * @param attributeDefinition attribute definition instance to retrieve control from 164 * @return Control instance or null if not found 165 */ 166 protected static Control convertControlToLookupControl(AttributeDefinition attributeDefinition) { 167 if (attributeDefinition.getControlField() == null) { 168 return null; 169 } 170 171 Control newControl = null; 172 173 // convert checkbox to radio with yes/no/both options 174 if (CheckboxControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) { 175 newControl = getCheckboxConvertedRadioControl(); 176 } 177 // text areas get converted to simple text inputs 178 else if (TextAreaControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) { 179 newControl = ComponentFactory.getTextControl(); 180 } else { 181 newControl = ComponentUtils.copy(attributeDefinition.getControlField(), ""); 182 } 183 184 return newControl; 185 } 186 187 /** 188 * @return the treatWildcardsAndOperatorsAsLiteral 189 */ 190 @BeanTagAttribute(name = "disableWildcardsAndOperators") 191 public boolean isDisableWildcardsAndOperators() { 192 return this.disableWildcardsAndOperators; 193 } 194 195 /** 196 * @param disableWildcardsAndOperators the treatWildcardsAndOperatorsAsLiteral to set 197 */ 198 public void setDisableWildcardsAndOperators(boolean disableWildcardsAndOperators) { 199 this.disableWildcardsAndOperators = disableWildcardsAndOperators; 200 } 201 202 /** 203 * Indicates whether the option for all values (blank key, 'All' label) should be added to the lookup 204 * field, note this is only supported for {@link org.kuali.rice.krad.uif.control.MultiValueControl} instance 205 * 206 * @return boolean true if all option should be added, false if not 207 */ 208 @BeanTagAttribute(name = "addControlSelectAllOption") 209 public boolean isAddControlSelectAllOption() { 210 return addControlSelectAllOption; 211 } 212 213 /** 214 * Setter for the add all option indicator 215 * 216 * @param addControlSelectAllOption 217 */ 218 public void setAddControlSelectAllOption(boolean addControlSelectAllOption) { 219 this.addControlSelectAllOption = addControlSelectAllOption; 220 } 221 222 /** 223 * Indicates that the search must execute on changing of a value in the lookup input field 224 * 225 * @return boolean 226 */ 227 public boolean isTriggerOnChange() { 228 return triggerOnChange; 229 } 230 231 /** 232 * Setter for the trigger search on change flag 233 * 234 * @param triggerOnChange 235 */ 236 public void setTriggerOnChange(boolean triggerOnChange) { 237 this.triggerOnChange = triggerOnChange; 238 } 239 240 /** 241 * Indicates that a field must be rendered as a from and to value 242 * 243 * @return 244 */ 245 public boolean isRanged() { 246 return ranged; 247 } 248 249 /** 250 * Setter for ranged flag to indicate this is a range field 251 * 252 * @param ranged 253 */ 254 public void setRanged(boolean ranged) { 255 this.ranged = ranged; 256 } 257 258 /** 259 * Remove any search criteria that are not part of the database lookup 260 * 261 * @param searchCriteria the search criteria to be filtered 262 * @return the filteredSearchCriteria 263 */ 264 public Map<String, String> filterSearchCriteria(Map<String, String> searchCriteria) { 265 if (getControl() instanceof FilterableLookupCriteriaControl) { 266 return ((FilterableLookupCriteriaControl) getControl()).filterSearchCriteria(getPropertyName(), 267 searchCriteria); 268 } else { 269 return searchCriteria; 270 } 271 } 272 273 /** 274 * @see org.kuali.rice.krad.uif.component.ComponentBase#copy() 275 */ 276 @Override 277 protected <T> void copyProperties(T component) { 278 super.copyProperties(component); 279 LookupInputField lookupInputFieldCopy = (LookupInputField) component; 280 lookupInputFieldCopy.setDisableWildcardsAndOperators(this.disableWildcardsAndOperators); 281 lookupInputFieldCopy.setAddControlSelectAllOption(this.addControlSelectAllOption); 282 lookupInputFieldCopy.setTriggerOnChange(this.triggerOnChange); 283 lookupInputFieldCopy.setRanged(this.ranged); 284 } 285 286 /** 287 * Retrieves a new radio group control instance for converted lookup criteria checkboxes from Spring 288 * (initialized by the bean definition with the given id) 289 * 290 * @return RadioGroupControl 291 */ 292 private static RadioGroupControl getCheckboxConvertedRadioControl() { 293 return (RadioGroupControl) ComponentFactory.getNewComponentInstance(CHECKBOX_CONVERTED_RADIO_CONTROL); 294 } 295}