FormExample.java
package com.itmill.toolkit.demo.featurebrowser;

import com.itmill.toolkit.data.Item;
import com.itmill.toolkit.data.Validator;
import com.itmill.toolkit.data.Validator.InvalidValueException;
import com.itmill.toolkit.data.util.BeanItem;
import com.itmill.toolkit.ui.BaseFieldFactory;
import com.itmill.toolkit.ui.Button;
import com.itmill.toolkit.ui.Component;
import com.itmill.toolkit.ui.CustomComponent;
import com.itmill.toolkit.ui.Field;
import com.itmill.toolkit.ui.Form;
import com.itmill.toolkit.ui.HorizontalLayout;
import com.itmill.toolkit.ui.TextField;
import com.itmill.toolkit.ui.VerticalLayout;
import com.itmill.toolkit.ui.Button.ClickEvent;
import com.itmill.toolkit.ui.Button.ClickListener;

/**
 * This example demonstrates the most important features of the Form component:
 * binding Form to a JavaBean so that form fields are automatically generated
 * from the bean properties, creation of custom field editors using a
 * FieldFactory, customizing the form without FieldFactory, buffering
 * (commit/discard) and validation. Please note that the example is quite a bit
 * more complex than real use, as it tries to demonstrate more features than
 * needed in general case.
 */
public class FormExample extends CustomComponent {

    static final String cities[] "Amsterdam""Berlin""Helsinki",
            "Hong Kong""London""Luxemburg""New York""Oslo""Paris",
            "Rome""Stockholm""Tokyo""Turku" };

    /** Compose the demo. */
    public FormExample() {

        // Example data model
        final Address dataModel = new Address();
        Button peekDataModelState = new Button("Show the data model state",
                new Button.ClickListener() {

                    public void buttonClick(ClickEvent event) {
                        getWindow().showNotification(
                                dataModel.getAddressAsText());
                    }
                });

        // Example form
        final AddressForm form = new AddressForm("Contact Information");
        form.setDataSource(dataModel);
        form
                .setDescription("Please enter valid name and address. Fields marked with * are required. "
                        "If you try to commit with invalid values, a form error message is displayed. "
                        "(Address is required but failing to give it a value does not display an error.)");

        // Layout the example
        VerticalLayout root = new VerticalLayout();
        root.setMargin(true);
        root.setSpacing(true);
        root.addComponent(form);
        root.addComponent(peekDataModelState);
        setCompositionRoot(root);
    }

    public static class AddressForm extends Form {
        public AddressForm(String caption) {

            setCaption(caption);

            // Use custom field factory to modify the defaults on how the
            // components are created
            setFieldFactory(new MyFieldFactory());

            // Add Commit and Discard controls to the form.

            Button commit = new Button("Save"new ClickListener() {

                public void buttonClick(ClickEvent event) {
                    try {
                        commit();
                    catch (InvalidValueException e) {
                        // Failed to commit. The validation errors are
                        // automatically shown to the user.
                    }
                }

            });

            Button discard = new Button("Reset", this, "discard");
            HorizontalLayout footer = new HorizontalLayout();
            footer.addComponent(commit);
            footer.addComponent(discard);
            setFooter(footer);
        }

        public void setDataSource(Address dataModel) {

            // Set the form to edit given datamodel by converting pojo used as
            // the datamodel to Item
            setItemDataSource(new BeanItem(dataModel));

            // Ensure that the fields are shown in correct order as the
            // datamodel does not force any specific order.
            setVisibleItemProperties(new String[] { "name""streetAddress",
                    "postalCode""city" });

            // For examples sake, customize some of the form fields directly
            // here. The alternative way is to use custom field factory as shown
            // above.
            getField("name").setRequired(true);
            getField("name").setDescription("Please enter name");
            getField("name").setRequiredError("Name is missing");
            getField("streetAddress").setRequired(true)// No error message
            getField("streetAddress").setDescription(
                    "Please enter street adderss.");
            getField("postalCode").setRequired(true)// No error message
            getField("postalCode").setDescription(
                    "Please enter postal code. Example: 12345.");
            replaceWithSelect("city", cities, cities).setNewItemsAllowed(true);
            getField("city")
                    .setDescription(
                            "Select city from list or type it. City field is not required.");

            // Set the form to act immediately on user input. This is
            // automatically transports data between the client and the server
            // to do server-side validation.
            setImmediate(true);

            // Enable buffering so that commit() must be called for the form
            // before input is written to the data. (Form input is not written
            // immediately through to the underlying object.)
            setWriteThrough(false);
        }
    }

    /**
     * This is example on how to customize field creation. Any kind of field
     * components could be created on the fly.
     */
    static class MyFieldFactory extends BaseFieldFactory {

        @Override
        public Field createField(Item item, Object propertyId,
                Component uiContext) {

            Field field = super.createField(item, propertyId, uiContext);

            if ("postalCode".equals(propertyId)) {
                ((TextFieldfield).setColumns(5);
                field.addValidator(new PostalCodeValidator());
            }

            return field;
        }

    }

    /**
     * This is an example of how to create a custom validator for automatic
     * input validation.
     */
    static class PostalCodeValidator implements Validator {

        public boolean isValid(Object value) {
            if (value == null || !(value instanceof String)) {
                return false;
            }

            return ((Stringvalue).matches("[0-9]{5}");
        }

        public void validate(Object valuethrows InvalidValueException {
            if (!isValid(value)) {
                throw new InvalidValueException(
                        "Postal code must be a five digit number.");
            }
        }
    }

    /**
     * Contact information data model created as POJO. Note that in many cases
     * it would be a good idea to implement Item -interface for the datamodel to
     * make it directly bindable to form (without BeanItem wrapper)
     */
    public static class Address {
        String name = "";
        String streetAddress = "";
        String postalCode = "";
        String city;

        public String getAddressAsText() {
            return name + "\n" + streetAddress + "\n" + postalCode + " "
                    (city == null "" : city);
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setStreetAddress(String address) {
            streetAddress = address;
        }

        public String getStreetAddress() {
            return streetAddress;
        }

        public void setPostalCode(String postalCode) {
            this.postalCode = postalCode;
        }

        public String getPostalCode() {
            return postalCode;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getCity() {
            return city;
        }
    }

}