org.bonitasoft.forms.client.view.widget.FormFieldWidget.java Source code

Java tutorial

Introduction

Here is the source code for org.bonitasoft.forms.client.view.widget.FormFieldWidget.java

Source

/**
 * Copyright (C) 2009 BonitaSoft S.A.
 * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2.0 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.bonitasoft.forms.client.view.widget;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.bonitasoft.forms.client.model.FormFieldValue;
import org.bonitasoft.forms.client.model.ReducedFormFieldAvailableValue;
import org.bonitasoft.forms.client.model.ReducedFormSubtitle.SubTitlePosition;
import org.bonitasoft.forms.client.model.ReducedFormWidget;
import org.bonitasoft.forms.client.model.ReducedFormWidget.ItemPosition;
import org.bonitasoft.forms.client.model.WidgetType;
import org.bonitasoft.forms.client.view.SupportedFieldTypes;
import org.bonitasoft.forms.client.view.common.URLUtils;

import com.google.gwt.dom.client.Document;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.HasChangeHandlers;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Focusable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestBox.DefaultSuggestionDisplay;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.datepicker.client.DateBox;
import com.google.gwt.user.datepicker.client.DateBox.DefaultFormat;
import com.google.gwt.user.datepicker.client.DateBox.Format;

/**
 * Generic form flow field widget
 *
 * @author Anthony Birembaut
 */
@SuppressWarnings("rawtypes")
public class FormFieldWidget extends Composite
        implements HasChangeHandlers, ChangeHandler, HasClickHandlers, ClickHandler, HasValueChangeHandlers,
        ValueChangeHandler, HasSelectionHandlers<Suggestion>, SelectionHandler<Suggestion> {

    /**
     * the flow panel used to display the data field and its decorations
     */
    protected FlowPanel flowPanel;

    /**
     * the container panel used to display the data field and its label
     */
    protected FlowPanel fieldContainer;

    /**
     * the flow panel used to display the tooltip icon
     */
    protected FlowPanel theOuterToolTipPanel;

    /**
     * The widget Id
     */
    protected String widgetId;

    /**
     * widget field type
     */
    protected WidgetType widgetType;

    /**
     * the value type
     */
    protected String valueType;

    /**
     * the field ouput type
     */
    protected String fieldOutputType;

    /**
     * the widget label
     */
    private LabelWidget labelWidget;

    /**
     * the widget field
     */
    protected Widget fieldWidget;

    /**
     * Date format for date picker
     */
    protected DateTimeFormat displayFormat;

    /**
     * mandatory form field symbol
     */
    protected String mandatoryFieldSymbol;

    /**
     * mandatory form field symbol classes
     */
    protected String mandatoryFieldClasses;

    /**
     * the display format
     */
    protected String displayFormatPattern;

    /**
     * The formID retrieved from the request as a String
     */
    protected String formID = null;

    /**
     * The URL contextmap retrieved from the History taken
     */
    protected Map<String, Object> contextMap;

    /**
     * Click handlers registered for the widget
     */
    protected List<ClickHandler> clickHandlers;

    /**
     * Change handlers registered for the widget
     */
    protected List<ChangeHandler> changeHandlers;

    /**
     * value change handlers registered for the widget
     */
    protected Map<String, ValueChangeHandler<Serializable>> valueChangeHandlers;

    /**
     * selection handlers registered for the widget
     */
    protected List<SelectionHandler<Suggestion>> selectionHandlers;

    /**
     * Map of suggestions for the suggestion box
     */
    protected TreeMap<String, String> suggestionsMap;

    /**
     * Constructor
     *
     * @param widgetData
     *        the widget data object
     * @param contextMap
     * @param mandatoryFieldSymbol
     * @param mandatoryFieldClasses
     */
    public FormFieldWidget(final ReducedFormWidget widgetData, final Map<String, Object> contextMap,
            final String mandatoryFieldSymbol, final String mandatoryFieldClasses) {
        this(widgetData, widgetData.getInitialFieldValue(), contextMap, mandatoryFieldSymbol,
                mandatoryFieldClasses);
    }

    /**
     * Constructor
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     * @param contextMap
     * @param mandatoryFieldSymbol
     * @param mandatoryFieldClasses
     */
    public FormFieldWidget(final ReducedFormWidget widgetData, final FormFieldValue fieldValue,
            final Map<String, Object> contextMap, final String mandatoryFieldSymbol,
            final String mandatoryFieldClasses) {
        if (contextMap.get(URLUtils.FORM_ID) != null) {
            formID = (String) contextMap.get(URLUtils.FORM_ID);
        }
        this.contextMap = contextMap;
        this.mandatoryFieldSymbol = mandatoryFieldSymbol;
        this.mandatoryFieldClasses = mandatoryFieldClasses;

        init(widgetData, fieldValue);

        initWidget(flowPanel);

        createWidget(widgetData, fieldValue);
    }

    /**
     * Initialize the widget attributes
     *
     * @param widgetData
     * @param fieldValue
     */
    protected void init(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {

        fieldContainer = new FlowPanel();

        flowPanel = new FlowPanel();

        widgetId = widgetData.getId();

        widgetType = widgetData.getType();

        displayFormatPattern = widgetData.getDisplayFormat();

        valueType = fieldValue.getValueType();

        fieldOutputType = widgetData.getFieldOutputType();
    }

    /**
     * Create a {@link TextBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link TextBox}
     */
    @SuppressWarnings("unchecked")
    protected TextBox createTextBox(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final TextBox textBox = new TextBox();
        textBox.addChangeHandler(this);
        textBox.addValueChangeHandler(this);
        if (widgetData.getMaxLength() != 0) {
            textBox.setMaxLength(widgetData.getMaxLength());
        }
        if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(valueType)) {
            textBox.setValue(getDateAsText(fieldValue));
        } else {
            textBox.setValue(getStringValue(fieldValue));
        }
        textBox.setEnabled(!widgetData.isReadOnly());
        return textBox;
    }

    /**
     * Create a {@link TextArea} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link TextArea}
     */
    @SuppressWarnings("unchecked")
    protected TextArea createTextArea(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final TextArea textArea = new TextArea();
        textArea.addChangeHandler(this);
        textArea.addValueChangeHandler(this);
        if (widgetData.getMaxLength() != 0) {
            textArea.setCharacterWidth(widgetData.getMaxLength());
        }
        if (widgetData.getMaxHeight() != 0) {
            textArea.setVisibleLines(widgetData.getMaxHeight());
        }
        if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(valueType)) {
            textArea.setValue(getDateAsText(fieldValue));
        } else {
            textArea.setValue(getStringValue(fieldValue));
        }
        textArea.setEnabled(!widgetData.isReadOnly());
        return textArea;
    }

    /**
     * Create a {@link RichTextWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link RichTextWidget}
     */
    protected RichTextWidget createRichTextArea(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final RichTextWidget richTextWidget = new RichTextWidget();
        if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(valueType)) {
            richTextWidget.setValue(getDateAsText(fieldValue));
        } else {
            richTextWidget.setValue(getStringValue(fieldValue));
        }
        richTextWidget.setEnabled(!widgetData.isReadOnly());
        return richTextWidget;
    }

    /**
     * Create a {@link PasswordTextBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link PasswordTextBox}
     */
    @SuppressWarnings("unchecked")
    protected PasswordTextBox createPasswordTextBox(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final PasswordTextBox passwordTextBox = new PasswordTextBox();
        passwordTextBox.addChangeHandler(this);
        passwordTextBox.addValueChangeHandler(this);
        if (widgetData.getMaxLength() != 0) {
            passwordTextBox.setMaxLength(widgetData.getMaxLength());
        }
        passwordTextBox.setValue(getStringValue(fieldValue));
        passwordTextBox.setEnabled(!widgetData.isReadOnly());
        return passwordTextBox;
    }

    /**
     * Create a {@link HTML} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link HTML}
     */
    protected HTML createText(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final HTML text = new HTML();
        if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(valueType)) {
            text.setText(getDateAsText(fieldValue));
        } else if (widgetData.allowHTMLInField()) {
            text.setHTML(getStringValue(fieldValue));
        } else {
            text.setText(getStringValue(fieldValue));
        }
        return text;
    }

    /**
     * Create a {@link CheckBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link CheckBox}
     */
    @SuppressWarnings("unchecked")
    protected CheckBox createCheckBox(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final CheckBox checkBox = new CheckBox();
        checkBox.addClickHandler(this);
        checkBox.addValueChangeHandler(this);
        try {
            checkBox.setValue((Boolean) fieldValue.getValue());
        } catch (final Exception e) {
            Window.alert("initial value for checkbox " + widgetData.getId() + " should be a boolean.");
            checkBox.setValue(false, false);
        }
        checkBox.setEnabled(!widgetData.isReadOnly());
        return checkBox;
    }

    /**
     * Create a {@link RadioButtonGroupWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link RadioButtonGroupWidget}
     */
    @SuppressWarnings("unchecked")
    protected RadioButtonGroupWidget createRadioButtonGroup(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final RadioButtonGroupWidget radioButtonGroupWidget = new RadioButtonGroupWidget(widgetData.getId(),
                widgetData.getAvailableValues(), getStringValue(fieldValue), widgetData.getItemsStyle(),
                widgetData.allowHTMLInField());
        radioButtonGroupWidget.addClickHandler(this);
        radioButtonGroupWidget.addValueChangeHandler(this);
        radioButtonGroupWidget.setEnabled(!widgetData.isReadOnly());
        return radioButtonGroupWidget;
    }

    /**
     * Create a {@link ListBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link ListBox}
     */
    protected ListBox createListBox(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final ListBox listBox = new ListBox(false);
        listBox.addChangeHandler(this);
        int index = 0;
        final String fieldValueStr = getStringValue(fieldValue);
        for (final ReducedFormFieldAvailableValue availableValue : widgetData.getAvailableValues()) {
            listBox.addItem(availableValue.getLabel(), availableValue.getValue());
            if (availableValue.getValue() != null && availableValue.getValue().equals(fieldValueStr)) {
                listBox.setItemSelected(index, true);
            }
            index++;
        }
        listBox.setEnabled(!widgetData.isReadOnly());
        return listBox;
    }

    /**
     * Create a multiple select {@link ListBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link ListBox}
     */
    protected ListBox createListBoxMulti(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final ListBox listBoxMulti = new ListBox(true);
        listBoxMulti.addChangeHandler(this);
        final Collection<String> initialValues = getStringValues(fieldValue);
        int indexMulti = 0;
        for (final ReducedFormFieldAvailableValue availableValue : widgetData.getAvailableValues()) {
            listBoxMulti.addItem(availableValue.getLabel(), availableValue.getValue());
            if (initialValues != null) {
                for (final String value : initialValues) {
                    if (availableValue.getValue() != null && availableValue.getValue().equals(value)) {
                        listBoxMulti.setItemSelected(indexMulti, true);
                    }
                }
            }
            indexMulti++;
        }
        if (widgetData.getMaxHeight() != 0) {
            listBoxMulti.setVisibleItemCount(widgetData.getMaxHeight());
        }
        listBoxMulti.setEnabled(!widgetData.isReadOnly());
        return listBoxMulti;
    }

    /**
     * Create a {@link SuggestBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link SuggestBox}
     */
    @SuppressWarnings("unchecked")
    protected SuggestBox createSuggestBox(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final TextBox textBox = new TextBox();
        textBox.setEnabled(!widgetData.isReadOnly());
        final DefaultSuggestionDisplay suggestionDisplay = new DefaultSuggestionDisplay();
        final String popupStyle = widgetData.getItemsStyle();
        if (popupStyle != null && popupStyle.length() > 0) {
            suggestionDisplay.setPopupStyleName(popupStyle);
        }
        suggestionsMap = new TreeMap<String, String>();
        final MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();

        // this fix the reordering of numbers
        final Comparator<String> numberComparator = new Comparator<String>() {

            @Override
            public int compare(final String o1, final String o2) {

                if (stringIsDouble(o1) && stringIsDouble(o2)) {
                    return Double.valueOf(o1).compareTo(Double.valueOf(o2));
                }
                return o1.compareTo(o2);
            }

            private boolean stringIsDouble(final String str) {
                return str.matches("^(([0-9]*)|(([0-9]*)[\\.,\\,]([0-9]*)))$");
            }

        };
        oracle.setComparator(numberComparator);

        String labelValue = null;
        final String fieldValueStr = getStringValue(fieldValue);
        widgetData.getAvailableValues();
        for (final ReducedFormFieldAvailableValue availableValue : widgetData.getAvailableValues()) {
            final String label = availableValue.getLabel();
            final String value = availableValue.getValue();
            suggestionsMap.put(label, value);
            oracle.add(label);
            if (value != null && value.equals(fieldValueStr)) {
                labelValue = label;
            }
        }
        final SuggestBox suggestBox = new SuggestBox(oracle, textBox, suggestionDisplay);
        suggestBox.addValueChangeHandler(this);
        suggestBox.addSelectionHandler(this);
        if (labelValue != null) {
            suggestBox.setValue(labelValue);
        } else {
            suggestBox.setValue(fieldValueStr);
        }
        if (widgetData.getMaxItems() > 0) {
            suggestBox.setLimit(widgetData.getMaxItems() - 1);
        }
        return suggestBox;
    }

    /**
     * @param widgetData
     * @param fieldValue
     * @return a {@link AsyncSuggestBoxWidget}
     */
    @SuppressWarnings("unchecked")
    protected AsyncSuggestBoxWidget createSuggestBoxAsync(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final AsyncSuggestBoxWidget formAsyncSuggestBoxWidget = new AsyncSuggestBoxWidget(widgetData, formID,
                contextMap, fieldValue);
        formAsyncSuggestBoxWidget.getAsyncSuggestBox().addValueChangeHandler(this);
        formAsyncSuggestBoxWidget.getAsyncSuggestBox().addSelectionHandler(this);
        return formAsyncSuggestBoxWidget;
    }

    /**
     * Create a {@link CheckboxGroupWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link CheckboxGroupWidget}
     */
    @SuppressWarnings("unchecked")
    protected CheckboxGroupWidget createCheckboxGroup(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final Collection<String> initialValues = getStringValues(fieldValue);
        final CheckboxGroupWidget checkBoxGroupWidget = new CheckboxGroupWidget(widgetData.getAvailableValues(),
                initialValues, widgetData.getItemsStyle(), widgetData.allowHTMLInField());
        checkBoxGroupWidget.addClickHandler(this);
        checkBoxGroupWidget.addValueChangeHandler(this);
        checkBoxGroupWidget.setEnabled(!widgetData.isReadOnly());
        return checkBoxGroupWidget;
    }

    /**
     * Create a {@link DateBox} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link DateBox}
     */
    @SuppressWarnings("unchecked")
    protected DateBox createDateBox(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final DateBox dateBox = new DateBox();
        dateBox.addValueChangeHandler(this);
        // display format
        if (displayFormatPattern != null && displayFormatPattern.length() > 0) {
            displayFormat = DateTimeFormat.getFormat(displayFormatPattern);
        } else {
            displayFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG);
        }
        final Format format = new DefaultFormat(displayFormat);
        dateBox.setFormat(format);
        if (fieldValue.getValue() != null) {
            final Date initialDate = (Date) fieldValue.getValue();
            dateBox.setValue(initialDate);
        }
        if (widgetData.isReadOnly()) {
            dateBox.getDatePicker().removeFromParent();
            dateBox.getTextBox().setEnabled(false);
        }
        return dateBox;
    }

    /**
     * Create a {@link DurationWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link DurationWidget}
     */
    protected DurationWidget createDuration(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        Long duration = null;
        try {
            duration = (Long) fieldValue.getValue();
        } catch (final Exception e) {
            duration = 0L;
            Window.alert("the initial value for duration widget " + widgetData.getId() + " should be a Long.");
        }
        final DurationWidget durationWidget = new DurationWidget(widgetData.getDisplayFormat(), duration,
                widgetData.getItemsStyle());
        durationWidget.addChangeHandler(this);
        durationWidget.setEnabled(!widgetData.isReadOnly());
        return durationWidget;
    }

    /**
     * Create a {@link FileUploadWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link FileUploadWidget}
     */
    protected FileUploadWidget createFileUpload(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final FileUploadWidget fileUploadWidget = new FileUploadWidget(formID, contextMap, widgetData.getId(),
                widgetData.getFileWidgetInputType(), fieldValue.getValueType(), fieldValue.getDocumentId(),
                fieldValue.getDocumentName(), getStringValue(fieldValue), widgetData.isDisplayAttachmentImage());
        if (widgetData.isReadOnly()) {
            fileUploadWidget.disable();
        }
        return fileUploadWidget;
    }

    /**
     * Create a {@link FileDownloadWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link FileDownloadWidget}
     */
    protected FileDownloadWidget createFileDownload(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        return new FileDownloadWidget(formID, contextMap, fieldValue.getValueType(), fieldValue.getDocumentId(),
                widgetData.isDisplayAttachmentImage(), getStringValue(fieldValue));
    }

    /**
     * Create a {@link ImageWidget} widget
     *
     * @param widgetData
     * @param fieldValue
     *        the widget value
     * @param displayAttachmentImage
     * @return a {@link ImageWidget}
     */
    protected ImageWidget createImage(final ReducedFormWidget widgetData, final FormFieldValue fieldValue,
            final boolean displayAttachmentImage) {
        String value = null;
        if (displayAttachmentImage && SupportedFieldTypes.JAVA_FILE_CLASSNAME.equals(fieldValue.getValueType())) {
            value = fieldValue.getDocumentName();
        } else {
            value = getStringValue(fieldValue);
        }
        return new ImageWidget(formID, contextMap, fieldValue.getValueType(), fieldValue.getDocumentId(), value,
                widgetData.getImageStyle(), displayAttachmentImage);
    }

    /**
     * Create an {@link TableWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link TableWidget}
     */
    @SuppressWarnings("unchecked")
    protected TableWidget createTable(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        final TableWidget tableWidget = new TableWidget(widgetData, getTableValue(fieldValue));
        tableWidget.addValueChangeHandler(this);
        return tableWidget;
    }

    /**
     * Create an {@link EditableGridWidget} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return an {@link EditableGridWidget}
     */
    @SuppressWarnings("unchecked")
    protected EditableGridWidget createEditableGrid(final ReducedFormWidget widgetData,
            final FormFieldValue fieldValue) {
        final EditableGridWidget gridWidget = new EditableGridWidget(formID, widgetData, getGridValue(fieldValue));
        gridWidget.addValueChangeHandler(this);
        return gridWidget;
    }

    /**
     * Create a {@link Hidden} widget
     *
     * @param widgetData
     *        the widget data object
     * @param fieldValue
     *        the widget value
     * @return a {@link Hidden}
     */
    protected Hidden createHidden(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        return new Hidden(widgetData.getId(), getStringValue(fieldValue));
    }

    /**
     * Create the widget
     *
     * @param widgetData
     *        the widget data object
     */
    protected void createWidget(final ReducedFormWidget widgetData, final FormFieldValue fieldValue) {
        // label creation
        if (widgetData.isMandatory() || widgetData.getLabel() != null && widgetData.getLabel().length() > 0) {
            labelWidget = new LabelWidget(widgetData, mandatoryFieldSymbol, mandatoryFieldClasses);
            if (ItemPosition.LEFT.equals(widgetData.getLabelPosition())) {
                addLabel(labelWidget, "bonita_form_label_left");
            } else if (ItemPosition.TOP.equals(widgetData.getLabelPosition())) {
                addLabel(labelWidget, "bonita_form_label_top");
            }
        }
        // field creation
        switch (widgetType) {
        case TEXTBOX:
            fieldWidget = createTextBox(widgetData, fieldValue);
            break;
        case TEXTAREA:
            fieldWidget = createTextArea(widgetData, fieldValue);
            break;
        case RICH_TEXTAREA:
            fieldWidget = createRichTextArea(widgetData, fieldValue);
            break;
        case PASSWORD:
            fieldWidget = createPasswordTextBox(widgetData, fieldValue);
            break;
        case TEXT:
            fieldWidget = createText(widgetData, fieldValue);
            break;
        case CHECKBOX:
            fieldWidget = createCheckBox(widgetData, fieldValue);
            break;
        case RADIOBUTTON_GROUP:
            fieldWidget = createRadioButtonGroup(widgetData, fieldValue);
            break;
        case LISTBOX_SIMPLE:
            fieldWidget = createListBox(widgetData, fieldValue);
            break;
        case LISTBOX_MULTIPLE:
            fieldWidget = createListBoxMulti(widgetData, fieldValue);
            break;
        case SUGGESTBOX:
            fieldWidget = createSuggestBox(widgetData, fieldValue);
            break;
        case SUGGESTBOX_ASYNC:
            fieldWidget = createSuggestBoxAsync(widgetData, fieldValue);
            break;
        case CHECKBOX_GROUP:
            fieldWidget = createCheckboxGroup(widgetData, fieldValue);
            break;
        case DATE:
            fieldWidget = createDateBox(widgetData, fieldValue);
            break;
        case DURATION:
            fieldWidget = createDuration(widgetData, fieldValue);
            break;
        case FILEUPLOAD:
            fieldWidget = createFileUpload(widgetData, fieldValue);
            break;
        case FILEDOWNLOAD:
            fieldWidget = createFileDownload(widgetData, fieldValue);
            break;
        case IMAGE:
            fieldWidget = createImage(widgetData, fieldValue, widgetData.isDisplayAttachmentImage());
            break;
        case TABLE:
            fieldWidget = createTable(widgetData, fieldValue);
            break;
        case EDITABLE_GRID:
            fieldWidget = createEditableGrid(widgetData, fieldValue);
            break;
        case HIDDEN:
            fieldWidget = createHidden(widgetData, fieldValue);
            fieldContainer.add(fieldWidget);
            break;
        default:
            Window.alert(widgetType + " widget not supported.");
            break;
        }

        if (widgetType == WidgetType.LISTBOX_SIMPLE) {
            final FlowPanel div = new FlowPanel();
            div.add(fieldWidget);
            addStandardWidgetFeatures(div, widgetData);
            div.addStyleName("list_container");
        } else {
            addStandardWidgetFeatures(fieldWidget, widgetData);
        }

        if (labelWidget != null) {
            if (ItemPosition.RIGHT.equals(widgetData.getLabelPosition())) {
                addLabel(labelWidget, "bonita_form_label_right");
                if (isStaticField()) {
                    fieldWidget.addStyleName("bonita_form_static_field_left");
                } else if (WidgetType.TEXTAREA.equals(widgetData.getType()) && widgetData.getMaxLength() != 0) {
                    fieldWidget.addStyleName("bonita_form_field_left_no_width");
                } else {
                    fieldWidget.addStyleName("bonita_form_field_left");
                }
            } else if (ItemPosition.BOTTOM.equals(widgetData.getLabelPosition())) {
                addLabel(labelWidget, "bonita_form_label_bottom");
                if (isStaticField()) {
                    fieldWidget.addStyleName("bonita_form_static_field_top");
                } else if (WidgetType.TEXTAREA.equals(widgetData.getType()) && widgetData.getMaxLength() != 0) {
                    fieldWidget.addStyleName("bonita_form_field_top_no_width");
                } else {
                    fieldWidget.addStyleName("bonita_form_field_top");
                }
            } else if (ItemPosition.TOP.equals(widgetData.getLabelPosition())) {
                if (isStaticField()) {
                    fieldWidget.addStyleName("bonita_form_static_field_bottom");
                } else if (WidgetType.TEXTAREA.equals(widgetData.getType()) && widgetData.getMaxLength() != 0) {
                    fieldWidget.addStyleName("bonita_form_field_bottom_no_width");
                } else {
                    fieldWidget.addStyleName("bonita_form_field_bottom");
                }
            } else {
                if (isStaticField()) {
                    fieldWidget.addStyleName("bonita_form_static_field_right");
                } else if (WidgetType.TEXTAREA.equals(widgetData.getType()) && widgetData.getMaxLength() != 0) {
                    fieldWidget.addStyleName("bonita_form_field_right_no_width");
                } else {
                    fieldWidget.addStyleName("bonita_form_field_right");
                }
            }
            if (widgetData.getLabelStyle() != null && widgetData.getLabelStyle().length() > 0) {
                labelWidget.addStyleName(widgetData.getLabelStyle());
            }
        } else {
            if (isStaticField()) {
                fieldWidget.addStyleName("bonita_form_static_field_top");
            } else {
                fieldWidget.addStyleName("bonita_form_field_top");
            }
        }
        if (widgetData.getInputStyle() != null && widgetData.getInputStyle().length() > 0) {
            fieldWidget.addStyleName(widgetData.getInputStyle());
        }

        // display sub title
        if (widgetData.getSubtitle() != null) {
            final String label = widgetData.getSubtitle().getLabel();
            if (label != null && label.trim().length() > 0) {
                if (SubTitlePosition.TOP.equals(widgetData.getSubtitle().getPosition())) {
                    final HTML subTitle = new HTML(widgetData.getSubtitle().getLabel());
                    subTitle.addStyleName("bonita_form_field_sub_title");
                    flowPanel.add(subTitle);
                    flowPanel.add(fieldContainer);
                } else {
                    final HTML subTitle = new HTML(widgetData.getSubtitle().getLabel());
                    subTitle.addStyleName("bonita_form_field_sub_title");
                    flowPanel.add(fieldContainer);
                    flowPanel.add(subTitle);
                }
            } else {
                flowPanel.add(fieldContainer);
            }
        } else {
            flowPanel.add(fieldContainer);
        }
        flowPanel.addStyleName("bonita_form_vertical_panel");

        // tool-tip widget display
        if (widgetData.getPopupTooltip() != null && widgetData.getPopupTooltip().length() > 0) {

            theOuterToolTipPanel = new FlowPanel();
            final PopupPanel toolTipPopupFrame = new PopupPanel(true);
            toolTipPopupFrame.setWidget(new Label(widgetData.getPopupTooltip()));
            toolTipPopupFrame.addStyleName("bonita_form_popup_tooltip");

            final Image toolTipIcon = new Image("themeResource?theme=portal&location=images/tooltip.gif");
            toolTipIcon.setStylePrimaryName("bonita_form_popup_tooltip_img");
            theOuterToolTipPanel.add(toolTipIcon);
            theOuterToolTipPanel.setStylePrimaryName("bonita_form_popup_tooltip_icon");

            toolTipIcon.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(final ClickEvent event) {
                    final Widget source = (Widget) event.getSource();
                    final int left = source.getAbsoluteLeft();
                    final int top = source.getAbsoluteTop();
                    toolTipPopupFrame.setPopupPosition(left + 10, top + 5);
                    toolTipPopupFrame.show();
                }
            });
            if (ItemPosition.RIGHT.equals(widgetData.getLabelPosition())) {
                toolTipPopupFrame.addStyleName("bonita_form_popup_tooltip_left");
                fieldContainer.add(theOuterToolTipPanel);
            } else if (ItemPosition.LEFT.equals(widgetData.getLabelPosition())) {
                fieldContainer.add(theOuterToolTipPanel);
            } else if (ItemPosition.TOP.equals(widgetData.getLabelPosition())) {
                fieldContainer.add(theOuterToolTipPanel);
            } else if (ItemPosition.BOTTOM.equals(widgetData.getLabelPosition())) {
                fieldContainer.add(theOuterToolTipPanel);
            }
        }
    }

    private void addLabel(final HTML labelWidget, final String styleName) {
        labelWidget.addStyleName(styleName);
        fieldContainer.add(labelWidget);
    }

    /**
     * @return true if the field is static, false otherwise
     */
    protected boolean isStaticField() {
        if (widgetType.equals(WidgetType.TEXT) || widgetType.equals(WidgetType.FILEDOWNLOAD)
                || widgetType.equals(WidgetType.IMAGE)) {
            return true;
        }
        return false;
    }

    /**
     * Get the string display value for a date
     *
     * @param fieldValue
     *        the field value object
     * @return the date as a String
     */
    protected String getDateAsText(final FormFieldValue fieldValue) {

        if (displayFormatPattern != null && displayFormatPattern.length() > 0) {
            displayFormat = DateTimeFormat.getFormat(displayFormatPattern);
        } else {
            displayFormat = DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG);
        }
        Date initialDate = null;
        if (fieldValue.getValue() != null) {
            initialDate = (Date) fieldValue.getValue();
        } else {
            initialDate = new Date();
        }
        return displayFormat.format(initialDate);
    }

    /**
     * @param fieldValue
     *        the data field value
     * @return a List<String>
     */
    @SuppressWarnings("unchecked")
    protected List<String> getTableValue(final FormFieldValue fieldValue) {
        List<String> valueList = null;
        try {
            valueList = (List<String>) fieldValue.getValue();
        } catch (final ClassCastException firstAttemptException) {
            try {
                final Collection<String> tableValue = (Collection<String>) fieldValue.getValue();
                valueList = new ArrayList<String>(tableValue);
            } catch (final ClassCastException secondAttemptException) {
                Window.alert("the initial value for table " + widgetId + " should be a Collection<String>.");
            }
        }
        return valueList;
    }

    /**
     * @param fieldValue
     *        the data field value
     * @return a List of List<String>
     */
    @SuppressWarnings("unchecked")
    protected List<List<String>> getGridValue(final FormFieldValue fieldValue) {
        List<List<String>> valueList = null;
        try {
            valueList = (List<List<String>>) fieldValue.getValue();
        } catch (final Exception firstAttemptException) {
            try {
                valueList = new ArrayList<List<String>>();
                final Collection<Collection<String>> tableValue = (Collection<Collection<String>>) fieldValue
                        .getValue();
                for (final Collection rowValue : tableValue) {
                    valueList.add(new ArrayList<String>(rowValue));
                }
            } catch (final Exception secondAttemptException) {
                Window.alert(
                        "the initial value for grid " + widgetId + " should be a Collection<Collection<String>>.");
            }
        }
        return valueList;
    }

    /**
     * Get the string display value for a date
     *
     * @param text
     *        the widget data object
     * @return the date as a String
     */
    protected Date getTextAsDate(final String text) {

        final DateTimeFormat initialFormat = DateTimeFormat.getFormat(displayFormatPattern);
        return initialFormat.parse(text);
    }

    /**
     * Get the string value of a {@link FormFieldValue}
     *
     * @param fieldValue
     *        the {@link FormFieldValue}
     * @return a String
     */
    protected String getStringValue(final FormFieldValue fieldValue) {
        String value = null;
        if (SupportedFieldTypes.JAVA_STRING_CLASSNAME.equals(fieldValue.getValueType())) {
            value = (String) fieldValue.getValue();
        } else if (fieldValue.getValue() != null) {
            value = fieldValue.getValue().toString();
        }
        return value;
    }

    /**
     * Get the Collection<String> value of a {@link FormFieldValue}
     *
     * @param fieldValue
     *        the {@link FormFieldValue}
     * @return a Collection<String>
     */
    @SuppressWarnings("unchecked")
    protected Collection<String> getStringValues(final FormFieldValue fieldValue) {
        Collection<String> value = null;
        try {
            value = (Collection<String>) fieldValue.getValue();
        } catch (final Exception e) {
            Window.alert("the initial value for a checkbox or radiobutton group should be a Collection<String>.");
            value = new HashSet<String>();
        }
        return value;
    }

    /**
     * add generic features to the field widgets
     *
     * @param fieldWidget
     *        the GWT widget
     * @param widgetData
     *        the widget data object
     */
    protected void addStandardWidgetFeatures(final Widget fieldWidget, final ReducedFormWidget widgetData) {
        if (isStaticField()) {
            if (widgetType.equals(WidgetType.IMAGE)) {
                fieldWidget.setStyleName("bonita_form_image_container");
            } else {
                fieldWidget.setStyleName("bonita_form_text");
            }
        } else {
            fieldWidget.setStyleName("bonita_form_field");
            if (widgetType.equals(WidgetType.DATE)) {
                fieldWidget.addStyleName("bonita_form_date");
            }
        }
        if (widgetData.getTitle() != null && widgetData.getTitle().length() > 0) {
            fieldWidget.setTitle(widgetData.getTitle());
        }
        insertWidgetInPanel(fieldWidget, widgetData);
    }

    /**
     * Insert the generated widget in the panel and set the fieldWidget attribute to keep a reference to it Set the HTML
     * attributes before inserting the generated widget in the panel.
     *
     * @param fieldWidget
     *        the field widget
     * @param widgetData
     *        the widget data object
     */
    protected void insertWidgetInPanel(final Widget fieldWidget, final ReducedFormWidget widgetData) {
        final ElementAttributeSupport elementAttributeSupport = new ElementAttributeSupport();
        elementAttributeSupport.addHtmlAttributes(fieldWidget, widgetData.getHtmlAttributes());
        fieldContainer.add(fieldWidget);
    }

    /**
     * Retrieve the value of the field under the form of a {@link FormFieldValue} object. This conversion is needed because RPC
     * calls do not support the type 'Object'.
     *
     * @return a {@link FormFieldValue} object
     */
    @SuppressWarnings("unchecked")
    public FormFieldValue getValue() {

        long attachmentId = -1;
        String attachmentName = null;
        Serializable value = null;
        String valueType = null;
        String format = null;
        String displayedValue = null;
        switch (widgetType) {
        case TEXTBOX:
            final TextBox textBox = (TextBox) fieldWidget;
            value = textBox.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case TEXTAREA:
            final TextArea textArea = (TextArea) fieldWidget;
            value = textArea.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case TEXT:
            final HTML text = (HTML) fieldWidget;
            value = text.getHTML();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case RICH_TEXTAREA:
            final RichTextWidget richTextWidget = (RichTextWidget) fieldWidget;
            value = richTextWidget.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case PASSWORD:
            final PasswordTextBox passwordTextBox = (PasswordTextBox) fieldWidget;
            value = passwordTextBox.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case CHECKBOX:
            final CheckBox checkBox = (CheckBox) fieldWidget;
            value = checkBox.getValue();
            valueType = SupportedFieldTypes.JAVA_BOOLEAN_CLASSNAME;
            break;
        case RADIOBUTTON_GROUP:
            final RadioButtonGroupWidget radioButtonGroupWidget = (RadioButtonGroupWidget) fieldWidget;
            value = radioButtonGroupWidget.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case LISTBOX_SIMPLE:
            final ListBox listBox = (ListBox) fieldWidget;
            final int index = listBox.getSelectedIndex();
            if (index > -1) {
                value = listBox.getValue(index);
            }
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case LISTBOX_MULTIPLE:
            value = new ArrayList<String>();
            final ListBox listBoxMulti = (ListBox) fieldWidget;
            for (int i = 0; i < listBoxMulti.getItemCount(); i++) {
                if (listBoxMulti.isItemSelected(i)) {
                    ((List<String>) value).add(listBoxMulti.getValue(i));
                }
            }
            valueType = SupportedFieldTypes.JAVA_COLLECTION_CLASSNAME;
            break;
        case SUGGESTBOX:
            final SuggestBox suggestBox = (SuggestBox) fieldWidget;
            displayedValue = suggestBox.getValue();
            value = suggestionsMap.get(displayedValue);
            if (value == null) {
                value = displayedValue;
            }
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case SUGGESTBOX_ASYNC:
            final AsyncSuggestBoxWidget formAsyncSuggestBoxWidget = (AsyncSuggestBoxWidget) fieldWidget;
            value = formAsyncSuggestBoxWidget.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        case CHECKBOX_GROUP:
            value = new ArrayList<String>();
            final CheckboxGroupWidget checkboxGroupWidget = (CheckboxGroupWidget) fieldWidget;
            for (final String checkboxGroupValue : checkboxGroupWidget.getValue()) {
                ((List<String>) value).add(checkboxGroupValue);
            }
            valueType = SupportedFieldTypes.JAVA_COLLECTION_CLASSNAME;
            break;
        case DATE:
            final DateBox dateBox = (DateBox) fieldWidget;
            final String strValue = dateBox.getTextBox().getValue();
            final Date dtValue = dateBox.getValue();
            if (strValue != null && strValue.length() > 0 && dtValue == null) {
                value = strValue;
                valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            } else {
                value = dtValue;
                valueType = SupportedFieldTypes.JAVA_DATE_CLASSNAME;
            }
            break;
        case DURATION:
            final DurationWidget duration = (DurationWidget) fieldWidget;
            value = duration.getValue();
            valueType = SupportedFieldTypes.JAVA_LONG_CLASSNAME;
            break;
        case FILEUPLOAD:
            final FileUploadWidget fileUpload = (FileUploadWidget) fieldWidget;
            attachmentName = fileUpload.getAttachmentName();
            attachmentId = fileUpload.getAttachmentId();
            value = fileUpload.getValue();
            displayedValue = fileUpload.getDisplayedValue();
            valueType = fileUpload.getValueType();
            break;
        case TABLE:
            final TableWidget table = (TableWidget) fieldWidget;
            value = (Serializable) table.getValue();
            valueType = SupportedFieldTypes.JAVA_COLLECTION_CLASSNAME;
            break;
        case EDITABLE_GRID:
            final EditableGridWidget grid = (EditableGridWidget) fieldWidget;
            value = (Serializable) grid.getValue();
            valueType = SupportedFieldTypes.JAVA_COLLECTION_CLASSNAME;
            break;
        case HIDDEN:
            final Hidden hidden = (Hidden) fieldWidget;
            value = hidden.getValue();
            valueType = SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            break;
        default:
            break;
        }
        if (displayFormat != null) {
            format = displayFormat.getPattern();
        } else {
            format = DateTimeFormat.getFormat(PredefinedFormat.DATE_LONG).getPattern();
        }
        final FormFieldValue formFieldValue = new FormFieldValue(value, valueType, format, fieldOutputType);
        if (WidgetType.FILEUPLOAD.equals(widgetType)) {
            formFieldValue.setDocumentName(attachmentName);
            formFieldValue.setDocumentId(attachmentId);
            formFieldValue.setDisplayedValue(displayedValue);
            formFieldValue.setDocument(true);
        }
        return formFieldValue;
    }

    /**
     * @return Return the type of the widget
     */
    public WidgetType getType() {
        return widgetType;
    }

    /**
     * Set the value of the widget
     *
     * @param fieldValue
     */
    public void setValue(final FormFieldValue fieldValue) {
        if (fieldValue.getValue() != null) {
            Collection<String> values = null;
            boolean fireEvents = true;
            switch (widgetType) {
            case TEXTBOX:
                final TextBox textBox = (TextBox) fieldWidget;
                if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(fieldValue.getValueType())) {
                    textBox.setValue(getDateAsText(fieldValue), fireEvents);
                } else {
                    textBox.setValue(getStringValue(fieldValue), fireEvents);
                }
                break;
            case TEXTAREA:
                final TextArea textArea = (TextArea) fieldWidget;
                if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(fieldValue.getValueType())) {
                    textArea.setValue(getDateAsText(fieldValue), fireEvents);
                } else {
                    textArea.setValue(getStringValue(fieldValue), fireEvents);
                }
                break;
            case RICH_TEXTAREA:
                final RichTextWidget richTextWidget = (RichTextWidget) fieldWidget;
                if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(fieldValue.getValueType())) {
                    richTextWidget.setValue(getDateAsText(fieldValue));
                } else {
                    richTextWidget.setValue(getStringValue(fieldValue));
                }
                break;
            case TEXT:
                final HTML text = (HTML) fieldWidget;
                if (text.getHTML() != null && text.getHTML().equals(fieldValue.getValue())
                        || fieldValue.getValue() != null && fieldValue.getValue().equals(text.getHTML())) {
                    fireEvents = false;
                }
                if (SupportedFieldTypes.JAVA_DATE_CLASSNAME.equals(fieldValue.getValueType())) {
                    text.setText(getDateAsText(fieldValue));
                } else {
                    text.setHTML(getStringValue(fieldValue));
                }
                if (fireEvents) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), text);
                }
                break;
            case PASSWORD:
                final PasswordTextBox passwordTextBox = (PasswordTextBox) fieldWidget;
                passwordTextBox.setValue(getStringValue(fieldValue), fireEvents);
                break;
            case CHECKBOX:
                final CheckBox checkBox = (CheckBox) fieldWidget;
                try {
                    checkBox.setValue((Boolean) fieldValue.getValue(), fireEvents);
                } catch (final Exception e) {
                    checkBox.setValue(false, fireEvents);
                    Window.alert("initial value for checkbox " + widgetId + " should be a Boolean.");
                }
                break;
            case RADIOBUTTON_GROUP:
                final RadioButtonGroupWidget radioButtonGroupWidget = (RadioButtonGroupWidget) fieldWidget;
                radioButtonGroupWidget.setValue(getStringValue(fieldValue), fireEvents);
                break;
            case LISTBOX_SIMPLE:
                final ListBox listBox = (ListBox) fieldWidget;
                final int index = listBox.getSelectedIndex();
                if (index < 0) {
                    fireEvents = false;
                } else {
                    if (listBox.getValue(index).equals(getStringValue(fieldValue))) {
                        fireEvents = false;
                    }
                }
                for (int i = 0; i < listBox.getItemCount(); i++) {
                    if (listBox.getItemText(i).equals(getStringValue(fieldValue))) {
                        listBox.setItemSelected(i, true);
                        break;
                    }
                }
                if (fireEvents) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), listBox);
                }
                break;
            case LISTBOX_MULTIPLE:
                final ListBox listBoxMulti = (ListBox) fieldWidget;
                values = getStringValues(fieldValue);
                boolean valueChanged = false;
                for (int i = 0; i < listBoxMulti.getItemCount(); i++) {
                    if (values != null && values.contains(listBoxMulti.getItemText(i))) {
                        if (!listBoxMulti.isItemSelected(i)) {
                            valueChanged = true;
                            listBoxMulti.setItemSelected(i, true);
                        }
                    } else {
                        if (listBoxMulti.isItemSelected(i)) {
                            valueChanged = true;
                            listBoxMulti.setItemSelected(i, false);
                        }
                    }
                }
                if (fireEvents && valueChanged) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), listBoxMulti);
                }
                break;
            case SUGGESTBOX:
                final SuggestBox suggestBox = (SuggestBox) fieldWidget;
                final String stringValue = getStringValue(fieldValue);
                String labelValue = null;
                for (final Entry<String, String> suggestionEntry : suggestionsMap.entrySet()) {
                    if (suggestionEntry.getValue() != null && suggestionEntry.getValue().equals(stringValue)) {
                        labelValue = suggestionEntry.getKey();
                    }
                }
                if (labelValue != null) {
                    suggestBox.setValue(labelValue, fireEvents);
                } else {
                    suggestBox.setValue(stringValue, fireEvents);
                }
                break;
            case SUGGESTBOX_ASYNC:
                final AsyncSuggestBoxWidget formAsyncSuggestBoxWidget = (AsyncSuggestBoxWidget) fieldWidget;
                formAsyncSuggestBoxWidget.setValue(getStringValue(fieldValue), fireEvents);
                break;
            case CHECKBOX_GROUP:
                final CheckboxGroupWidget checkboxGroupWidget = (CheckboxGroupWidget) fieldWidget;
                values = getStringValues(fieldValue);
                checkboxGroupWidget.setValue(values, fireEvents);
                break;
            case DATE:
                final DateBox dateBox = (DateBox) fieldWidget;
                try {
                    dateBox.setValue((Date) fieldValue.getValue(), fireEvents);
                } catch (final Exception e) {
                    dateBox.setValue(null, fireEvents);
                    Window.alert("initial value for date " + widgetId + " should be a Date.");
                }
                break;
            case DURATION:
                final DurationWidget durationWidget = (DurationWidget) fieldWidget;
                Long duration = null;
                try {
                    duration = (Long) fieldValue.getValue();
                } catch (final Exception e) {
                    duration = 0L;
                    Window.alert("The initial value for duration widget " + widgetId + " should be a Long.");
                }
                durationWidget.setValue(duration, fireEvents);
                break;
            case IMAGE:
                final ImageWidget image = (ImageWidget) fieldWidget;
                image.setValue(fieldValue.getDocumentId(), getStringValue(fieldValue), fireEvents);
                break;
            case TABLE:
                final TableWidget table = (TableWidget) fieldWidget;
                table.setValue(getTableValue(fieldValue), fireEvents);
                if (fireEvents) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), table);
                }
                break;
            case EDITABLE_GRID:
                final EditableGridWidget grid = (EditableGridWidget) fieldWidget;
                grid.setValue(getGridValue(fieldValue));
                if (fireEvents) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), grid);
                }
                break;
            case HIDDEN:
                final Hidden hidden = (Hidden) fieldWidget;
                if (hidden.getValue() != null && hidden.getValue().equals(fieldValue.getValue())
                        || fieldValue.getValue() != null && fieldValue.getValue().equals(hidden.getValue())) {
                    fireEvents = false;
                }
                hidden.setValue(getStringValue(fieldValue));
                if (fireEvents) {
                    DomEvent.fireNativeEvent(Document.get().createChangeEvent(), hidden);
                }
                break;
            default:
                Window.alert("The modification of the value of a " + widgetType + " widget is not supported.");
                break;
            }
        }
    }

    /**
     * Set the available values of the widget (for list widgets only)
     *
     * @param availableValues
     */
    public void setAvailableValues(final List<ReducedFormFieldAvailableValue> availableValues,
            final boolean fireEvents) {
        switch (widgetType) {
        case RADIOBUTTON_GROUP:
            final RadioButtonGroupWidget radioButtonGroupWidget = (RadioButtonGroupWidget) fieldWidget;
            radioButtonGroupWidget.setAvailableValues(availableValues, fireEvents);
            break;
        case LISTBOX_SIMPLE:
            final ListBox listBox = (ListBox) fieldWidget;
            listBox.clear();
            for (final ReducedFormFieldAvailableValue availableValue : availableValues) {
                listBox.addItem(availableValue.getLabel(), availableValue.getValue());
            }
            if (fireEvents) {
                DomEvent.fireNativeEvent(Document.get().createChangeEvent(), listBox);
            }
            break;
        case LISTBOX_MULTIPLE:
            final ListBox listBoxMulti = (ListBox) fieldWidget;
            listBoxMulti.clear();
            for (final ReducedFormFieldAvailableValue availableValue : availableValues) {
                listBoxMulti.addItem(availableValue.getLabel(), availableValue.getValue());
            }
            if (fireEvents) {
                DomEvent.fireNativeEvent(Document.get().createChangeEvent(), listBoxMulti);
            }
            break;
        case SUGGESTBOX:
            final SuggestBox suggestBox = (SuggestBox) fieldWidget;
            final MultiWordSuggestOracle oracle = (MultiWordSuggestOracle) suggestBox.getSuggestOracle();
            oracle.clear();
            suggestionsMap.clear();
            for (final ReducedFormFieldAvailableValue availableValue : availableValues) {
                suggestionsMap.put(availableValue.getLabel(), availableValue.getValue());
                oracle.add(availableValue.getLabel());
            }
            if (fireEvents) {
                DomEvent.fireNativeEvent(Document.get().createChangeEvent(), suggestBox);
            }
            break;
        case SUGGESTBOX_ASYNC:
            final AsyncSuggestBoxWidget formAsyncSuggestBoxWidget = (AsyncSuggestBoxWidget) fieldWidget;
            formAsyncSuggestBoxWidget.setAvailableValues(availableValues, fireEvents);
            break;
        case CHECKBOX_GROUP:
            final CheckboxGroupWidget checkboxGroupWidget = (CheckboxGroupWidget) fieldWidget;
            checkboxGroupWidget.setAvailableValues(availableValues, fireEvents);
            break;
        default:
            Window.alert(
                    "The modification of the available values of a " + widgetType + " widget is not supported.");
            break;
        }
    }

    /**
     * Set the available values of the widget (for table widgets only)
     *
     * @param newTableWidgetAvailableValues
     */
    public void setTableAvailableValues(
            final List<List<ReducedFormFieldAvailableValue>> newTableWidgetAvailableValues,
            final boolean fireEvents) {
        if (WidgetType.TABLE.equals(widgetType)) {
            final TableWidget formTableWidget = (TableWidget) fieldWidget;
            formTableWidget.setAvailableValues(newTableWidgetAvailableValues, fireEvents);
        } else {
            Window.alert("The modification of the table available values of a " + widgetType
                    + " widget is not supported.");
        }
    }

    /**
     * set the mandatory label
     *
     * @param mandatoryLabel
     */
    public void setMandatoryLabel(final String mandatoryLabel) {
        labelWidget.setMandatoryText(mandatoryLabel);
    }

    /**
     * Set the focus on this widget if it's focusable
     */
    public void setFocusOn() {

        if (fieldWidget instanceof Focusable) {
            ((Focusable) fieldWidget).setFocus(true);
        }
    }

    /**
     * @return the ID of the widget
     */
    public String getId() {
        return widgetId;
    }

    /**
     * @return the field widget
     */
    public Widget getFieldWidget() {
        return fieldWidget;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public HandlerRegistration addChangeHandler(final ChangeHandler changeHandler) {
        if (changeHandlers == null) {
            changeHandlers = new ArrayList<ChangeHandler>();
        }
        changeHandlers.add(changeHandler);
        return new EventHandlerRegistration(changeHandler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public HandlerRegistration addClickHandler(final ClickHandler clickHandler) {
        if (clickHandlers == null) {
            clickHandlers = new ArrayList<ClickHandler>();
        }
        clickHandlers.add(clickHandler);
        return new EventHandlerRegistration(clickHandler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public HandlerRegistration addValueChangeHandler(final ValueChangeHandler valueChangeHandler) {
        if (valueChangeHandlers == null) {
            valueChangeHandlers = new HashMap<String, ValueChangeHandler<Serializable>>();
        }
        if (valueChangeHandler != null) {
            valueChangeHandlers.put(String.valueOf(valueChangeHandler.hashCode()), valueChangeHandler);
            return new EventHandlerRegistration(valueChangeHandler);
        } else {
            throw new NullPointerException("the given ValueChangeHandler is not defined");
        }
    }

    @Override
    public HandlerRegistration addSelectionHandler(final SelectionHandler<Suggestion> selectionHandler) {
        if (selectionHandlers == null) {
            selectionHandlers = new ArrayList<SelectionHandler<Suggestion>>();
        }
        selectionHandlers.add(selectionHandler);
        return new EventHandlerRegistration(selectionHandler);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onChange(final ChangeEvent changeEvent) {
        if (changeHandlers != null) {
            for (final ChangeHandler changeHandler : changeHandlers) {
                changeHandler.onChange(changeEvent);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onClick(final ClickEvent clickEvent) {
        if (clickHandlers != null) {
            for (final ClickHandler clickHandler : clickHandlers) {
                clickHandler.onClick(clickEvent);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public void onValueChange(final ValueChangeEvent valueChangeEvent) {
        if (valueChangeHandlers != null) {
            for (final ValueChangeHandler valueChangeHandler : valueChangeHandlers.values()) {
                valueChangeHandler.onValueChange(valueChangeEvent);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onSelection(final SelectionEvent<Suggestion> selectionEvent) {
        if (selectionHandlers != null) {
            for (final SelectionHandler<Suggestion> selectionHandler : selectionHandlers) {
                selectionHandler.onSelection(selectionEvent);
            }
        }
    }

    /**
     * Custom Handler registration
     */
    protected class EventHandlerRegistration implements HandlerRegistration {

        protected EventHandler eventHandler;

        public EventHandlerRegistration(final EventHandler eventHandler) {
            this.eventHandler = eventHandler;
        }

        @Override
        public void removeHandler() {
            if (eventHandler instanceof ClickHandler) {
                clickHandlers.remove(eventHandler);
            } else if (eventHandler instanceof ChangeHandler) {
                changeHandlers.remove(eventHandler);
            } else if (eventHandler instanceof ValueChangeHandler) {
                valueChangeHandlers.remove(eventHandler);
            } else if (eventHandler instanceof SelectionHandler) {
                selectionHandlers.remove(eventHandler);
            }
        }
    }

}