001/**
002 * Copyright 2005-2016 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.core.api.util.KeyValue;
021import org.kuali.rice.krad.datadictionary.AttributeDefinition;
022import org.kuali.rice.krad.uif.component.Component;
023import org.kuali.rice.krad.uif.control.CheckboxControl;
024import org.kuali.rice.krad.uif.control.Control;
025import org.kuali.rice.krad.uif.control.MultiValueControl;
026import org.kuali.rice.krad.uif.control.RadioGroupControl;
027import org.kuali.rice.krad.uif.control.TextAreaControl;
028import org.kuali.rice.krad.uif.util.ComponentFactory;
029import org.kuali.rice.krad.uif.util.ComponentUtils;
030import org.kuali.rice.krad.uif.view.View;
031import org.kuali.rice.krad.util.KRADConstants;
032import org.kuali.rice.krad.util.KRADPropertyConstants;
033
034import java.util.ArrayList;
035import java.util.List;
036
037/**
038 * Custom <code>InputField</code> for search fields within a lookup view
039 *
040 * @author Kuali Rice Team (rice.collab@kuali.org)
041 */
042public class LookupInputField extends InputField {
043    private static final long serialVersionUID = -8294275596836322699L;
044
045    private boolean treatWildcardsAndOperatorsAsLiteral;
046    private boolean addAllOption;
047
048    public LookupInputField() {
049        super();
050
051        treatWildcardsAndOperatorsAsLiteral = false;
052        addAllOption = false;
053    }
054
055    /**
056     * The following actions are performed:
057     *
058     * <ul>
059     * <li>Add all option if enabled and control is multi-value</li>
060     * </ul>
061     *
062     * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
063     *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
064     */
065    @Override
066    public void performFinalize(View view, Object model, Component parent) {
067        super.performFinalize(view, model, parent);
068
069        // add all option
070        if (addAllOption && (getControl() != null) && getControl() instanceof MultiValueControl) {
071            MultiValueControl multiValueControl = (MultiValueControl) getControl();
072            if (multiValueControl.getOptions() != null) {
073                List<KeyValue> fieldOptions = multiValueControl.getOptions();
074                fieldOptions.add(0, new ConcreteKeyValue("", "All"));
075
076                multiValueControl.setOptions(fieldOptions);
077            }
078        }
079    }
080
081    /**
082     * Override of InputField copy to setup properties necessary to make the field usable for inputting
083     * search criteria
084     *
085     * @param attributeDefinition - AttributeDefinition instance the property values should be copied from
086     * @see DataField#copyFromAttributeDefinition(org.kuali.rice.krad.uif.view.View,
087     * org.kuali.rice.krad.datadictionary.AttributeDefinition)
088     */
089    @Override
090    public void copyFromAttributeDefinition(View view, AttributeDefinition attributeDefinition) {
091        // label
092        if (StringUtils.isEmpty(getLabel())) {
093            setLabel(attributeDefinition.getLabel());
094        }
095
096        // short label
097        if (StringUtils.isEmpty(getShortLabel())) {
098            setShortLabel(attributeDefinition.getShortLabel());
099        }
100
101        // security
102        if (getDataFieldSecurity().getAttributeSecurity() == null) {
103            getDataFieldSecurity().setAttributeSecurity(attributeDefinition.getAttributeSecurity());
104        }
105
106        // options
107        if (getOptionsFinder() == null) {
108            setOptionsFinder(attributeDefinition.getOptionsFinder());
109        }
110
111        // TODO: what about formatter?
112
113        // use control from dictionary if not specified and convert for searching
114        if (getControl() == null) {
115            Control control = convertControlToLookupControl(attributeDefinition);
116            view.assignComponentIds(control);
117
118            setControl(control);
119        }
120
121        // overwrite maxLength to allow for wildcards and ranges
122        setMaxLength(100);
123
124        // set default value for active field to true
125        if (StringUtils.isEmpty(getDefaultValue())) {
126            if ((StringUtils.equals(getPropertyName(), KRADPropertyConstants.ACTIVE))) {
127                setDefaultValue(KRADConstants.YES_INDICATOR_VALUE);
128            }
129        }
130
131        /*
132           * TODO delyea: FieldUtils.createAndPopulateFieldsForLookup used to allow for a set of property names to be passed in via the URL
133           * parameters of the lookup url to set fields as 'read only'
134           */
135
136    }
137
138    /**
139     * If control definition is defined on the given attribute definition, converts to an appropriate control for
140     * searching (if necessary) and returns a copy for setting on the field
141     *
142     * @param attributeDefinition - attribute definition instance to retrieve control from
143     * @return Control instance or null if not found
144     */
145    protected static Control convertControlToLookupControl(AttributeDefinition attributeDefinition) {
146        if (attributeDefinition.getControlField() == null) {
147            return null;
148        }
149
150        Control newControl = null;
151
152        // convert checkbox to radio with yes/no/both options
153        if (CheckboxControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) {
154            newControl = ComponentFactory.getRadioGroupControlHorizontal();
155            List<KeyValue> options = new ArrayList<KeyValue>();
156            options.add(new ConcreteKeyValue("Y", "Yes"));
157            options.add(new ConcreteKeyValue("N", "No"));
158            options.add(new ConcreteKeyValue("", "Both"));
159
160            ((RadioGroupControl) newControl).setOptions(options);
161        }
162        // text areas get converted to simple text inputs
163        else if (TextAreaControl.class.isAssignableFrom(attributeDefinition.getControlField().getClass())) {
164            newControl = ComponentFactory.getTextControl();
165        } else {
166            newControl = ComponentUtils.copy(attributeDefinition.getControlField(), "");
167        }
168
169        return newControl;
170    }
171
172    /**
173     * @return the treatWildcardsAndOperatorsAsLiteral
174     */
175    public boolean isTreatWildcardsAndOperatorsAsLiteral() {
176        return this.treatWildcardsAndOperatorsAsLiteral;
177    }
178
179    /**
180     * @param treatWildcardsAndOperatorsAsLiteral the treatWildcardsAndOperatorsAsLiteral to set
181     */
182    public void setTreatWildcardsAndOperatorsAsLiteral(boolean treatWildcardsAndOperatorsAsLiteral) {
183        this.treatWildcardsAndOperatorsAsLiteral = treatWildcardsAndOperatorsAsLiteral;
184    }
185
186    /**
187     * Indicates whether the option for all values (blank key, 'All' label) should be added to the lookup
188     * field, note this is only supported for {@link org.kuali.rice.krad.uif.control.MultiValueControl} instance
189     *
190     * @return boolean true if all option should be added, false if not
191     */
192    public boolean isAddAllOption() {
193        return addAllOption;
194    }
195
196    /**
197     * Setter for the add all option indicator
198     *
199     * @param addAllOption
200     */
201    public void setAddAllOption(boolean addAllOption) {
202        this.addAllOption = addAllOption;
203    }
204}