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