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.lookup;
17  
18  import java.util.Map;
19  
20  import org.apache.commons.lang.StringUtils;
21  import org.kuali.rice.core.api.util.ConcreteKeyValue;
22  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
24  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
25  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
26  import org.kuali.rice.krad.uif.UifConstants;
27  import org.kuali.rice.krad.uif.control.CheckboxControl;
28  import org.kuali.rice.krad.uif.control.Control;
29  import org.kuali.rice.krad.uif.control.FilterableLookupCriteriaControl;
30  import org.kuali.rice.krad.uif.control.MultiValueControl;
31  import org.kuali.rice.krad.uif.control.RadioGroupControl;
32  import org.kuali.rice.krad.uif.control.TextAreaControl;
33  import org.kuali.rice.krad.uif.element.Message;
34  import org.kuali.rice.krad.uif.field.InputField;
35  import org.kuali.rice.krad.uif.field.InputFieldBase;
36  import org.kuali.rice.krad.uif.util.ComponentFactory;
37  import org.kuali.rice.krad.uif.util.ComponentUtils;
38  import org.kuali.rice.krad.uif.util.KeyMessage;
39  import org.kuali.rice.krad.uif.util.LifecycleElement;
40  import org.kuali.rice.krad.util.KRADConstants;
41  import org.kuali.rice.krad.util.KRADPropertyConstants;
42  
43  /**
44   * Custom {@link InputField} for criteria fields within a lookup view that adds criteria specific options.
45   *
46   * @author Kuali Rice Team (rice.collab@kuali.org)
47   */
48  @BeanTag(name = "lookupCriteriaInputField-bean", parent = "Uif-LookupCriteriaInputField")
49  public class LookupInputField extends InputFieldBase {
50      private static final long serialVersionUID = -8294275596836322699L;
51  
52      private boolean disableWildcardsAndOperators;
53      private boolean addControlSelectAllOption;
54      private boolean ranged;
55  
56      public LookupInputField() {
57          super();
58      }
59  
60      /**
61       * The following actions are performed:
62       *
63       * <ul>
64       * <li>Add all option if enabled and control is multi-value</li>
65       * </ul>
66       *
67       * {@inheritDoc}
68       */
69      @Override
70      public void performFinalize(Object model, LifecycleElement parent) {
71          super.performFinalize(model, parent);
72  
73          // if enabled add option to select all values
74          if (addControlSelectAllOption && (getControl() != null) && getControl() instanceof MultiValueControl) {
75              String allOptionText = KRADServiceLocatorWeb.getMessageService().getMessageText(
76                      UifConstants.MessageKeys.OPTION_ALL);
77  
78              MultiValueControl multiValueControl = (MultiValueControl) getControl();
79              if (multiValueControl.getOptions() != null) {
80                  multiValueControl.getOptions().add(0, new ConcreteKeyValue("", allOptionText));
81              }
82  
83              if (multiValueControl.getRichOptions() != null) {
84                  Message message = ComponentFactory.getMessage();
85                  message.setMessageText(allOptionText);
86                  message.setRenderWrapperTag(false);
87  
88                  multiValueControl.getRichOptions().add(0, new KeyMessage("", allOptionText, message));
89              }
90          }
91      }
92  
93      /**
94       * Override of InputField copy to setup properties necessary to make the field usable for inputting
95       * search criteria.
96       *
97       * <p>Note super is not being called because we don't want to add restirctions that can cause problems
98       * with the use of wildcard</p>
99       *
100      * {@inheritDoc}
101      */
102     @Override
103     public void copyFromAttributeDefinition(AttributeDefinition attributeDefinition) {
104         // label
105         if (StringUtils.isEmpty(getLabel())) {
106             setLabel(attributeDefinition.getLabel());
107         }
108 
109         // short label
110         if (StringUtils.isEmpty(getShortLabel())) {
111             setShortLabel(attributeDefinition.getShortLabel());
112         }
113 
114         // security
115         if ((attributeDefinition.getAttributeSecurity() != null) && ((getDataFieldSecurity() == null) || (
116                 getDataFieldSecurity().getAttributeSecurity() == null))) {
117             initializeComponentSecurity();
118 
119             getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity());
120         }
121 
122         // options
123         if (getOptionsFinder() == null) {
124             setOptionsFinder(attributeDefinition.getOptionsFinder());
125         }
126 
127         // use control from dictionary if not specified and convert for searching
128         if (getControl() == null) {
129             Control control = convertControlToLookupControl(attributeDefinition);
130             setControl(control);
131         }
132 
133         // overwrite maxLength to allow for wildcards and ranges; set a minimum max length unless it is greater than 100
134         setMaxLength(100);
135         if ( attributeDefinition.getMaxLength()!=null && (attributeDefinition.getMaxLength() > 100)) {
136             setMaxLength(attributeDefinition.getMaxLength());
137         }
138 
139         // set default value for active field to true
140         if (getDefaultValue() == null || (getDefaultValue() instanceof String && StringUtils.isEmpty((String)getDefaultValue()))) {
141             if ((StringUtils.equals(getPropertyName(), KRADPropertyConstants.ACTIVE))) {
142                 setDefaultValue(KRADConstants.YES_INDICATOR_VALUE);
143             }
144         }
145     }
146 
147     /**
148      * If control definition is defined on the given attribute definition, converts to an appropriate control for
149      * searching (if necessary) and returns a copy for setting on the field.
150      *
151      * @param attributeDefinition attribute definition instance to retrieve control from
152      * @return Control instance or null if not found
153      */
154     protected static Control convertControlToLookupControl(AttributeDefinition attributeDefinition) {
155         if (attributeDefinition.getControlField() == null) {
156             return null;
157         }
158 
159         Control newControl = null;
160 
161         // convert checkbox to radio with yes/no/both options
162         if (CheckboxControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) {
163             newControl = (RadioGroupControl) ComponentFactory.getNewComponentInstance(
164                     ComponentFactory.CHECKBOX_CONVERTED_RADIO_CONTROL);
165         }
166         // text areas get converted to simple text inputs
167         else if (TextAreaControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) {
168             newControl = ComponentFactory.getTextControl();
169         } else {
170             newControl = ComponentUtils.copy(attributeDefinition.getControlField(), "");
171         }
172 
173         return newControl;
174     }
175 
176     /**
177      * Invoked before search is carried out to perform any necessary filtering of the criteria.
178      *
179      * @param searchCriteria the search criteria to be filtered
180      * @return map of filtered search criteria
181      */
182     public Map<String, String> filterSearchCriteria(Map<String, String> searchCriteria) {
183         return searchCriteria;
184     }
185 
186     /**
187      * Indicates whether wildcard and other search operators should be disabled (treated as literals) for
188      * the input field.
189      *
190      * @return boolean true if wildcards and search operators should be disabled, false if enabled
191      */
192     @BeanTagAttribute(name = "disableWildcardsAndOperators")
193     public boolean isDisableWildcardsAndOperators() {
194         return this.disableWildcardsAndOperators;
195     }
196 
197     /**
198      * @see LookupInputField#isDisableWildcardsAndOperators()
199      */
200     public void setDisableWildcardsAndOperators(boolean disableWildcardsAndOperators) {
201         this.disableWildcardsAndOperators = disableWildcardsAndOperators;
202     }
203 
204     /**
205      * Indicates whether the option for all values (blank key, 'All' label) should be added to the lookup
206      * field, note this is only supported for {@link org.kuali.rice.krad.uif.control.MultiValueControl} instance.
207      *
208      * @return boolean true if all option should be added, false if not
209      */
210     @BeanTagAttribute(name = "addControlSelectAllOption")
211     public boolean isAddControlSelectAllOption() {
212         return addControlSelectAllOption;
213     }
214 
215     /**
216      * @see LookupInputField#isAddControlSelectAllOption()
217      */
218     public void setAddControlSelectAllOption(boolean addControlSelectAllOption) {
219         this.addControlSelectAllOption = addControlSelectAllOption;
220     }
221 
222     /**
223      * Indicates a field group should be created containing a from and to input field for date search
224      * ranges.
225      *
226      * <p>
227      * When this is set to true, the input field will be replaced by a field group that is created by
228      * copying the prototype {@link org.kuali.rice.krad.lookup.LookupView#getRangeFieldGroupPrototype()}. Within the
229      * field group, an lookup input field will be created for the from field, and this input will be used
230      * as the to date field. Between the two fields a message will be rendered that can be specified using
231      * {@link LookupView#getRangedToMessage()}
232      * </p>
233      *
234      * @return boolean true if ranged field group should be created, false if not
235      */
236     public boolean isRanged() {
237         return ranged;
238     }
239 
240     /**
241      * @see LookupInputField#isRanged()
242      */
243     public void setRanged(boolean ranged) {
244         this.ranged = ranged;
245     }
246 }