Package org.gwtoolbox.widget.client.form

Source Code of org.gwtoolbox.widget.client.form.Form$InternalFormFields

package org.gwtoolbox.widget.client.form;

import com.google.gwt.user.client.ui.Widget;
import org.gwtoolbox.widget.client.data.MapRecord;
import org.gwtoolbox.widget.client.data.MutableRecord;
import org.gwtoolbox.widget.client.data.Record;
import org.gwtoolbox.widget.client.form.field.FormField;
import org.gwtoolbox.widget.client.form.field.HasFields;
import org.gwtoolbox.widget.client.form.validation.ValidationResult;
import org.gwtoolbox.widget.client.form.validation.Validator;

import java.util.*;

/**
* <p>Utility class to help creating and handling forms. A form has multiple <code>FormField</code>s, a <code>Validator</code>
* and some utilities that almost every form needs. Rendering the form is a seperate concern from doing validation and
* form submission.</p>
* <p/>
* <p>Most important interactions with the form are described below</p>
* <ul>
* <li>obtaining fields - You can obtain a collection or a single instance by key</li>
* <li>obtain field characteristics poer key like : Label, EditorWidget</li>
* <li>validate the fields in the form. {@see FormField} for more information about the validators of the <code>FormField</code>
* items.</li>
* <li>Submit the form and provide a <code>SubmissionHandler</code> to determine what to do when the submission is valid or not.
* The handler receives the <code>Record</code> containing the fields and their values.</li>
* <li>Reset the form, cleaning all form fields</li>
* <li>Mark the form as mutable or un mutable. A mutable form can be edited, an un mutable form cannot</li>
* </ul>
* <p/>
* <p>This class also specifies the <code>FormValidationResult</code> as an inner class. This interface defines the interaction
* with the validation result. Of course you can ask if the form is valid. You can also ask the error messages. These are split
* up in generic error messages as well as field specific error messages.</p>
* <p/>
* <p>During form submission, a <code>Record</code> is filled with the data of the form fields. The record makes it easier to
* get to the data without the specifics of the widgets. Custom records can be provided using the contructor. By default the
* {@see MapRecord} is used.</p>
* <p/>
*
* @author Uri Boness
* @author Jettro Coenradie
*/
public class Form implements HasFields {

    private final InternalFormFields formFields;

    private final MutableRecord record;

    private Validator<Form> formValidator;

    private boolean mutable = true;

    /**
     * Default constructor of the form.
     */
    public Form() {
        this(new MapRecord());
    }

    /**
     * Constructor that accepts an implementation of the <code>MutableRecord</code> specification.
     *
     * @param record a non default implementation of the <code>MutableRecord</code>.
     */
    public Form(MutableRecord record) {
        formFields = new InternalFormFields();
        this.record = record;
    }

    /**
     * Returns a collection with all the <code>FormField</code>s
     *
     * @return collection with all the FormFields
     */
    public FormFields getFields() {
        return formFields;
    }

    /**
     * Returns the FormField belonging to the provided key. If the key cannot be found, a NoSuchFormFieldException is thrown
     * is returned.
     *
     * @param key the key to obtain the FormField for
     * @return FormField belonging to the provided key
     */
    public FormField getField(String key) throws NoSuchFormFieldException {
        FormField field = formFields.getField(key);
        if (field == null) {
            throw new NoSuchFormFieldException("No field with key " + key + " available in the form");
        }
        return field;
    }

    /**
     * Returns a collection with all available keys
     *
     * @return Colection containing all keys
     */
    public Collection<String> getKeys() {
        return formFields.getFieldsKeys();
    }

    /**
     * Return the label registered for the provided key
     *
     * @param fieldKey the label for the provided key
     * @return the label belonging to the provided key
     * @throws NoSuchFormFieldException thrown if the provided key is unknown
     */
    public String getLabel(String fieldKey) throws NoSuchFormFieldException {
        return getField(fieldKey).getLabel();
    }

    /**
     * Returns the editor for the field with the provided key
     *
     * @param fieldKey key of the field to obtain the editor for
     * @return editor for the field with the provided key
     * @throws NoSuchFormFieldException thrown if the provided key is unknown
     */
    public Widget getEditorWidget(String fieldKey) throws NoSuchFormFieldException {
        return getField(fieldKey).getEditor().getWidget();
    }

    /**
     * Provided a form validator with validation rules that are not specific for one of the fields.
     *
     * @param formValidator validator for the complete form
     */
    public void setFormValidator(Validator<Form> formValidator) {
        this.formValidator = formValidator;
    }

    /**
     * Removes the form validator
     */
    public void clearFormValidator() {
        formValidator = null;
    }

    /**
     * Adds the given fields to this form.
     *
     * @param fields The fields to be added.
     */
    public void addFields(FormField... fields) {
        for (FormField field : fields) {
            field.setEnabled(mutable);
            formFields.add(field);
        }
    }

    /**
     * Evaluates and validates the input data.
     *
     * @return The validation result.
     */
    public FormValidationResult validate() {
        DefaultFormValidationResult result = new DefaultFormValidationResult();
        for (Map.Entry<String, FormField> entry : formFields.fieldByKey.entrySet()) {
            FormField field = entry.getValue();
            if (field.isEnabled()) {
                ValidationResult fieldResult = entry.getValue().validate();
                result.merge(field.getKey(), fieldResult);
            }
        }
        if (formValidator != null) {
            ValidationResult generalValidationResult = formValidator.validate(this);
            if (!generalValidationResult.isValid()) {
                result.setGeneralValidationResult(generalValidationResult);
            }
        }
        return result;
    }

    /**
     * Returns the record underneath the form. Beware, this is useless before the form is submitted.
     *
     * @return The record from the form
     */
    public MutableRecord getRecord() {
        return record;
    }

    /**
     * Submits the form. The submision process is composed of 2 phases:
     * <ol>
     * <li>Validates the input data in all the fields</li>
     * <li>Collects the input data into a Record</li>
     * </ol>
     * If validation fails, the {@link org.gwtoolbox.widget.client.form.SubmitHandler#invalid(FormValidationResult)}
     * will be called. Otherwise, the {@link org.gwtoolbox.widget.client.form.SubmitHandler#success(org.gwtoolbox.widget.client.data.Record)} will be called.
     *
     * @param handler The handler to handle the form submission.
     */
    public void submit(SubmitHandler handler) {
        FormValidationResult validationResult = validate();
        if (!validationResult.isValid()) {
            if (handler != null) {
                handler.invalid(validationResult);
            }
            return;
        }

        record.setValues(collectData());
        if (handler != null) {
            handler.success(record);
        }
    }

    /**
     * Resets the form. Calls {@link org.gwtoolbox.widget.client.form.field.FormField#reset()} on all the fields.
     */
    public void reset() {
        for (FormField field : formFields.fieldByKey.values()) {
            field.reset();
        }
    }

    /**
     * indicate that the fields of the form should be editable in the rendering
     */
    public void markMutable() {
        mutable = true;
        for (FormField field : formFields.fieldByKey.values()) {
            field.setEnabled(true);
        }
    }

    /**
     * Indicate that the fields of the form should not be editable in the rendering
     */
    public void markUnMutable() {
        mutable = false;
        for (FormField field : formFields.fieldByKey.values()) {
            field.setEnabled(false);
        }
    }

    /**
     * Returns if the form is currently editable
     *
     * @return true if editable false elsewise
     */
    public boolean isMutable() {
        return mutable;
    }

    //================================================ Helper Methods ==================================================

    /**
     * Collects all the input data and returns it as a {@link org.gwtoolbox.widget.client.data.Record}. Note that no validation is performed on the
     * collected data therefore the returned data may be invalid.
     *
     * @return A record representing the input data.
     */
    private Record collectData() {
        Map<String, Object> data = new HashMap<String, Object>();
        for (Map.Entry<String, FormField> entry : formFields.fieldByKey.entrySet()) {
            FormField field = entry.getValue();
            if (field.isEnabled()) {
                Object value = entry.getValue().getEditor().getValue();
                data.put(entry.getKey(), value);
            }
        }
        return new MapRecord(data);
    }


    //================================================= Inner Classes ==================================================

    public static interface FormValidationResult {

        boolean isValid();

        boolean isValid(String fieldKey);

        List<String> getGeneralErrorMessages();

        Collection<String> getInvalidFieldsKeys();

        List<String> getErrorMessages(String fieldKey);

    }

    private static class DefaultFormValidationResult implements FormValidationResult {

        private ValidationResult generalValidationResult;
        private Map<String, ValidationResult> validationResultByFieldKey;

        public boolean isValid() {
            return (validationResultByFieldKey == null || validationResultByFieldKey.isEmpty()) &&
                    (generalValidationResult == null || generalValidationResult.isValid());
        }

        public boolean isValid(String fieldKey) {
            if (generalValidationResult == null && validationResultByFieldKey == null) {
                return true;
            }
            ValidationResult result = validationResultByFieldKey == null ? null : validationResultByFieldKey.get(fieldKey);
            return result == null ? true : result.isValid();
        }

        public Collection<String> getInvalidFieldsKeys() {
            return validationResultByFieldKey == null ? Collections.EMPTY_LIST : validationResultByFieldKey.keySet();
        }

        public List<String> getErrorMessages(String fieldKey) {
            if (validationResultByFieldKey == null) {
                return null;
            }
            ValidationResult result = validationResultByFieldKey.get(fieldKey);
            return result == null ? null : result.getErrorMessages();
        }

        public List<String> getGeneralErrorMessages() {
            return (generalValidationResult == null) ? Collections.EMPTY_LIST : generalValidationResult.getErrorMessages();
        }

        /**
         * If the ValidationResult is not valid, the result is stored in the list with errors per field
         *
         * @param key    The key to put the ValidationResult in the map with errors
         * @param result The ValidationResult to store for the provided key.
         */
        private void merge(String key, ValidationResult result) {
            if (result == null || result.isValid()) {
                return;
            }

            if (validationResultByFieldKey == null) {
                validationResultByFieldKey = new HashMap<String, ValidationResult>();
            }
            validationResultByFieldKey.put(key, result);
        }

        private void setGeneralValidationResult(ValidationResult result) {
            this.generalValidationResult = result;
        }
    }

    private class InternalFormFields implements FormFields {

        private final Map<String, FormField> fieldByKey = new HashMap<String, FormField>();
        private final List<String> fieldKeys = new ArrayList<String>();

        public List<String> getFieldsKeys() {
            return fieldKeys;
        }

        public FormField getField(String key) {
            return fieldByKey.get(key);
        }

        public void add(FormField field) {
            fieldByKey.put(field.getKey(), field);
            fieldKeys.add(field.getKey());
        }
    }


}
TOP

Related Classes of org.gwtoolbox.widget.client.form.Form$InternalFormFields

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.