View Javadoc

1   /**
2    * Copyright 2005-2012 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.core.api.util.KeyValue;
21  import org.kuali.rice.core.api.util.type.TypeUtils;
22  import org.kuali.rice.core.web.format.Formatter;
23  import org.kuali.rice.krad.bo.DataObjectRelationship;
24  import org.kuali.rice.krad.bo.KualiCode;
25  import org.kuali.rice.krad.datadictionary.AttributeDefinition;
26  import org.kuali.rice.krad.datadictionary.AttributeSecurity;
27  import org.kuali.rice.krad.datadictionary.validation.constraint.CaseConstraint;
28  import org.kuali.rice.krad.datadictionary.validation.constraint.MustOccurConstraint;
29  import org.kuali.rice.krad.datadictionary.validation.constraint.PrerequisiteConstraint;
30  import org.kuali.rice.krad.datadictionary.validation.constraint.SimpleConstraint;
31  import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
32  import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
33  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
34  import org.kuali.rice.krad.uif.UifConstants;
35  import org.kuali.rice.krad.uif.control.MultiValueControl;
36  import org.kuali.rice.krad.uif.control.UifKeyValuesFinder;
37  import org.kuali.rice.krad.uif.util.ComponentFactory;
38  import org.kuali.rice.krad.uif.view.FormView;
39  import org.kuali.rice.krad.uif.view.View;
40  import org.kuali.rice.krad.uif.control.Control;
41  import org.kuali.rice.krad.uif.control.MultiValueControlBase;
42  import org.kuali.rice.krad.uif.component.BindingInfo;
43  import org.kuali.rice.krad.uif.component.Component;
44  import org.kuali.rice.krad.uif.component.DataBinding;
45  import org.kuali.rice.krad.uif.util.ClientValidationUtils;
46  import org.kuali.rice.krad.uif.util.ComponentUtils;
47  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
48  import org.kuali.rice.krad.uif.util.ViewModelUtils;
49  import org.kuali.rice.krad.uif.view.ViewModel;
50  import org.kuali.rice.krad.uif.widget.DirectInquiry;
51  import org.kuali.rice.krad.uif.widget.Inquiry;
52  import org.kuali.rice.krad.uif.widget.QuickFinder;
53  import org.kuali.rice.krad.uif.widget.Suggest;
54  import org.kuali.rice.krad.util.KRADPropertyConstants;
55  import org.kuali.rice.krad.util.ObjectUtils;
56  import org.kuali.rice.krad.valuefinder.ValueFinder;
57  
58  import java.util.ArrayList;
59  import java.util.List;
60  
61  /**
62   * Field that encapsulates data input/output captured by an attribute within the
63   * application
64   *
65   * <p>                                                                                                                                    R
66   * The <code>AttributField</code> provides the majority of the data input/output
67   * for the screen. Through these fields the model can be displayed and updated.
68   * For data input, the field contains a <code>Control</code> instance will
69   * render an HTML control element(s). The attribute field also contains a
70   * <code>LabelField</code>, summary, and widgets such as a quickfinder (for
71   * looking up values) and inquiry (for getting more information on the value).
72   * <code>InputField</code> instances can have associated messages (errors)
73   * due to invalid input or business rule failures. Security can also be
74   * configured to restrict who may view the fields value.
75   * </p>
76   *
77   * @author Kuali Rice Team (rice.collab@kuali.org)
78   */
79  public class InputField extends DataField {
80      private static final long serialVersionUID = -3703656713706343840L;
81  
82      // constraint variables
83      private String customValidatorClass;
84      private ValidCharactersConstraint validCharactersConstraint;
85      private CaseConstraint caseConstraint;
86      private List<PrerequisiteConstraint> dependencyConstraints;
87      private List<MustOccurConstraint> mustOccurConstraints;
88      private SimpleConstraint simpleConstraint;
89  
90      // display props
91      private Control control;
92      private KeyValuesFinder optionsFinder;
93      private boolean performUppercase;
94  
95      private String errorMessagePlacement;
96      private ErrorsField errorsField;
97  
98      // messages
99      private String constraintText;
100     private String instructionalText;
101 
102     private MessageField instructionalMessageField;
103     private MessageField constraintMessageField;
104 
105     private AttributeQuery fieldAttributeQuery;
106 
107     // widgets
108     private QuickFinder fieldLookup;
109     private DirectInquiry fieldDirectInquiry;
110     private Suggest fieldSuggest;
111 
112     public InputField() {
113         super();
114 
115         simpleConstraint = new SimpleConstraint();
116     }
117 
118     /**
119      * The following actions are performed:
120      *
121      * <ul>
122      * <li>Set the ids for the various attribute components</li>
123      * <li>Sets up the client side validation for constraints on this field. In
124      * addition, it sets up the messages applied to this field</li>
125      * </ul>
126      *
127      * @see org.kuali.rice.krad.uif.component.ComponentBase#performFinalize(org.kuali.rice.krad.uif.view.View,
128      *      java.lang.Object, org.kuali.rice.krad.uif.component.Component)
129      */
130     @Override
131     public void performFinalize(View view, Object model, Component parent) {
132         super.performFinalize(view, model, parent);
133 
134         setupIds();
135 
136         // invoke options finder if options not configured on the control
137         List<KeyValue> fieldOptions = new ArrayList<KeyValue>();
138 
139         // use options directly configured on the control first
140         if ((control != null) && control instanceof MultiValueControlBase) {
141             MultiValueControlBase multiValueControl = (MultiValueControlBase) control;
142             if ((multiValueControl.getOptions() != null) && !multiValueControl.getOptions().isEmpty()) {
143                 fieldOptions = multiValueControl.getOptions();
144             }
145         }
146 
147         // if options not configured on the control, invoke configured options finder
148         if (fieldOptions.isEmpty() && (optionsFinder != null)) {
149             if (optionsFinder instanceof UifKeyValuesFinder) {
150                 fieldOptions = ((UifKeyValuesFinder) optionsFinder).getKeyValues((ViewModel) model);
151 
152                 // check if blank option should be added
153                 if (((UifKeyValuesFinder) optionsFinder).isAddBlankOption()) {
154                     fieldOptions.add(0, new ConcreteKeyValue("", ""));
155                 }
156             } else {
157                 fieldOptions = optionsFinder.getKeyValues();
158             }
159 
160             if ((control != null) && control instanceof MultiValueControlBase) {
161                ((MultiValueControlBase) control).setOptions(fieldOptions);
162             }
163         }
164 
165         // if read only do key/value translation if necessary (if alternative and additional properties not set)
166         if (isReadOnly()
167                 && !fieldOptions.isEmpty()
168                 && StringUtils.isBlank(getAlternateDisplayValue())
169                 && StringUtils.isBlank(getAdditionalDisplayValue())
170                 && StringUtils.isBlank(getAlternateDisplayPropertyName())
171                 && StringUtils.isBlank(getAdditionalDisplayPropertyName())) {
172 
173             Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, getBindingInfo().getBindingPath());
174 
175             // TODO: can we translate Collections? (possibly combining output with delimiter
176             if ((fieldValue != null) && (TypeUtils.isSimpleType(fieldValue.getClass()))) {
177                 for (KeyValue keyValue : fieldOptions) {
178                     if (StringUtils.equals((String) fieldValue, keyValue.getKey())) {
179                         setAlternateDisplayValue(keyValue.getValue());
180                         break;
181                     }
182                 }
183             }
184         }
185 
186         // if read only or the control is null no input can be given so no need to setup validation
187         if (isReadOnly() || getControl() == null) {
188             return;
189         }
190 
191         // Sets message
192         if (StringUtils.isNotBlank(instructionalText)) {
193             instructionalMessageField.setMessageText(instructionalText);
194         }
195 
196         // Sets constraints
197         if (StringUtils.isNotBlank(constraintText)) {
198             constraintMessageField.setMessageText(constraintText);
199         }
200 
201         // adjust paths on PrerequisiteConstraint property names
202         adjustPrerequisiteConstraintBinding(dependencyConstraints);
203 
204         // adjust paths on MustOccurConstraints property names
205         adjustMustOccurConstraintBinding(mustOccurConstraints);
206 
207         // adjust paths on CaseConstraint property names
208         if (caseConstraint != null) {
209             String propertyName = getBindingInfo().getPropertyAdjustedBindingPath(caseConstraint.getPropertyName());
210             caseConstraint.setPropertyName(propertyName);
211         }        
212 
213         setupFieldQuery();
214 
215         if (view instanceof FormView && ((FormView) view).isValidateClientSide()) {
216             ClientValidationUtils.processAndApplyConstraints(this, view);
217         }
218     }
219 
220     protected void adjustMustOccurConstraintBinding(List<MustOccurConstraint> mustOccurConstraints) {
221         if (mustOccurConstraints != null) {
222             for (MustOccurConstraint mustOccurConstraint : mustOccurConstraints) {
223                 adjustPrerequisiteConstraintBinding(mustOccurConstraint.getPrerequisiteConstraints());
224                 adjustMustOccurConstraintBinding(mustOccurConstraint.getMustOccurConstraints());
225             }
226         }
227     }
228 
229     protected void adjustPrerequisiteConstraintBinding(List<PrerequisiteConstraint> prerequisiteConstraints) {
230         if (prerequisiteConstraints != null) {
231             for (PrerequisiteConstraint prerequisiteConstraint : prerequisiteConstraints) {
232                 String propertyName = getBindingInfo().getPropertyAdjustedBindingPath(prerequisiteConstraint.getPropertyName());
233                 prerequisiteConstraint.setPropertyName(propertyName);
234             }
235         }
236     }
237 
238     /**
239      * Performs setup of the field attribute query and informational display properties. Paths
240      * are adjusted to match the binding for the this field, and the necessary onblur script for
241      * triggering the query client side is constructed
242      */
243     protected void setupFieldQuery() {
244         if (getFieldAttributeQuery() != null) {
245             // adjust paths on query mappings
246             getFieldAttributeQuery().updateQueryFieldMapping(getBindingInfo());
247             getFieldAttributeQuery().updateReturnFieldMapping(getBindingInfo());
248             getFieldAttributeQuery().updateQueryMethodArgumentFieldList(getBindingInfo());
249 
250             // build onblur script for field query
251             String script = "executeFieldQuery('" + getControl().getId() + "',";
252             script += "'" + getId() + "'," + getFieldAttributeQuery().getQueryFieldMappingJsString() + ",";
253             script += getFieldAttributeQuery().getQueryMethodArgumentFieldsJsString() + ",";
254             script += getFieldAttributeQuery().getReturnFieldMappingJsString() + ");";
255 
256             if (StringUtils.isNotBlank(getControl().getOnBlurScript())) {
257                 script = getControl().getOnBlurScript() + script;
258             }
259             getControl().setOnBlurScript(script);
260         }
261     }
262 
263     /**
264      * Sets the ids on all components the attribute field uses so they will all
265      * contain this attribute's id in their ids. This is useful for jQuery
266      * manipulation.
267      */
268     protected void setupIds() {
269         // update ids so they all match the attribute
270         if (getControl() != null) {
271             getControl().setId(getId());
272         }
273 
274         setNestedComponentIdAndSuffix(getErrorsField(), UifConstants.IdSuffixes.ERRORS);
275         setNestedComponentIdAndSuffix(getLabelField(), UifConstants.IdSuffixes.LABEL);
276         setNestedComponentIdAndSuffix(getInstructionalMessageField(), UifConstants.IdSuffixes.INSTRUCTIONAL);
277         setNestedComponentIdAndSuffix(getConstraintMessageField(), UifConstants.IdSuffixes.CONSTRAINT);
278         setNestedComponentIdAndSuffix(getFieldLookup(), UifConstants.IdSuffixes.QUICK_FINDER);
279         setNestedComponentIdAndSuffix(getFieldDirectInquiry(), UifConstants.IdSuffixes.DIRECT_INQUIRY);
280         setNestedComponentIdAndSuffix(getFieldSuggest(), UifConstants.IdSuffixes.SUGGEST);
281 
282         setId(getId() + UifConstants.IdSuffixes.ATTRIBUTE);
283     }
284 
285     /**
286      * Helper method for suffixing the ids of the fields nested components
287      *
288      * @param component - component to adjust id for
289      * @param suffix - suffix to append to id
290      */
291     private void setNestedComponentIdAndSuffix(Component component, String suffix) {
292         if (component != null) {
293             String fieldId = getId();
294             fieldId += suffix;
295 
296             component.setId(fieldId);
297         }
298     }
299 
300     /**
301      * Defaults the properties of the <code>InputField</code> to the
302      * corresponding properties of its <code>AttributeDefinition</code>
303      * retrieved from the dictionary (if such an entry exists). If the field
304      * already contains a value for a property, the definitions value is not
305      * used.
306      *
307      * @param view - view instance the field belongs to
308      * @param attributeDefinition - AttributeDefinition instance the property values should be
309      * copied from
310      */
311     public void copyFromAttributeDefinition(View view, AttributeDefinition attributeDefinition) {
312         super.copyFromAttributeDefinition(view, attributeDefinition);
313 
314         // max length
315         if (getMaxLength() == null) {
316             setMaxLength(attributeDefinition.getMaxLength());
317         }
318 
319         // min length
320         if (getMinLength() == null) {
321             setMinLength(attributeDefinition.getMinLength());
322         }
323 
324         // valid characters
325         if (getValidCharactersConstraint() == null) {
326             setValidCharactersConstraint(attributeDefinition.getValidCharactersConstraint());
327         }
328 
329         if (getCaseConstraint() == null) {
330             setCaseConstraint(attributeDefinition.getCaseConstraint());
331         }
332 
333         if (getDependencyConstraints() == null) {
334             setDependencyConstraints(attributeDefinition.getPrerequisiteConstraints());
335         }
336 
337         if (getMustOccurConstraints() == null) {
338             setMustOccurConstraints(attributeDefinition.getMustOccurConstraints());
339         }
340 
341         // required
342         if (getRequired() == null) {
343             setRequired(attributeDefinition.isRequired());
344 
345             //if still null, default to false
346             if (getRequired() == null) {
347                 setRequired(false);
348             }
349         }
350 
351         // control
352         if ((getControl() == null) && (attributeDefinition.getControlField() != null)) {
353             Control control = attributeDefinition.getControlField();
354             view.assignComponentIds(control);
355 
356             setControl(ComponentUtils.copy(control));
357         }
358 
359         // constraint
360         if (StringUtils.isEmpty(getConstraintText())) {
361             setConstraintText(attributeDefinition.getConstraintText());
362             getConstraintMessageField().setMessageText(attributeDefinition.getConstraintText());
363         }
364 
365         // options
366         if (getOptionsFinder() == null) {
367             setOptionsFinder(attributeDefinition.getOptionsFinder());
368         }
369     }
370 
371     /**
372      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
373      */
374     @Override
375     public List<Component> getComponentsForLifecycle() {
376         List<Component> components = super.getComponentsForLifecycle();
377 
378         components.add(control);
379         components.add(errorsField);
380         components.add(fieldLookup);
381         components.add(fieldDirectInquiry);
382         components.add(fieldSuggest);
383 
384         return components;
385     }
386 
387     /**
388      * @see DataField#isInputAllowed()
389      */
390     @Override
391     public boolean isInputAllowed() {
392         return true;
393     }
394 
395     /**
396      * <code>Control</code> instance that should be used to input data for the
397      * field
398      *
399      * <p>
400      * When the field is editable, the control will be rendered so the user can
401      * input a value(s). Controls typically are part of a Form and render
402      * standard HTML control elements such as text input, select, and checkbox
403      * </p>
404      *
405      * @return Control instance
406      */
407     public Control getControl() {
408         return this.control;
409     }
410 
411     /**
412      * Setter for the field's control
413      *
414      * @param control
415      */
416     public void setControl(Control control) {
417         this.control = control;
418     }
419 
420     public String getErrorMessagePlacement() {
421         return this.errorMessagePlacement;
422     }
423 
424     public void setErrorMessagePlacement(String errorMessagePlacement) {
425         this.errorMessagePlacement = errorMessagePlacement;
426     }
427 
428     /**
429      * Field that contains the messages (errors) for the attribute field. The
430      * <code>ErrorsField</code> holds configuration on associated messages along
431      * with information on rendering the messages in the user interface
432      *
433      * @return ErrorsField instance
434      */
435     public ErrorsField getErrorsField() {
436         return this.errorsField;
437     }
438 
439     /**
440      * Setter for the attribute field's errors field
441      *
442      * @param errorsField
443      */
444     public void setErrorsField(ErrorsField errorsField) {
445         this.errorsField = errorsField;
446     }
447 
448     /**
449      * Instance of <code>KeyValluesFinder</code> that should be invoked to
450      * provide a List of values the field can have. Generally used to provide
451      * the options for a multi-value control or to validate the submitted field
452      * value
453      *
454      * @return KeyValuesFinder instance
455      */
456     public KeyValuesFinder getOptionsFinder() {
457         return this.optionsFinder;
458     }
459 
460     /**
461      * Setter for the field's KeyValuesFinder instance
462      *
463      * @param optionsFinder
464      */
465     public void setOptionsFinder(KeyValuesFinder optionsFinder) {
466         this.optionsFinder = optionsFinder;
467     }
468 
469     /**
470      * Setter that takes in the class name for the options finder and creates a
471      * new instance to use as the finder for the attribute field
472      *
473      * @param optionsFinderClass
474      */
475     public void setOptionsFinderClass(Class<? extends KeyValuesFinder> optionsFinderClass) {
476         this.optionsFinder = ObjectUtils.newInstance(optionsFinderClass);
477     }
478 
479     /**
480      * Text explaining how to use the field, including things like what values should be selected
481      * in certain cases and so on (instructions)
482      *
483      * @return String instructional message
484      */
485     public String getInstructionalText() {
486         return this.instructionalText;
487     }
488 
489     /**
490      * Setter for the instructional message
491      *
492      * @param instructionalText
493      */
494     public void setInstructionalText(String instructionalText) {
495         this.instructionalText = instructionalText;
496     }
497 
498     /**
499      * @see org.kuali.rice.krad.uif.component.ComponentBase#getSupportsOnLoad()
500      */
501     @Override
502     public boolean getSupportsOnLoad() {
503         return true;
504     }
505 
506     /**
507      * Lookup finder widget for the field
508      *
509      * <p>
510      * The quickfinder widget places a small icon next to the field that allows
511      * the user to bring up a search screen for finding valid field values. The
512      * <code>Widget</code> instance can be configured to point to a certain
513      * <code>LookupView</code>, or the framework will attempt to associate the
514      * field with a lookup based on its metadata (in particular its
515      * relationships in the model)
516      * </p>
517      *
518      * @return QuickFinder lookup widget
519      */
520     public QuickFinder getFieldLookup() {
521         return this.fieldLookup;
522     }
523 
524     /**
525      * Setter for the lookup widget
526      *
527      * @param fieldLookup
528      */
529     public void setFieldLookup(QuickFinder fieldLookup) {
530         this.fieldLookup = fieldLookup;
531     }
532 
533     /**
534      * Suggest box widget for the attribute field
535      *
536      * <p>
537      * If enabled (by render flag), as the user inputs data into the
538      * fields control a dynamic query is performed to provide the user
539      * suggestions on values which they can then select
540      * </p>
541      *
542      * <p>
543      * Note the Suggest widget is only valid when using a standard TextControl
544      * </p>
545      *
546      * @return Suggest instance
547      */
548     public Suggest getFieldSuggest() {
549         return fieldSuggest;
550     }
551 
552     /**
553      * Setter for the fields Suggest widget
554      *
555      * @param fieldSuggest
556      */
557     public void setFieldSuggest(Suggest fieldSuggest) {
558         this.fieldSuggest = fieldSuggest;
559     }
560 
561     /**
562      * Message field that displays instructional text
563      *
564      * <p>
565      * This message field can be configured to for adjusting how the instructional text will display. Generally
566      * the styleClasses property will be of most interest
567      * </p>
568      *
569      * @return MessageField instructional message field
570      */
571     public MessageField getInstructionalMessageField() {
572         return this.instructionalMessageField;
573     }
574 
575     /**
576      * Setter for the instructional text message field
577      *
578      * <p>
579      * Note this is the setter for the field that will render the instructional text. The actual text can be
580      * set on the field but can also be set using {@link #setInstructionalText(String)}
581      * </p>
582      *
583      * @param instructionalMessageField
584      */
585     public void setInstructionalMessageField(MessageField instructionalMessageField) {
586         this.instructionalMessageField = instructionalMessageField;
587     }
588 
589     /**
590      * Text that display a restriction on the value a field can hold
591      *
592      * <p>
593      * For example when the value must be a valid format (phone number, email), certain length, min/max value and
594      * so on this text can be used to indicate the constraint to the user. Generally displays with the control so
595      * it is visible when the user tabs to the field
596      * </p>
597      *
598      * @return String text to display for the constraint message
599      */
600     public String getConstraintText() {
601         return this.constraintText;
602     }
603 
604     /**
605      * Setter for the constraint message text
606      *
607      * @param constraintText
608      */
609     public void setConstraintText(String constraintText) {
610         this.constraintText = constraintText;
611     }
612 
613     /**
614      * Message field that displays constraint text
615      *
616      * <p>
617      * This message field can be configured to for adjusting how the constrain text will display. Generally
618      * the styleClasses property will be of most interest
619      * </p>
620      *
621      * @return MessageField constraint message field
622      */
623     public MessageField getConstraintMessageField() {
624         return this.constraintMessageField;
625     }
626 
627     /**
628      * Setter for the constraint text message field
629      *
630      * <p>
631      * Note this is the setter for the field that will render the constraint text. The actual text can be
632      * set on the field but can also be set using {@link #setConstraintText(String)}
633      * </p>
634      *
635      * @param constraintMessageField
636      */
637     public void setConstraintMessageField(MessageField constraintMessageField) {
638         this.constraintMessageField = constraintMessageField;
639     }
640 
641     /**
642      * Valid character constraint that defines regular expressions for the valid
643      * characters for this field
644      *
645      * @return the validCharactersConstraint
646      */
647     public ValidCharactersConstraint getValidCharactersConstraint() {
648         return this.validCharactersConstraint;
649     }
650 
651     /**
652      * @param validCharactersConstraint the validCharactersConstraint to set
653      */
654     public void setValidCharactersConstraint(ValidCharactersConstraint validCharactersConstraint) {
655         this.validCharactersConstraint = validCharactersConstraint;
656     }
657 
658     /**
659      * @return the caseConstraint
660      */
661     public CaseConstraint getCaseConstraint() {
662         return this.caseConstraint;
663     }
664 
665     /**
666      * @param caseConstraint the caseConstraint to set
667      */
668     public void setCaseConstraint(CaseConstraint caseConstraint) {
669         this.caseConstraint = caseConstraint;
670     }
671 
672     /**
673      * @return the dependencyConstraints
674      */
675     public List<PrerequisiteConstraint> getDependencyConstraints() {
676         return this.dependencyConstraints;
677     }
678 
679     /**
680      * @param dependencyConstraints the dependencyConstraints to set
681      */
682     public void setDependencyConstraints(List<PrerequisiteConstraint> dependencyConstraints) {
683         this.dependencyConstraints = dependencyConstraints;
684     }
685 
686     /**
687      * @return the mustOccurConstraints
688      */
689     public List<MustOccurConstraint> getMustOccurConstraints() {
690         return this.mustOccurConstraints;
691     }
692 
693     /**
694      * @param mustOccurConstraints the mustOccurConstraints to set
695      */
696     public void setMustOccurConstraints(List<MustOccurConstraint> mustOccurConstraints) {
697         this.mustOccurConstraints = mustOccurConstraints;
698     }
699 
700     /**
701      * A simple constraint which store the values for required, min/max length,
702      * and min/max value
703      *
704      * @return the simpleConstraint
705      */
706     public SimpleConstraint getSimpleConstraint() {
707         return this.simpleConstraint;
708     }
709 
710     /**
711      * When a simple constraint is set on this object ALL simple validation
712      * constraints set directly will be overridden - recommended to use this or
713      * the other gets/sets for defining simple constraints, not both
714      *
715      * @param simpleConstraint the simpleConstraint to set
716      */
717     public void setSimpleConstraint(SimpleConstraint simpleConstraint) {
718         this.simpleConstraint = simpleConstraint;
719     }
720 
721     /**
722      * Maximum number of the characters the attribute value is allowed to have.
723      * Used to set the maxLength for supporting controls. Note this can be
724      * smaller or longer than the actual control size
725      *
726      * @return Integer max length
727      */
728     public Integer getMaxLength() {
729         return simpleConstraint.getMaxLength();
730     }
731 
732     /**
733      * Setter for attributes max length
734      *
735      * @param maxLength
736      */
737     public void setMaxLength(Integer maxLength) {
738         simpleConstraint.setMaxLength(maxLength);
739     }
740 
741     /**
742      * @return the minLength
743      */
744     public Integer getMinLength() {
745         return simpleConstraint.getMinLength();
746     }
747 
748     /**
749      * @param minLength the minLength to set
750      */
751     public void setMinLength(Integer minLength) {
752         simpleConstraint.setMinLength(minLength);
753     }
754 
755     /**
756      * @see org.kuali.rice.krad.uif.component.ComponentBase#getRequired()
757      */
758     @Override
759     public Boolean getRequired() {
760         return this.simpleConstraint.getRequired();
761     }
762 
763     /**
764      * @see org.kuali.rice.krad.uif.component.ComponentBase#setRequired(java.lang.Boolean)
765      */
766     @Override
767     public void setRequired(Boolean required) {
768         this.simpleConstraint.setRequired(required);
769     }
770 
771     /**
772      * The exclusiveMin element determines the minimum allowable value for data
773      * entry editing purposes. Value can be an integer or decimal value such as
774      * -.001 or 99.
775      */
776     public String getExclusiveMin() {
777         return simpleConstraint.getExclusiveMin();
778     }
779 
780     /**
781      * @param exclusiveMin the minValue to set
782      */
783     public void setExclusiveMin(String exclusiveMin) {
784         simpleConstraint.setExclusiveMin(exclusiveMin);
785     }
786 
787     /**
788      * The inclusiveMax element determines the maximum allowable value for data
789      * entry editing purposes. Value can be an integer or decimal value such as
790      * -.001 or 99.
791      */
792     public String getInclusiveMax() {
793         return simpleConstraint.getInclusiveMax();
794     }
795 
796     /**
797      * @param inclusiveMax the maxValue to set
798      */
799     public void setInclusiveMax(String inclusiveMax) {
800         simpleConstraint.setInclusiveMax(inclusiveMax);
801     }
802 
803     /**
804      * Setter for the direct inquiry widget
805      *
806      * @param fieldDirectInquiry - field DirectInquiry to set
807      */
808     public void setFieldDirectInquiry(DirectInquiry fieldDirectInquiry) {
809         this.fieldDirectInquiry = fieldDirectInquiry;
810     }
811 
812     /**
813      * DirectInquiry widget for the field
814      *
815      * <p>
816      * The direct inquiry widget will render a button for the field value when
817      * that field is editable. It points to the associated inquiry view for the
818      * field. The inquiry can be configured to point to a certain
819      * <code>InquiryView</code>, or the framework will attempt to associate the
820      * field with a inquiry based on its metadata (in particular its
821      * relationships in the model)
822      * </p>
823      *
824      * @return the <code>DirectInquiry</code> field DirectInquiry
825      */
826     public DirectInquiry getFieldDirectInquiry() {
827         return fieldDirectInquiry;
828     }
829 
830     /**
831      * Attribute query instance configured for this field to dynamically pull information back for
832      * updates other fields or providing messages
833      *
834      * <p>
835      * If field attribute query is not null, associated event script will be generated to trigger the
836      * query from the UI. This will invoke the <code>AttributeQueryService</code> to
837      * execute the query and return an instance of <code>AttributeQueryResult</code> that is then
838      * read by the script to update the UI. Typically used to update informational property values or
839      * other field values
840      * </p>
841      *
842      * @return AttributeQuery instance
843      */
844     public AttributeQuery getFieldAttributeQuery() {
845         return fieldAttributeQuery;
846     }
847 
848     /**
849      * Setter for this fields query
850      *
851      * @param fieldAttributeQuery
852      */
853     public void setFieldAttributeQuery(AttributeQuery fieldAttributeQuery) {
854         this.fieldAttributeQuery = fieldAttributeQuery;
855     }
856 
857     /**
858      * Perform uppercase flag for this field to force input to uppercase.
859      *
860      * <p>
861      * It this flag is set to true the 'text-transform' style on the field will be set to 'uppercase'
862      * which will automatically change any text input into the field to uppercase.
863      * </p>
864      *
865      * @return performUppercase flag
866      */
867     public boolean isPerformUppercase() {
868         return performUppercase;
869     }
870 
871     /**
872      * Setter for this fields performUppercase flag
873      *
874      * @param performUppercase flag
875      */
876     public void setPerformUppercase(boolean performUppercase) {
877         this.performUppercase = performUppercase;
878     }
879 }