View Javadoc
1   /**
2    * Copyright 2005-2016 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.field;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.util.ConcreteKeyValue;
20  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
21  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
22  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
23  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
24  import org.kuali.rice.krad.uif.UifConstants;
25  import org.kuali.rice.krad.uif.component.Component;
26  import org.kuali.rice.krad.uif.control.CheckboxControl;
27  import org.kuali.rice.krad.uif.control.Control;
28  import org.kuali.rice.krad.uif.control.FilterableLookupCriteriaControl;
29  import org.kuali.rice.krad.uif.control.MultiValueControl;
30  import org.kuali.rice.krad.uif.control.RadioGroupControl;
31  import org.kuali.rice.krad.uif.control.TextAreaControl;
32  import org.kuali.rice.krad.uif.element.Message;
33  import org.kuali.rice.krad.uif.util.ComponentFactory;
34  import org.kuali.rice.krad.uif.util.ComponentUtils;
35  import org.kuali.rice.krad.uif.util.KeyMessage;
36  import org.kuali.rice.krad.uif.view.View;
37  import org.kuali.rice.krad.util.KRADConstants;
38  import org.kuali.rice.krad.util.KRADPropertyConstants;
39  
40  import java.util.Map;
41  
42  /**
43   * Custom <code>InputField</code> for search fields within a lookup view
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  @BeanTag(name = "lookupCriteriaInputField-bean", parent = "Uif-LookupCriteriaInputField")
48  public class LookupInputField extends InputField {
49      private static final long serialVersionUID = -8294275596836322699L;
50  
51      public static final String CHECKBOX_CONVERTED_RADIO_CONTROL = "Uif-CheckboxConvertedRadioControl";
52  
53      private boolean disableWildcardsAndOperators;
54      private boolean addControlSelectAllOption;
55      private boolean triggerOnChange;
56      private boolean ranged;
57  
58      public LookupInputField() {
59          super();
60  
61          disableWildcardsAndOperators = false;
62          addControlSelectAllOption = false;
63          setTriggerOnChange(false);
64      }
65  
66      /**
67       * The following actions are performed:
68       *
69       * <ul>
70       * <li>Add all option if enabled and control is multi-value</li>
71       * </ul>
72       *
73       * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
74       *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
75       */
76      @Override
77      public void performFinalize(View view, Object model, Component parent) {
78          super.performFinalize(view, model, parent);
79  
80          // if enabled add option to select all values
81          if (addControlSelectAllOption && (getControl() != null) && getControl() instanceof MultiValueControl) {
82              String allOptionText = KRADServiceLocatorWeb.getMessageService().getMessageText(
83                      UifConstants.MessageKeys.OPTION_ALL);
84  
85              MultiValueControl multiValueControl = (MultiValueControl) getControl();
86              if (multiValueControl.getOptions() != null) {
87                  multiValueControl.getOptions().add(0, new ConcreteKeyValue("", allOptionText));
88              }
89  
90              if (multiValueControl.getRichOptions() != null) {
91                  Message message = ComponentFactory.getMessage();
92  
93                  view.assignComponentIds(message);
94                  message.setMessageText(allOptionText);
95                  message.setGenerateSpan(false);
96  
97                  multiValueControl.getRichOptions().add(0, new KeyMessage("", allOptionText, message));
98              }
99          }
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 }