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