001 // Copyright 2007, 2008, 2009 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry5.corelib.components;
016
017 import org.apache.tapestry5.*;
018 import org.apache.tapestry5.annotations.*;
019 import org.apache.tapestry5.beaneditor.BeanModel;
020 import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
021 import org.apache.tapestry5.ioc.annotations.Inject;
022 import org.apache.tapestry5.services.BeanModelSource;
023
024 /**
025 * A component that creates an entire form editing the properties of a particular bean. Inspired by <a
026 * href="http://www.trailsframework.org/">Trails</a> and <a href="http://beanform.sourceforge.net/">BeanForm</a> (both
027 * for Tapestry 4). Generates a simple UI for editing the properties of a JavaBean, with the flavor of UI for each
028 * property (text field, checkbox, drop down list) determined from the property type (or by other means, such as an
029 * annotation), and the order and validation for the properties determined from annotations on the property's getter and
030 * setter methods.
031 * <p/>
032 * You may add block parameters to the component; when the name matches (case insensitive) the name of a property, then
033 * the corresponding Block is renderered, rather than any of the built in property editor blocks. This allows you to
034 * override specific properties with your own customized UI, for cases where the default UI is insufficient, or no
035 * built-in editor type is appropriate.
036 * <p/>
037 * BeanEditForm contains a {@link org.apache.tapestry5.corelib.components.Form} component and will trigger all the
038 * events of a Form.
039 *
040 * @see org.apache.tapestry5.beaneditor.BeanModel
041 * @see org.apache.tapestry5.services.BeanModelSource
042 * @see org.apache.tapestry5.corelib.components.PropertyEditor
043 * @see org.apache.tapestry5.beaneditor.DataType
044 */
045 @SupportsInformalParameters
046 @Events(EventConstants.PREPARE)
047 public class BeanEditForm implements ClientElement, FormValidationControl
048 {
049
050 /**
051 * The text label for the submit button of the form, by default "Create/Update".
052 */
053 @Parameter(value = "message:submit-label", defaultPrefix = BindingConstants.LITERAL)
054 @Property
055 private String submitLabel;
056
057 /**
058 * The object to be edited. This will be read when the component renders and updated when the form for the component
059 * is submitted. Typically, the container will listen for a "prepare" event, in order to ensure that a non-null
060 * value is ready to be read or updated. Often, the BeanEditForm can create the object as needed (assuming a public,
061 * no arguments constructor). The object property defaults to a property with the same name as the component id.
062 */
063 @Parameter(required = true, autoconnect = true)
064 @Property
065 private Object object;
066
067 /**
068 * A comma-separated list of property names to be retained from the {@link org.apache.tapestry5.beaneditor.BeanModel}.
069 * Only these properties will be retained, and the properties will also be reordered. The names are
070 * case-insensitive.
071 */
072 @SuppressWarnings("unused")
073 @Parameter(defaultPrefix = BindingConstants.LITERAL)
074 private String include;
075
076 /**
077 * A comma-separated list of property names to be added to the {@link org.apache.tapestry5.beaneditor.BeanModel}.
078 */
079 @Parameter(defaultPrefix = BindingConstants.LITERAL)
080 private String add;
081
082 /**
083 * A comma-separated list of property names to be removed from the {@link org.apache.tapestry5.beaneditor.BeanModel}.
084 * The names are case-insensitive.
085 */
086 @SuppressWarnings("unused")
087 @Parameter(defaultPrefix = BindingConstants.LITERAL)
088 private String exclude;
089
090 /**
091 * A comma-separated list of property names indicating the order in which the properties should be presented. The
092 * names are case insensitive. Any properties not indicated in the list will be appended to the end of the display
093 * order.
094 */
095 @SuppressWarnings("unused")
096 @Parameter(defaultPrefix = BindingConstants.LITERAL)
097 private String reorder;
098
099 @Component(parameters =
100 "validationId=componentResources.id", publishParameters = "clientValidation,autofocus,zone")
101 private Form form;
102
103 /**
104 * The model that identifies the parameters to be edited, their order, and every other aspect. If not specified, a
105 * default bean model will be created from the type of the object bound to the object parameter.
106 */
107 @SuppressWarnings("unused")
108 @Parameter
109 @Property
110 private BeanModel model;
111
112 @Inject
113 private ComponentResources resources;
114
115 @Inject
116 private BeanModelSource beanModelSource;
117
118
119 void onPrepareFromForm()
120 {
121 resources.triggerEvent(EventConstants.PREPARE, null, null);
122
123 if (model == null)
124 {
125 Class beanType = resources.getBoundType("object");
126
127 model = beanModelSource.createEditModel(beanType, resources.getContainerMessages());
128 }
129
130 BeanModelUtils.modify(model, add, include, exclude, reorder);
131 }
132
133
134 /**
135 * Returns the client id of the embedded form.
136 */
137 public String getClientId()
138 {
139 return form.getClientId();
140 }
141
142 public void clearErrors()
143 {
144 form.clearErrors();
145 }
146
147 public boolean getHasErrors()
148 {
149 return form.getHasErrors();
150 }
151
152 public boolean isValid()
153 {
154 return form.isValid();
155 }
156
157 public void recordError(Field field, String errorMessage)
158 {
159 form.recordError(field, errorMessage);
160 }
161
162 public void recordError(String errorMessage)
163 {
164 form.recordError(errorMessage);
165 }
166 }