001/**
002 * Copyright 2005-2018 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.control;
017
018import java.util.ArrayList;
019import java.util.List;
020
021import org.apache.commons.lang.StringUtils;
022import org.kuali.rice.krad.datadictionary.parse.BeanTag;
023import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
024import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
025import org.kuali.rice.krad.uif.UifConstants;
026import org.kuali.rice.krad.uif.component.Component;
027import org.kuali.rice.krad.uif.element.ContentElementBase;
028import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle;
029import org.kuali.rice.krad.uif.util.LifecycleElement;
030import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
031import org.kuali.rice.krad.uif.view.View;
032
033/**
034 * Base class for all {@link Control} implementations.
035 *
036 * @author Kuali Rice Team (rice.collab@kuali.org)
037 */
038@BeanTag(name = "controlBase", parent = "Uif-ControlBase")
039public abstract class ControlBase extends ContentElementBase implements Control {
040    private static final long serialVersionUID = -7898244978136312663L;
041
042    private int tabIndex;
043
044    private boolean disabled;
045    private String disabledExpression;
046    private String disabledReason;
047    private boolean evaluateDisabledOnKeyUp;
048
049    private String disabledConditionJs;
050    private List<String> disabledConditionControlNames;
051
052    private List<String> disabledWhenChangedPropertyNames;
053    private List<String> enabledWhenChangedPropertyNames;
054
055    public ControlBase() {
056        super();
057
058        disabled = false;
059        disabledWhenChangedPropertyNames = new ArrayList<String>();
060        enabledWhenChangedPropertyNames = new ArrayList<String>();
061    }
062
063    /**
064     * Sets the disabledExpression, if any, evaluates it and sets the disabled property
065     *
066     * @param model top level object containing the data (could be the form or a
067     * top level business object, dto)
068     * @param parent
069     */
070    @Override
071    public void performApplyModel(Object model, LifecycleElement parent) {
072        super.performApplyModel(model, parent);
073
074        disabledExpression = this.getPropertyExpression("disabled");
075        if (disabledExpression != null) {
076            ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
077
078            disabledExpression = expressionEvaluator.replaceBindingPrefixes(ViewLifecycle.getView(), this,
079                    disabledExpression);
080            disabled = (Boolean) expressionEvaluator.evaluateExpression(this.getContext(), disabledExpression);
081        }
082    }
083
084    /**
085     * Parses the disabled expressions, if any, to equivalent javascript and evaluates the disable/enable when
086     * changed property names.
087     *
088     * @param model top level object containing the data
089     * @param parent parent component
090     */
091    @Override
092    public void performFinalize(Object model, LifecycleElement parent) {
093        super.performFinalize(model, parent);
094
095        ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator();
096
097        if (StringUtils.isNotEmpty(disabledExpression)
098                && !disabledExpression.equalsIgnoreCase("true")
099                && !disabledExpression.equalsIgnoreCase("false")) {
100            disabledConditionControlNames = new ArrayList<String>();
101            disabledConditionJs = expressionEvaluator.parseExpression(disabledExpression, disabledConditionControlNames,
102                    this.getContext());
103        }
104
105        View view = ViewLifecycle.getView();
106        List<String> adjustedDisablePropertyNames = new ArrayList<String>();
107        for (String propertyName : disabledWhenChangedPropertyNames) {
108            adjustedDisablePropertyNames.add(expressionEvaluator.replaceBindingPrefixes(view, this, propertyName));
109        }
110        disabledWhenChangedPropertyNames = adjustedDisablePropertyNames;
111
112        List<String> adjustedEnablePropertyNames = new ArrayList<String>();
113        for (String propertyName : enabledWhenChangedPropertyNames) {
114            adjustedEnablePropertyNames.add(expressionEvaluator.replaceBindingPrefixes(view, this, propertyName));
115        }
116        enabledWhenChangedPropertyNames = adjustedEnablePropertyNames;
117
118        // add control role
119        this.addDataAttribute(UifConstants.DataAttributes.ROLE, UifConstants.RoleTypes.CONTROL);
120    }
121
122    /**
123     * {@inheritDoc}
124     */
125    @Override
126    public final String getComponentTypeName() {
127        return "control";
128    }
129
130    /**
131     * {@inheritDoc}
132     */
133    @BeanTagAttribute
134    public int getTabIndex() {
135        return this.tabIndex;
136    }
137
138    /**
139     * @see org.kuali.rice.krad.uif.control.Control#setTabIndex(int)
140     */
141    public void setTabIndex(int tabIndex) {
142        this.tabIndex = tabIndex;
143    }
144
145    /**
146     * @see org.kuali.rice.krad.uif.control.Control#isDisabled()
147     */
148    @BeanTagAttribute
149    public boolean isDisabled() {
150        return disabled;
151    }
152
153    /**
154     * @see org.kuali.rice.krad.uif.control.Control#setDisabled(boolean)
155     */
156    public void setDisabled(boolean disabled) {
157        this.disabled = disabled;
158    }
159
160    /**
161     * @see org.kuali.rice.krad.uif.control.Control#getDisabledReason()
162     */
163    @BeanTagAttribute
164    public String getDisabledReason() {
165        return disabledReason;
166    }
167
168    /**
169     * @see org.kuali.rice.krad.uif.control.Control#setDisabledReason(java.lang.String)
170     */
171    public void setDisabledReason(String disabledReason) {
172        this.disabledReason = disabledReason;
173    }
174
175    /**
176     * Evaluate the disable condition on controls which disable it on each key up event
177     *
178     * @return true if evaluate on key up, false otherwise
179     */
180    @BeanTagAttribute
181    public boolean isEvaluateDisabledOnKeyUp() {
182        return evaluateDisabledOnKeyUp;
183    }
184
185    /**
186     * Set evaluateDisableOnKeyUp
187     *
188     * @param evaluateDisabledOnKeyUp
189     */
190    public void setEvaluateDisabledOnKeyUp(boolean evaluateDisabledOnKeyUp) {
191        this.evaluateDisabledOnKeyUp = evaluateDisabledOnKeyUp;
192    }
193
194    /**
195     * Get the disable condition js derived from the springEL, cannot be set.
196     *
197     * @return the disableConditionJs javascript to be evaluated
198     */
199    public String getDisabledConditionJs() {
200        return disabledConditionJs;
201    }
202
203    /**
204     * Control names to add handlers to for disable functionality, cannot be set
205     *
206     * @return control names to add handlers to for disable
207     */
208    public List<String> getDisabledConditionControlNames() {
209        return disabledConditionControlNames;
210    }
211
212    /**
213     * Gets the property names of fields that when changed, will disable this component
214     *
215     * @return the property names to monitor for change to disable this component
216     */
217    @BeanTagAttribute
218    public List<String> getDisabledWhenChangedPropertyNames() {
219        return disabledWhenChangedPropertyNames;
220    }
221
222    /**
223     * Sets the property names of fields that when changed, will disable this component
224     *
225     * @param disabledWhenChangedPropertyNames
226     */
227    public void setDisabledWhenChangedPropertyNames(List<String> disabledWhenChangedPropertyNames) {
228        this.disabledWhenChangedPropertyNames = disabledWhenChangedPropertyNames;
229    }
230
231    /**
232     * Gets the property names of fields that when changed, will enable this component
233     *
234     * @return the property names to monitor for change to enable this component
235     */
236    @BeanTagAttribute
237    public List<String> getEnabledWhenChangedPropertyNames() {
238        return enabledWhenChangedPropertyNames;
239    }
240
241    /**
242     * Sets the property names of fields that when changed, will enable this component
243     *
244     * @param enabledWhenChangedPropertyNames
245     */
246    public void setEnabledWhenChangedPropertyNames(List<String> enabledWhenChangedPropertyNames) {
247        this.enabledWhenChangedPropertyNames = enabledWhenChangedPropertyNames;
248    }
249
250    /**
251     * Sets the disabled expression
252     *
253     * @param disabledExpression
254     */
255    protected void setDisabledExpression(String disabledExpression) {
256        this.disabledExpression = disabledExpression;
257    }
258
259    /**
260     * Sets the disabled condition javascript
261     *
262     * @param disabledConditionJs
263     */
264    protected void setDisabledConditionJs(String disabledConditionJs) {
265        this.disabledConditionJs = disabledConditionJs;
266    }
267
268    /**
269     * Sets the disabled condition control names
270     *
271     * @param disabledConditionControlNames
272     */
273    protected void setDisabledConditionControlNames(List<String> disabledConditionControlNames) {
274        this.disabledConditionControlNames = disabledConditionControlNames;
275    }
276
277    /**
278     * {@inheritDoc}
279     */
280    @Override
281    public void completeValidation(ValidationTrace tracer) {
282        tracer.addBean(this);
283
284        super.completeValidation(tracer.getCopy());
285    }
286}