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.util;
017    
018    import org.apache.commons.lang.StringUtils;
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    import org.kuali.rice.core.api.uif.RemotableAbstractWidget;
022    import org.kuali.rice.core.api.uif.RemotableAttributeField;
023    import org.kuali.rice.core.api.uif.RemotableCheckbox;
024    import org.kuali.rice.core.api.uif.RemotableCheckboxGroup;
025    import org.kuali.rice.core.api.uif.RemotableControlContract;
026    import org.kuali.rice.core.api.uif.RemotableDatepicker;
027    import org.kuali.rice.core.api.uif.RemotableHiddenInput;
028    import org.kuali.rice.core.api.uif.RemotableQuickFinder;
029    import org.kuali.rice.core.api.uif.RemotableRadioButtonGroup;
030    import org.kuali.rice.core.api.uif.RemotableSelect;
031    import org.kuali.rice.core.api.uif.RemotableSelectGroup;
032    import org.kuali.rice.core.api.uif.RemotableTextExpand;
033    import org.kuali.rice.core.api.uif.RemotableTextInput;
034    import org.kuali.rice.core.api.uif.RemotableTextarea;
035    import org.kuali.rice.core.api.util.ConcreteKeyValue;
036    import org.kuali.rice.core.api.util.KeyValue;
037    import org.kuali.rice.krad.datadictionary.validation.constraint.ValidCharactersConstraint;
038    import org.kuali.rice.krad.keyvalues.KeyValuesFinder;
039    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
040    import org.kuali.rice.krad.uif.UifConstants;
041    import org.kuali.rice.krad.uif.container.CollectionGroup;
042    import org.kuali.rice.krad.uif.container.Group;
043    import org.kuali.rice.krad.uif.container.LinkGroup;
044    import org.kuali.rice.krad.uif.container.NavigationGroup;
045    import org.kuali.rice.krad.uif.container.PageGroup;
046    import org.kuali.rice.krad.uif.container.TabGroup;
047    import org.kuali.rice.krad.uif.container.TreeGroup;
048    import org.kuali.rice.krad.uif.control.CheckboxControl;
049    import org.kuali.rice.krad.uif.control.CheckboxGroupControl;
050    import org.kuali.rice.krad.uif.control.Control;
051    import org.kuali.rice.krad.uif.control.FileControl;
052    import org.kuali.rice.krad.uif.control.HiddenControl;
053    import org.kuali.rice.krad.uif.control.MultiValueControl;
054    import org.kuali.rice.krad.uif.control.RadioGroupControl;
055    import org.kuali.rice.krad.uif.control.SelectControl;
056    import org.kuali.rice.krad.uif.control.SizedControl;
057    import org.kuali.rice.krad.uif.control.TextAreaControl;
058    import org.kuali.rice.krad.uif.control.TextControl;
059    import org.kuali.rice.krad.uif.component.Component;
060    import org.kuali.rice.krad.uif.element.Action;
061    import org.kuali.rice.krad.uif.element.Header;
062    import org.kuali.rice.krad.uif.element.Iframe;
063    import org.kuali.rice.krad.uif.element.Image;
064    import org.kuali.rice.krad.uif.element.Label;
065    import org.kuali.rice.krad.uif.element.Message;
066    import org.kuali.rice.krad.uif.element.ValidationMessages;
067    import org.kuali.rice.krad.uif.field.DataField;
068    import org.kuali.rice.krad.uif.field.InputField;
069    import org.kuali.rice.krad.uif.field.MessageField;
070    import org.kuali.rice.krad.uif.field.SpaceField;
071    import org.kuali.rice.krad.uif.field.FieldGroup;
072    import org.kuali.rice.krad.uif.field.GenericField;
073    import org.kuali.rice.krad.uif.field.ImageField;
074    import org.kuali.rice.krad.uif.field.LinkField;
075    import org.kuali.rice.krad.uif.view.View;
076    import org.kuali.rice.krad.uif.widget.LightBox;
077    
078    import java.util.ArrayList;
079    import java.util.HashMap;
080    import java.util.List;
081    import java.util.Map;
082    
083    /**
084     * Factory class for creating new UIF components from their base definitions
085     * in the dictionary
086     *
087     * @author Kuali Rice Team (rice.collab@kuali.org)
088     */
089    public class ComponentFactory {
090    
091        private static Log LOG = LogFactory.getLog(ComponentFactory.class);
092    
093        protected static final String TEXT_CONTROL = "Uif-TextControl";
094        protected static final String CHECKBOX_CONTROL = "Uif-CheckboxControl";
095        protected static final String HIDDEN_CONTROL = "Uif-HiddenControl";
096        protected static final String TEXTAREA_CONTROL = "Uif-TextAreaControl";
097        protected static final String SELECT_CONTROL = "Uif-DropdownControl";
098        protected static final String CHECKBOX_GROUP_CONTROL = "Uif-VerticalCheckboxesControl";
099        protected static final String CHECKBOX_GROUP_CONTROL_HORIZONTAL = "Uif-HorizontalCheckboxesControl";
100        protected static final String RADIO_GROUP_CONTROL = "Uif-VerticalRadioControl";
101        protected static final String RADIO_GROUP_CONTROL_HORIZONTAL = "Uif-HorizontalRadioControl";
102        protected static final String FILE_CONTROL = "Uif-FileControl";
103        protected static final String DATE_CONTROL = "Uif-DateControl";
104        protected static final String USER_CONTROL = "Uif-KimPersonControl";
105        protected static final String GROUP_CONTROL = "Uif-KimGroupControl";
106    
107        protected static final String DATA_FIELD = "Uif-DataField";
108        protected static final String INPUT_FIELD = "Uif-InputField";
109        protected static final String ERRORS_FIELD = "Uif-FieldValidationMessages";
110        protected static final String ACTION = "Uif-PrimaryActionButton";
111        protected static final String ACTION_LINK = "Uif-ActionLink";
112        protected static final String LINK_FIELD = "Uif-LinkField";
113        protected static final String IFRAME = "Uif-Iframe";
114        protected static final String IMAGE_FIELD = "Uif-ImageField";
115        protected static final String SPACE_FIELD = "Uif-SpaceField";
116        protected static final String GENERIC_FIELD = "Uif-CustomTemplateField";
117        protected static final String IMAGE = "Uif-Image";
118        protected static final String LABEL = "Uif-Label";
119        protected static final String MESSAGE = "Uif-Message";
120        protected static final String MESSAGE_FIELD = "Uif-MessageField";
121        protected static final String COLLECTION_GROUPING_FIELD = "Uif-ColGroupingField";
122        protected static final String FIELD_GROUP = "Uif-VerticalFieldGroup";
123        protected static final String HORIZONTAL_FIELD_GROUP = "Uif-HorizontalFieldGroup";
124    
125        protected static final String GROUP = "Uif-GroupBase";
126        protected static final String VERTICAL_BOX_GROUP = "Uif-VerticalBoxGroup";
127        protected static final String HORIZONTAL_BOX_GROUP = "Uif-HorizontalBoxGroup";
128        protected static final String VERTICAL_BOX_SECTION = "Uif-VerticalBoxSection";
129        protected static final String HORIZONTAL_BOX_SECTION = "Uif-HorizontalBoxSection";
130        protected static final String PAGE_GROUP = "Uif-Page";
131        protected static final String GROUP_GRID_LAYOUT = "Uif-GridSection";
132        protected static final String GROUP_BODY_ONLY = "Uif-BoxGroupBase";
133        protected static final String GROUP_GRID_BODY_ONLY = "Uif-GridGroup";
134        protected static final String TAB_GROUP = "Uif-TabSection";
135        protected static final String NAVIGATION_GROUP = "Uif-NavigationGroupBase";
136        protected static final String TREE_GROUP = "Uif-TreeSection";
137        protected static final String LINK_GROUP = "Uif-LinkGroup";
138        protected static final String COLLECTION_GROUP = "Uif-StackedCollectionSection";
139        protected static final String COLLECTION_GROUP_TABLE_LAYOUT = "Uif-TableCollectionSection";
140        protected static final String LIST_GROUP = "Uif-ListCollectionSection";
141    
142        protected static final String HEADER = "Uif-HeaderFieldBase";
143        protected static final String FOOTER = "Uif-FooterBase";
144        protected static final String FOOTER_SAVECLOSECANCEL = "Uif-FormPageFooter";
145    
146        protected static final String CONSTRAINT_MESSAGE = "Uif-ConstraintMessage";
147        protected static final String INSTRUCTIONAL_MESSAGE = "Uif-InstructionalMessage";
148        protected static final String HELP_ACTION = "Uif-HelpAction";
149        protected static final String IMAGE_CAPTION_HEADER = "Uif-ImageCaptionHeader";
150        protected static final String IMAGE_CUTLINE_MESSAGE = "Uif-ImageCutineMessage";
151    
152        protected static final String LIGHTBOX = "Uif-LightBox";
153    
154        private static Map<String, Component> cache = new HashMap<String, Component>();
155    
156        /**
157         * Gets a fresh copy of the component by the id passed in which used to look up the component in
158         * the view index, then retrieve a new instance with initial state configured using the factory id
159         *
160         * @param id - id for the component in the view index
161         * @return Component new instance
162         */
163        public static Component getNewInstanceForRefresh(View view, String id) {
164            Component component = null;
165            Component origComponent = view.getViewIndex().getComponentById(id);
166    
167            if (origComponent == null) {
168                throw new RuntimeException(id + " not found in view index try setting p:forceSessionPersistence=\"true\" in xml");
169            }
170    
171            if (view.getViewIndex().getInitialComponentStates().containsKey(origComponent.getBaseId())) {
172                component = view.getViewIndex().getInitialComponentStates().get(origComponent.getBaseId());
173                LOG.debug("getNewInstanceForRefresh: id '" + id + "' was found in initialStates");
174            } else {
175                component = (Component) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryObject(
176                        origComponent.getBaseId());
177                LOG.debug("getNewInstanceForRefresh: id '"
178                        + id
179                        + "' was NOT found in initialStates. New one fetched from DD");
180            }
181    
182            if (component != null) {
183                component = ComponentUtils.copyObject(component);
184                component.setId(origComponent.getBaseId());
185            }
186    
187            return component;
188        }
189    
190        /**
191         * Returns a new <code>Component</code> instance for the given bean id from the spring factory
192         *
193         * @param beanId - id of the bean definition
194         * @return new component instance or null if no such component definition was found
195         */
196        public static Component getNewComponentInstance(String beanId) {
197            Component component = null;
198            if (cache.containsKey(beanId)) {
199                component = ComponentUtils.copy(cache.get(beanId));
200            } else {
201                component = (Component) KRADServiceLocatorWeb.getDataDictionaryService().getDictionaryObject(beanId);
202    
203                // clear id before returning so duplicates do not occur
204                component.setId(null);
205                component.setBaseId(null);
206    
207                // populate property expressions from expression graph
208                ExpressionUtils.populatePropertyExpressionsFromGraph(component, true);
209    
210                // add to cache
211                // TODO: is this copy needed here? A copy is done when a request is made
212                cache.put(beanId, ComponentUtils.copy(component));
213            }
214    
215            return component;
216        }
217    
218        /**
219         * Retrieves a new Text control instance from Spring (initialized by the bean definition
220         * with the given id)
221         *
222         * @return TextControl
223         */
224        public static TextControl getTextControl() {
225            return (TextControl) getNewComponentInstance(TEXT_CONTROL);
226        }
227    
228        /**
229         * Retrieves a new Text area control instance from Spring (initialized by the bean definition
230         * with the given id)
231         *
232         * @return TextAreaControl
233         */
234        public static TextAreaControl getTextAreaControl() {
235            return (TextAreaControl) getNewComponentInstance(TEXTAREA_CONTROL);
236        }
237    
238        /**
239         * Retrieves a new checkbox control instance from Spring (initialized by the bean definition
240         * with the given id)
241         *
242         * @return CheckboxControl
243         */
244        public static CheckboxControl getCheckboxControl() {
245            return (CheckboxControl) getNewComponentInstance(CHECKBOX_CONTROL);
246        }
247    
248        /**
249         * Retrieves a new hidden control instance from Spring (initialized by the bean definition
250         * with the given id)
251         *
252         * @return HiddenControl
253         */
254        public static HiddenControl getHiddenControl() {
255            return (HiddenControl) getNewComponentInstance(HIDDEN_CONTROL);
256        }
257    
258        /**
259         * Retrieves a new select control instance from Spring (initialized by the bean definition
260         * with the given id)
261         *
262         * @return SelectControl
263         */
264        public static SelectControl getSelectControl() {
265            return (SelectControl) getNewComponentInstance(SELECT_CONTROL);
266        }
267    
268        /**
269         * Retrieves a new checkbox group control instance from Spring (initialized by the bean definition
270         * with the given id)
271         *
272         * <p>
273         * Return checkbox group set for vertical orientation
274         * </p>
275         *
276         * @return CheckboxGroupControl
277         */
278        public static CheckboxGroupControl getCheckboxGroupControl() {
279            return (CheckboxGroupControl) getNewComponentInstance(CHECKBOX_GROUP_CONTROL);
280        }
281    
282        /**
283         * Retrieves a new checkbox group control instance from Spring (initialized by the bean definition
284         * with the given id)
285         *
286         * <p>
287         * Return checkbox group set for horizontal orientation
288         * </p>
289         *
290         * @return CheckboxGroupControl
291         */
292        public static CheckboxGroupControl getCheckboxGroupControlHorizontal() {
293            return (CheckboxGroupControl) getNewComponentInstance(CHECKBOX_GROUP_CONTROL_HORIZONTAL);
294        }
295    
296        /**
297         * Retrieves a new radio group control instance from Spring (initialized by the bean definition
298         * with the given id)
299         *
300         * <p>
301         * Return radio group set for vertical orientation
302         * </p>
303         *
304         * @return RadioGroupControl
305         */
306        public static RadioGroupControl getRadioGroupControl() {
307            return (RadioGroupControl) getNewComponentInstance(RADIO_GROUP_CONTROL);
308        }
309    
310        /**
311         * Retrieves a new radio group control instance from Spring (initialized by the bean definition
312         * with the given id)
313         *
314         * <p>
315         * Return radio group set for horizontal orientation
316         * </p>
317         *
318         * @return RadioGroupControl
319         */
320        public static RadioGroupControl getRadioGroupControlHorizontal() {
321            return (RadioGroupControl) getNewComponentInstance(RADIO_GROUP_CONTROL_HORIZONTAL);
322        }
323    
324        /**
325         * Retrieves a new file control instance from Spring (initialized by the bean definition
326         * with the given id)
327         *
328         * @return FileControl
329         */
330        public static FileControl getFileControl() {
331            return (FileControl) getNewComponentInstance(FILE_CONTROL);
332        }
333    
334        /**
335         * Retrieves a new text control instance from Spring (initialized by the bean definition
336         * with the given id) configured for a date (enabled data picker)
337         *
338         * @return TextControl
339         */
340        public static TextControl getDateControl() {
341            return (TextControl) getNewComponentInstance(DATE_CONTROL);
342        }
343    
344        /**
345         * Retrieves a new text control instance from Spring (initialized by the bean definition
346         * with the given id) configured for KIM user input
347         *
348         * @return TextControl
349         */
350        public static TextControl getUserControl() {
351            return (TextControl) getNewComponentInstance(USER_CONTROL);
352        }
353    
354        /**
355         * Retrieves a new text control instance from Spring (initialized by the bean definition
356         * with the given id) configured for KIM group input
357         *
358         * @return TextControl
359         */
360        public static TextControl getGroupControl() {
361            return (TextControl) getNewComponentInstance(GROUP_CONTROL);
362        }
363    
364        /**
365         * Retrieves a new data field instance from Spring (initialized by the bean definition
366         * with the given id)
367         *
368         * @return DataField
369         */
370        public static DataField getDataField() {
371            return (DataField) getNewComponentInstance(DATA_FIELD);
372        }
373    
374        /**
375         * Retrieves a new data field instance from Spring (initialized by the bean definition
376         * with the given id) and sets the property name and label to the given parameters
377         *
378         * @param propertyName - name of the property the data field should bind to
379         * @param label - label for the field
380         * @return DataField
381         */
382        public static DataField getDataField(String propertyName, String label) {
383            DataField field = (DataField) getNewComponentInstance(DATA_FIELD);
384    
385            field.setPropertyName(propertyName);
386            field.setLabel(label);
387    
388            return field;
389        }
390    
391        /**
392         * Retrieves a new input field instance from Spring (initialized by the bean definition
393         * with the given id)
394         *
395         * @return InputField
396         */
397        public static InputField getInputField() {
398            return (InputField) getNewComponentInstance(INPUT_FIELD);
399        }
400    
401        /**
402         * Retrieves a new input field instance from Spring (initialized by the bean definition
403         * with the given id) and sets the property name and label to the given parameters
404         *
405         * @param propertyName - name of the property the input field should bind to
406         * @param label - label for the field
407         * @return InputField
408         */
409        public static InputField getInputField(String propertyName, String label) {
410            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
411    
412            field.setPropertyName(propertyName);
413            field.setLabel(label);
414    
415            return field;
416        }
417    
418        /**
419         * Retrieves a new input field instance from Spring (initialized by the bean definition
420         * with the given id) and sets the property name, control, and label to the given parameters
421         *
422         * @param propertyName - name of the property the input field should bind to
423         * @param label - label for the field
424         * @param controlType - enum that identifies the type of control to create for the input field
425         * @return InputField
426         */
427        public static InputField getInputField(String propertyName, String label, UifConstants.ControlType controlType) {
428            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
429    
430            field.setPropertyName(propertyName);
431            field.setLabel(label);
432            field.setControl(getControl(controlType));
433    
434            return field;
435        }
436    
437        /**
438         * Retrieves a new input field instance from Spring (initialized by the bean definition
439         * with the given id) and sets the property name, control, defaultValue, and label to the given parameters
440         *
441         * @param propertyName - name of the property the input field should bind to
442         * @param label - label for the field
443         * @param controlType - enum that identifies the type of control to create for the input field
444         * @param defaultValue - default value for the property backing the input field
445         * @return InputField
446         */
447        public static InputField getInputField(String propertyName, String label, UifConstants.ControlType controlType,
448                String defaultValue) {
449            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
450    
451            field.setPropertyName(propertyName);
452            field.setLabel(label);
453            field.setControl(getControl(controlType));
454            field.setDefaultValue(defaultValue);
455    
456            return field;
457        }
458    
459        /**
460         * Retrieves a new input field instance from Spring (initialized by the bean definition
461         * with the given id) and sets the property name, control, options finder, and label to the given parameters
462         *
463         * @param propertyName - name of the property the input field should bind to
464         * @param label - label for the field
465         * @param controlType - enum that identifies the type of control to create for the input field
466         * @param optionsFinderClass - class that will provide options for the control (assume control type is multi-value)
467         * @return InputField
468         */
469        public static InputField getInputField(String propertyName, String label, UifConstants.ControlType controlType,
470                Class<? extends KeyValuesFinder> optionsFinderClass) {
471            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
472    
473            field.setPropertyName(propertyName);
474            field.setLabel(label);
475            field.setControl(getControl(controlType));
476            field.setOptionsFinderClass(optionsFinderClass);
477    
478            return field;
479        }
480    
481        /**
482         * Retrieves a new input field instance from Spring (initialized by the bean definition
483         * with the given id) and sets the property name, control, options, and label to the given parameters
484         *
485         * @param propertyName - name of the property the input field should bind to
486         * @param label - label for the field
487         * @param controlType - enum that identifies the type of control to create for the input field
488         * @param options - list of key value objects to set as the controls options
489         * @return InputField
490         */
491        public static InputField getInputField(String propertyName, String label, UifConstants.ControlType controlType,
492                List<KeyValue> options) {
493            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
494    
495            field.setPropertyName(propertyName);
496            field.setLabel(label);
497    
498            Control control = getControl(controlType);
499            if (control instanceof MultiValueControl) {
500                ((MultiValueControl) control).setOptions(options);
501            } else {
502                throw new RuntimeException("Control is not instance of multi-value control, cannot set options");
503            }
504    
505            return field;
506        }
507    
508        /**
509         * Retrieves a new input field instance from Spring (initialized by the bean definition
510         * with the given id) and sets the property name, control, size, min and max length,
511         * and label to the given parameters
512         *
513         * @param propertyName - name of the property the input field should bind to
514         * @param label - label for the field
515         * @param controlType - enum that identifies the type of control to create for the input field
516         * @param size - size for the control
517         * @param maxLength - max length for the field's value (also used for the control)
518         * @param minLength - min length for the field's value (also used for the control)
519         * @return InputField
520         */
521        public static InputField getInputField(String propertyName, String label, UifConstants.ControlType controlType,
522                int size, int maxLength, int minLength) {
523            InputField field = (InputField) getNewComponentInstance(INPUT_FIELD);
524    
525            field.setPropertyName(propertyName);
526            field.setLabel(label);
527    
528            Control control = getControl(controlType);
529            if (control instanceof SizedControl) {
530                ((SizedControl) control).setSize(size);
531            } else {
532                throw new RuntimeException("Control does not support the size property");
533            }
534    
535            field.setMaxLength(maxLength);
536            field.setMinLength(minLength);
537    
538            return field;
539        }
540    
541        /**
542         * Builds a new <code>InputField</code> from the properties set on the
543         * given <code>RemotableAttributeField</code>
544         *
545         * <p>
546         * Note the returned InputField will not be initialized yet. Its state will be that of the initial
547         * object returned from the UIF dictionary with the properties set from the remotable attribute field, thus it
548         * is really just a more configuration complete field
549         * </p>
550         *
551         * @return AttributeField instance built from remotable field
552         */
553        public static InputField translateRemotableField(RemotableAttributeField remotableField) {
554            InputField inputField = getInputField();
555    
556            inputField.setPropertyName(remotableField.getName());
557            inputField.setShortLabel(remotableField.getShortLabel());
558            inputField.setLabel(remotableField.getLongLabel());
559            inputField.setConstraintText(remotableField.getConstraintText());
560            inputField.setUppercaseValue(remotableField.isForceUpperCase());
561            inputField.setMinLength(remotableField.getMinLength());
562            inputField.setMaxLength(remotableField.getMaxLength());
563    
564            // why are exclusive min and max strings?
565            if (remotableField.getMinValue() != null) {
566                inputField.setExclusiveMin(remotableField.getMinValue().toString());
567            }
568            if (remotableField.getMaxValue() != null) {
569                inputField.setInclusiveMax(remotableField.getMaxValue().toString());
570            }
571            inputField.setRequired(remotableField.isRequired());
572    
573            if ((remotableField.getDefaultValues() != null) && !remotableField.getDefaultValues().isEmpty()) {
574                inputField.setDefaultValue(remotableField.getDefaultValues().iterator().next());
575            }
576    
577            if (StringUtils.isNotBlank(remotableField.getRegexConstraint())) {
578                ValidCharactersConstraint constraint = new ValidCharactersConstraint();
579                constraint.setValue(remotableField.getRegexConstraint());
580                inputField.setValidCharactersConstraint(constraint);
581                // TODO: how to deal with remotable field regexContraintMsg?
582            }
583    
584            RemotableDatepicker remotableDatepicker = null;
585            RemotableTextExpand remotableTextExpand = null;
586            RemotableQuickFinder remotableQuickFinder = null;
587            for (RemotableAbstractWidget remoteWidget : remotableField.getWidgets()) {
588                if (remoteWidget instanceof RemotableDatepicker) {
589                    remotableDatepicker = (RemotableDatepicker) remoteWidget;
590                } else if (remoteWidget instanceof RemotableTextExpand) {
591                    remotableTextExpand = (RemotableTextExpand) remoteWidget;
592                } else if (remoteWidget instanceof RemotableQuickFinder) {
593                    remotableQuickFinder = (RemotableQuickFinder) remoteWidget;
594                }
595            }
596    
597            if (remotableQuickFinder != null) {
598                inputField.getQuickfinder().setBaseLookupUrl(remotableQuickFinder.getBaseLookupUrl());
599                inputField.getQuickfinder().setDataObjectClassName(remotableQuickFinder.getDataObjectClass());
600                inputField.getQuickfinder().setLookupParameters(remotableQuickFinder.getLookupParameters());
601                inputField.getQuickfinder().setFieldConversions(remotableQuickFinder.getFieldConversions());
602            }
603    
604            if (remotableField.getControl() != null) {
605                Control control = null;
606    
607                RemotableControlContract remotableControl = remotableField.getControl();
608                if (remotableControl instanceof RemotableHiddenInput) {
609                    control = getHiddenControl();
610                } else if (remotableControl instanceof RemotableRadioButtonGroup) {
611                    RemotableRadioButtonGroup remotableRadioButtonGroup = (RemotableRadioButtonGroup) remotableControl;
612                    control = getRadioGroupControl();
613                    ((RadioGroupControl) control).setOptions(buildKeyValuePairs(remotableRadioButtonGroup.getKeyLabels()));
614                } else if (remotableControl instanceof RemotableSelect) {
615                    RemotableSelect remotableSelect = (RemotableSelect) remotableControl;
616                    control = getSelectControl();
617    
618                    Map<String, String> keyLabels = new HashMap<String, String>();
619                    if ((remotableSelect.getGroups() != null) && (!remotableSelect.getGroups().isEmpty())) {
620                        for (RemotableSelectGroup remotableSelectGroup : remotableSelect.getGroups()) {
621                            keyLabels.putAll(remotableSelectGroup.getKeyLabels());
622                        }
623                    } else {
624                        keyLabels = remotableSelect.getKeyLabels();
625                    }
626    
627                    ((SelectControl) control).setOptions(buildKeyValuePairs(keyLabels));
628                    if (remotableSelect.getSize() != null) {
629                        ((SelectControl) control).setSize(remotableSelect.getSize());
630                    }
631                    ((SelectControl) control).setMultiple(remotableSelect.isMultiple());
632                } else if (remotableControl instanceof RemotableCheckboxGroup) {
633                    RemotableCheckboxGroup remotableCheckboxGroup = (RemotableCheckboxGroup) remotableControl;
634                    control = getCheckboxGroupControl();
635                    ((CheckboxGroupControl) control).setOptions(buildKeyValuePairs(remotableCheckboxGroup.getKeyLabels()));
636                } else if (remotableControl instanceof RemotableCheckbox) {
637                    control = getCheckboxControl();
638                } else if (remotableControl instanceof RemotableTextarea) {
639                    RemotableTextarea remotableTextarea = (RemotableTextarea) remotableControl;
640                    control = getTextAreaControl();
641    
642                    if (remotableTextExpand != null) {
643                        ((TextAreaControl) control).setTextExpand(true);
644                    }
645                    ((TextAreaControl) control).setRows(remotableTextarea.getRows());
646                    ((TextAreaControl) control).setCols(remotableTextarea.getCols());
647                    ((TextAreaControl) control).setWatermarkText(remotableTextarea.getWatermark());
648    
649                } else if (remotableControl instanceof RemotableTextInput) {
650                    RemotableTextInput remotableTextInput = (RemotableTextInput) remotableControl;
651    
652                    if (remotableDatepicker != null) {
653                        control = getDateControl();
654                    } else {
655                        control = getTextControl();
656                    }
657    
658                    if (remotableTextExpand != null) {
659                        ((TextAreaControl) control).setTextExpand(true);
660                    }
661                    ((TextControl) control).setSize(remotableTextInput.getSize());
662                    ((TextControl) control).setWatermarkText(remotableTextInput.getWatermark());
663                }
664    
665                inputField.setControl(control);
666            }
667    
668            return inputField;
669        }
670    
671        /**
672         * For each remotable field in the given list creates a new {@link org.kuali.rice.krad.uif.field.InputField}
673         * instance and sets the
674         * corresponding properties from the remotable instance
675         *
676         * @param remotableFields - list of remotable fields to translate
677         * @return List<AttributeField> list of attribute fields built from the remotable field properties
678         */
679        public static List<InputField> translateRemotableFields(List<RemotableAttributeField> remotableFields) {
680            List<InputField> inputFields = new ArrayList<InputField>();
681    
682            for (RemotableAttributeField remotableField : remotableFields) {
683                inputFields.add(translateRemotableField(remotableField));
684            }
685    
686            return inputFields;
687        }
688    
689        /**
690         * For each option in the given list, create a new {@link org.kuali.rice.core.api.util.KeyValue} instance
691         *
692         * @param optionsMap - list of options
693         * @return List<KeyValue> list of key values built from the list of options
694         */
695        protected static List<KeyValue> buildKeyValuePairs(Map<String, String> optionsMap) {
696            List<KeyValue> options = new ArrayList<KeyValue>();
697    
698            for (Map.Entry<String, String> optionEntry : optionsMap.entrySet()) {
699                KeyValue keyValue = new ConcreteKeyValue(optionEntry.getKey(), optionEntry.getValue());
700                options.add(keyValue);
701            }
702    
703            return options;
704        }
705    
706        /**
707         * Gets the control
708         *
709         * @param controlType
710         * @return Control the control based on the control type
711         */
712        protected static Control getControl(UifConstants.ControlType controlType) {
713            Control control = null;
714            switch (controlType) {
715                case CHECKBOX:
716                    control = getCheckboxControl();
717                    break;
718                case CHECKBOXGROUP:
719                    control = getCheckboxGroupControl();
720                    break;
721                case FILE:
722                    control = getFileControl();
723                    break;
724                case GROUP:
725                    control = getGroupControl();
726                    break;
727                case HIDDEN:
728                    control = getHiddenControl();
729                    break;
730                case RADIOGROUP:
731                    control = getRadioGroupControl();
732                    break;
733                case SELECT:
734                    control = getSelectControl();
735                    break;
736                case TEXTAREA:
737                    control = getTextAreaControl();
738                    break;
739                case TEXT:
740                    control = getTextControl();
741                    break;
742                case USER:
743                    control = getUserControl();
744                    break;
745            }
746    
747            return control;
748        }
749    
750        /**
751         * Gets the errors field
752         *
753         * @return ValidationMessages errors field
754         */
755        public static ValidationMessages getErrorsField() {
756            return (ValidationMessages) getNewComponentInstance(ERRORS_FIELD);
757        }
758    
759        /**
760         * Gets the action
761         *
762         * @return Action action
763         */
764        public static Action getAction() {
765            return (Action) getNewComponentInstance(ACTION);
766        }
767    
768        /**
769         * Gets the action link
770         *
771         * @return Action action link
772         */
773        public static Action getActionLink() {
774            return (Action) getNewComponentInstance(ACTION_LINK);
775        }
776    
777        /**
778         * Gets the link field
779         *
780         * @return LinkField link field
781         */
782        public static LinkField getLinkField() {
783            return (LinkField) getNewComponentInstance(LINK_FIELD);
784        }
785    
786        /**
787         * Gets the iframe
788         *
789         * @return Iframe iframe
790         */
791        public static Iframe getIframe() {
792            return (Iframe) getNewComponentInstance(IFRAME);
793        }
794    
795        /**
796         * Gets the image field
797         *
798         * @return ImageField image field
799         */
800        public static ImageField getImageField() {
801            return (ImageField) getNewComponentInstance(IMAGE_FIELD);
802        }
803    
804        /**
805         * Gets the image component
806         *
807         * @return ImageField image field
808         */
809        public static Image getImage() {
810            return (Image) getNewComponentInstance(IMAGE);
811        }
812    
813        /**
814         * Gets the space field
815         *
816         * @return SpaceField space field
817         */
818        public static SpaceField getSpaceField() {
819            return (SpaceField) getNewComponentInstance(SPACE_FIELD);
820        }
821    
822        /**
823         * Gets the generic field
824         *
825         * @return GenericField generic field
826         */
827        public static GenericField getGenericField() {
828            return (GenericField) getNewComponentInstance(GENERIC_FIELD);
829        }
830    
831        /**
832         * Gets the label
833         *
834         * @return Label label
835         */
836        public static Label getLabel() {
837            return (Label) getNewComponentInstance(LABEL);
838        }
839    
840        /**
841         * Gets the message
842         *
843         * @return Message message
844         */
845        public static Message getMessage() {
846            return (Message) getNewComponentInstance(MESSAGE);
847        }
848    
849        /**
850         * Gets the message field
851         *
852         * @return MessageField message field
853         */
854        public static MessageField getMessageField() {
855            return (MessageField) getNewComponentInstance(MESSAGE_FIELD);
856        }
857    
858        /**
859         * Gets the collection grouping field
860         *
861         * @return MessageField message field
862         */
863        public static MessageField getColGroupingField() {
864            return (MessageField) getNewComponentInstance(COLLECTION_GROUPING_FIELD);
865        }
866    
867        /**
868         * Gets the field group
869         *
870         * @return FieldGroup field group
871         */
872        public static FieldGroup getFieldGroup() {
873            return (FieldGroup) getNewComponentInstance(FIELD_GROUP);
874        }
875    
876        /**
877         * Gets the horizontal field group
878         *
879         * @return FieldGroup horizontal field group
880         */
881        public static FieldGroup getHorizontalFieldGroup() {
882            return (FieldGroup) getNewComponentInstance(HORIZONTAL_FIELD_GROUP);
883        }
884    
885        /**
886         * Gets the group
887         *
888         * @return Group group
889         */
890        public static Group getGroup() {
891            return (Group) getNewComponentInstance(GROUP);
892        }
893    
894        /**
895         * Gets the vertical box group
896         *
897         * @return Group group
898         */
899        public static Group getVerticalBoxGroup() {
900            return (Group) getNewComponentInstance(VERTICAL_BOX_GROUP);
901        }
902    
903        /**
904         * Gets the horizontal box group
905         *
906         * @return Group group
907         */
908        public static Group getHorizontalBoxGroup() {
909            return (Group) getNewComponentInstance(HORIZONTAL_BOX_GROUP);
910        }
911    
912        /**
913         * Gets the vertical box section
914         *
915         * @return Group group
916         */
917        public static Group getVerticalBoxSection() {
918            return (Group) getNewComponentInstance(VERTICAL_BOX_SECTION);
919        }
920    
921        /**
922         * Gets the horizontal box section
923         *
924         * @return Group group
925         */
926        public static Group getHorizontalBoxSection() {
927            return (Group) getNewComponentInstance(HORIZONTAL_BOX_SECTION);
928        }
929    
930        /**
931         * Gets the page group
932         *
933         * @return PageGroup page group
934         */
935        public static PageGroup getPageGroup() {
936            return (PageGroup) getNewComponentInstance(PAGE_GROUP);
937        }
938    
939        /**
940         * Gets the group grid layout
941         *
942         * @return Group group grid layout
943         */
944        public static Group getGroupGridLayout() {
945            return (Group) getNewComponentInstance(GROUP_GRID_LAYOUT);
946        }
947    
948        /**
949         * Gets the group body only
950         *
951         * @return Group group body only
952         */
953        public static Group getGroupBodyOnly() {
954            return (Group) getNewComponentInstance(GROUP_BODY_ONLY);
955        }
956    
957        /**
958         * Gets the group grid body only
959         *
960         * @return Group group grid body only
961         */
962        public static Group getGroupGridBodyOnly() {
963            return (Group) getNewComponentInstance(GROUP_GRID_BODY_ONLY);
964        }
965    
966        /**
967         * Gets the tab group
968         *
969         * @return TabGroup tab group
970         */
971        public static TabGroup getTabGroup() {
972            return (TabGroup) getNewComponentInstance(TAB_GROUP);
973        }
974    
975        /**
976         * Gets the navigation group
977         *
978         * @return NavigationGroup navigation group
979         */
980        public static NavigationGroup getNavigationGroup() {
981            return (NavigationGroup) getNewComponentInstance(NAVIGATION_GROUP);
982        }
983    
984        /**
985         * Gets the tree group
986         *
987         * @return TreeGroup tree group
988         */
989        public static TreeGroup getTreeGroup() {
990            return (TreeGroup) getNewComponentInstance(TREE_GROUP);
991        }
992    
993        /**
994         * Gets the link group
995         *
996         * @return LinkGroup link group
997         */
998        public static LinkGroup getLinkGroup() {
999            return (LinkGroup) getNewComponentInstance(LINK_GROUP);
1000        }
1001    
1002        /**
1003         * Gets the collection group
1004         *
1005         * @return CollectionGroup collection group
1006         */
1007        public static CollectionGroup getCollectionGroup() {
1008            return (CollectionGroup) getNewComponentInstance(COLLECTION_GROUP);
1009        }
1010    
1011        /**
1012         * Gets the collection group table layout
1013         *
1014         * @return CollectionGroup collection group table layout
1015         */
1016        public static CollectionGroup getCollectionGroupTableLayout() {
1017            return (CollectionGroup) getNewComponentInstance(COLLECTION_GROUP_TABLE_LAYOUT);
1018        }
1019    
1020        /**
1021         * Gets the list group
1022         *
1023         * @return CollectionGroup list group
1024         */
1025        public static CollectionGroup getListGroup() {
1026            return (CollectionGroup) getNewComponentInstance(LIST_GROUP);
1027        }
1028    
1029        /**
1030         * Gets the header
1031         *
1032         * @return Header header
1033         */
1034        public static Header getHeader() {
1035            return (Header) getNewComponentInstance(HEADER);
1036        }
1037    
1038        /**
1039         * Gets the footer
1040         *
1041         * @return Group footer
1042         */
1043        public static Group getFooter() {
1044            return (Group) getNewComponentInstance(FOOTER);
1045        }
1046    
1047        /**
1048         * Gets the footer save/close/cancel
1049         *
1050         * @return Group footer save/close/cancel
1051         */
1052        public static Group getFooterSaveCloseCancel() {
1053            return (Group) getNewComponentInstance(FOOTER_SAVECLOSECANCEL);
1054        }
1055    
1056        /**
1057         * Gets the default action component configured for help
1058         *
1059         * @return Action for help display
1060         */
1061        public static Action getHelpAction() {
1062            return (Action) getNewComponentInstance(HELP_ACTION);
1063        }
1064    
1065        /**
1066         * Gets the default constraint message configuration
1067         *
1068         * @return Message component for constraint messages
1069         */
1070        public static Message getConstraintMessage() {
1071            return (Message) getNewComponentInstance(CONSTRAINT_MESSAGE);
1072        }
1073    
1074        /**
1075         * Gets the default instructional message configuration
1076         *
1077         * @return Message component for instructional messages
1078         */
1079        public static Message getInstructionalMessage() {
1080            return (Message) getNewComponentInstance(INSTRUCTIONAL_MESSAGE);
1081        }
1082    
1083        /**
1084         * Gets the default image caption header configuration
1085         *
1086         * @return Header component for image caption headers
1087         */
1088        public static Header getImageCaptionHeader() {
1089            return (Header) getNewComponentInstance(IMAGE_CAPTION_HEADER);
1090        }
1091    
1092        /**
1093         * Gets the default image cutline message configuration
1094         *
1095         * @return Message component for image cutlines messages
1096         */
1097        public static Message getImageCutlineMessage() {
1098            return (Message) getNewComponentInstance(IMAGE_CUTLINE_MESSAGE);
1099        }
1100    
1101        /**
1102         * Gets the default lightbox configuration
1103         *
1104         * @return Lightbox component
1105         */
1106        public static LightBox getLightBox() {
1107            return (LightBox) getNewComponentInstance(LIGHTBOX);
1108        }
1109    }