/* * Copyright 2009 Andrew Pietsch * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions * and limitations under the License. */ package com.dragome.forms.bindings.client.form; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import com.dragome.forms.bindings.client.format.Format; import com.dragome.forms.bindings.client.value.ValueModel; import com.dragome.model.interfaces.list.ListModel; /** * <p> * FormModel provides builders for creating {@link FieldModel}s, {@link FormattedFieldModel}s * and {@link ListFieldModel}. Widgets can then be bound to these models using a {@link com.pietschy.gwt.pectin.client.form.binding.FormBinder}. * </p> * <p> * FormModels also allow support properties to allow plugins to store additional * information and {@link BindingCallback}s to hook into the binding process. * </p> * * @see #fieldOfType(Class) * @see #formattedFieldOfType(Class) * @see #listOfType(Class) */ public class FormModel { private HashMap<Object, Object> properties= new HashMap<Object, Object>(); private ArrayList<BindingCallback> bindingCallbacks= new ArrayList<BindingCallback>(); private ArrayList<Field<?>> allFields= new ArrayList<Field<?>>(); /** * Returns a {@link FieldModel} buider of the specified type. * * @param type the value type held by the field. * @return a builder for the specified type. */ public <T> FieldBuilder<T> fieldOfType(Class<T> type) { return new FieldBuilder<T>(this, type); } /** * Returns a {@link FormattedFieldModel} builder for the specified type. * * @param type the value type held by the field. * @return a builder for the specified type. */ public <T> FormattedFieldFormatBuilder<T> formattedFieldOfType(Class<T> type) { return new FormattedFieldFormatBuilder<T>(this, type); } /** * Returns a {@link ListFieldModel} builder for the specified type. * * @param type the value type held by the list. * @return a builder for the specified type. */ public <T> ListFieldBindingBuilder<T> listOfType(Class<T> type) { return new ListFieldBindingBuilder<T>(this, type); } /** * Returns a {@link FormattedListFieldModel} builder for the specified type. * * @param type the value type held by the list. * @return a builder for the specified type. */ public <T> FormattedListFieldFormatBuilder<T> formattedListOfType(Class<T> type) { return new FormattedListFieldFormatBuilder<T>(this, type); } /** * Returns all the fields in this form model at the time this method is called. Fields added * after this method is invoked will not be included in the collection. * <p/> * Fields are in the order they are added to the form. * * @return a collection of the fields in this model. */ public Collection<Field<?>> allFields() { // It may be tempting to include a live collection of the fields so that the notion of // "all fields" is true no matter when the method was used to construct an expression // This however would cause problems as most bindings take some initialisation action // when a new field is added. // // Thus if we want this method to return a live collection then we will need to: // a) make the collection observable (i.e. make it a ListModel) // b) ensure all bindings that take a collection of fields observe the collection and // ensure new additions to it are initialised appropriately. // // but for now we return a copy. return new ArrayList<Field<?>>(allFields); } /** * Returns all the fields in this form model at the time this method is called except those * specified. Fields added after this method is invoked will not be included in the collection. * <p/> * Fields are in the order they are added to the form. * * @return a collection of the fields in this model. */ public Collection<Field<?>> allFieldsExcept(Field<?> first, Field<?>... others) { // See the notes in allFields() for details on why I haven't got around to // creating a live collections. ArrayList<Field<?>> list= new ArrayList<Field<?>>(allFields); list.remove(first); for (Field<?> other : others) { list.remove(other); } return list; } /** * Factory method for creating field model instances. This method is invoked by the field model * builder and is provided so subclasses can override the specific type that is returned. * * @param model the source value model. * @param valueType the type of the value held by this model. * @return a new field model */ protected <T> FieldModel<T> createFieldModel(ValueModel<T> model, Class<T> valueType) { FieldModelImpl<T> field= new FieldModelImpl<T>(this, model, valueType); allFields.add(field); return field; } /** * Factory method for creating field model instances. This method is invoked by the field model * builder and is provided so subclasses can override the specific type that is returned. * * @param source the source value model. * @param format the format to use * @param exceptionPolicy the policy for handling format exceptions. * @param valueType the type of the value held by this model. * @return a new field model */ protected <T> FormattedFieldModel<T> createFormattedFieldModel(ValueModel<T> source, Format<T> format, FormatExceptionPolicy<T> exceptionPolicy, Class<T> valueType) { FormattedFieldModelImpl<T> field= new FormattedFieldModelImpl<T>(this, source, format, exceptionPolicy, valueType); allFields.add(field); return field; } /** * Factory method for creating field model instances. This method is invoked by the field model * builder and is provided so subclasses can override the specific type that is returned. * * @param source the source value model. * @param valueType the type of the value held by this model. * @return a new field model */ protected <T> ListFieldModel<T> createListModel(ListModel<T> source, Class<T> valueType) { ListFieldModelImpl<T> field= new ListFieldModelImpl<T>(this, source, valueType); allFields.add(field); return field; } /** * Factory method for creating field model instances. This method is invoked by the field model * builder and is provided so subclasses can override the specific type that is returned. * * @param source the source value model. * @param format the format to use * @param exceptionPolicy the policy for handling format exceptions. * @param valueType the type of the value held by this model. * @return a new field model */ public <T> FormattedListFieldModel<T> createFormattedListFieldModel(ListModel<T> source, Format<T> format, ListFormatExceptionPolicy<T> exceptionPolicy, Class<T> valueType) { return new FormattedListFieldModelImpl<T>(this, source, format, exceptionPolicy, valueType); } public void putProperty(Object key, Object value) { properties.put(key, value); } public Object getProperty(Object key) { return properties.get(key); } public void addBindingCallback(BindingCallback callback) { bindingCallbacks.add(callback); } public Collection<BindingCallback> getBindingCallbacks() { return Collections.unmodifiableCollection(bindingCallbacks); } }