1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.form.field.factory;
35
36 import info.magnolia.cms.i18n.I18nContentSupport;
37 import info.magnolia.objectfactory.ComponentProvider;
38 import info.magnolia.ui.api.view.View;
39 import info.magnolia.ui.form.AbstractFormItem;
40 import info.magnolia.ui.form.field.definition.FieldDefinition;
41 import info.magnolia.ui.form.field.definition.TextFieldDefinition;
42 import info.magnolia.ui.form.field.transformer.TransformedProperty;
43 import info.magnolia.ui.form.field.transformer.Transformer;
44 import info.magnolia.ui.form.field.transformer.UndefinedPropertyType;
45 import info.magnolia.ui.form.field.transformer.basic.BasicTransformer;
46 import info.magnolia.ui.form.validator.definition.FieldValidatorDefinition;
47 import info.magnolia.ui.form.validator.factory.FieldValidatorFactory;
48 import info.magnolia.ui.form.validator.registry.FieldValidatorFactoryFactory;
49 import info.magnolia.ui.vaadin.integration.ItemAdapter;
50 import info.magnolia.ui.vaadin.integration.jcr.DefaultPropertyUtil;
51
52 import java.util.Locale;
53
54 import org.apache.commons.lang.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 import com.vaadin.data.Item;
59 import com.vaadin.data.Property;
60 import com.vaadin.data.util.converter.AbstractStringToNumberConverter;
61 import com.vaadin.server.Sizeable.Unit;
62 import com.vaadin.ui.AbstractTextField;
63 import com.vaadin.ui.Component;
64 import com.vaadin.ui.CssLayout;
65 import com.vaadin.ui.Field;
66 import com.vaadin.ui.Label;
67
68
69
70
71
72
73
74
75 public abstract class AbstractFieldFactory<D extends FieldDefinition, T> extends AbstractFormItem implements FieldFactory {
76 private static final Logger log = LoggerFactory.getLogger(AbstractFieldFactory.class);
77 protected Item item;
78 protected Field<T> field;
79 protected D definition;
80 private FieldValidatorFactoryFactory fieldValidatorFactoryFactory;
81 private I18nContentSupport i18nContentSupport;
82 private ComponentProvider componentProvider;
83
84 public AbstractFieldFactory(D definition, Item relatedFieldItem) {
85 this.definition = definition;
86 this.item = relatedFieldItem;
87 }
88
89 @Override
90 public void setFieldValidatorFactoryFactory(FieldValidatorFactoryFactory fieldValidatorFactoryFactory) {
91 this.fieldValidatorFactoryFactory = fieldValidatorFactoryFactory;
92 }
93
94 @Override
95 public void setI18nContentSupport(I18nContentSupport i18nContentSupport) {
96 this.i18nContentSupport = i18nContentSupport;
97 }
98
99 @Override
100 public Field<T> createField() {
101 if (field == null) {
102
103 this.field = createFieldComponent();
104
105 Property<?> property = initializeProperty();
106
107
108 if (Long.class.equals(property.getType()) && field instanceof AbstractTextField) {
109 ((AbstractTextField) field).setConverter(new StringToLongConverter());
110 }
111
112 setPropertyDataSourceAndDefaultValue(property);
113
114 if (StringUtils.isNotBlank(definition.getStyleName())) {
115 this.field.addStyleName(definition.getStyleName());
116 }
117
118 field.setWidth(100, Unit.PERCENTAGE);
119
120
121 this.field.setCaption(getFieldDefinition().getLabel() + (getFieldDefinition().isRequired() ? "<span class=\"requiredfield\">*</span>" : ""));
122
123 setConstraints();
124
125 }
126 return this.field;
127 }
128
129
130
131
132
133
134
135
136 public void setPropertyDataSourceAndDefaultValue(Property<?> property) {
137 this.field.setPropertyDataSource(property);
138
139 if ((item instanceof ItemAdapter && ((ItemAdapter) item).isNew()) || !(item instanceof ItemAdapter)) {
140 setPropertyDataSourceDefaultValue(property);
141 }
142 }
143
144
145
146
147 protected void setPropertyDataSourceDefaultValue(Property property) {
148 Object defaultValue = createDefaultValue(property);
149 if (defaultValue != null && !definition.isReadOnly()) {
150 if (defaultValue.getClass().isAssignableFrom(property.getType())) {
151 property.setValue(defaultValue);
152 } else {
153 log.warn("Default value {} is not assignable to the field of type {}.", defaultValue, field.getPropertyDataSource().getType().getName());
154 }
155 }
156 }
157
158
159
160
161 protected Object createDefaultValue(Property<?> property) {
162 String defaultValue = definition.getDefaultValue();
163 if (StringUtils.isNotBlank(defaultValue)) {
164 return DefaultPropertyUtil.createTypedValue(property.getType(), defaultValue);
165 }
166 return null;
167 }
168
169 @Override
170 public D getFieldDefinition() {
171 return this.definition;
172 }
173
174
175
176
177 protected abstract Field<T> createFieldComponent();
178
179 @Override
180 public View getView() {
181 Property<?> property = initializeProperty();
182
183 final CssLayout fieldView = new CssLayout();
184 fieldView.setStyleName("field-view");
185
186 Label label = new Label();
187 label.setSizeUndefined();
188 label.setCaption(getFieldDefinition().getLabel());
189
190 if (getFieldDefinition().getClass().isAssignableFrom(TextFieldDefinition.class)) {
191 final TextFieldDefinition textFieldDefinition = (TextFieldDefinition) getFieldDefinition();
192 if (textFieldDefinition.getRows() > 0) {
193 label.addStyleName("textarea");
194 }
195 }
196 label.setPropertyDataSource(property);
197
198 fieldView.addComponent(label);
199
200 return new View() {
201 @Override
202 public Component asVaadinComponent() {
203 return fieldView;
204 }
205 };
206 }
207
208
209
210
211
212 @SuppressWarnings("unchecked")
213 private Property<?> initializeProperty() {
214 Class<? extends Transformer<?>> transformerClass = definition.getTransformerClass();
215
216 if (transformerClass == null) {
217
218 transformerClass = (Class<? extends Transformer<?>>) (Object) BasicTransformer.class;
219 }
220 Transformer<?> transformer = initializeTransformer(transformerClass);
221
222 return new TransformedProperty(transformer);
223 }
224
225
226
227
228
229 protected Transformer<?> initializeTransformer(Class<? extends Transformer<?>> transformerClass) {
230 return this.componentProvider.newInstance(transformerClass, item, definition, getFieldType());
231 }
232
233
234
235
236
237
238
239
240 protected Class<?> getFieldType() {
241 Class<?> type = getDefinitionType();
242 if (type == null) {
243 type = getDefaultFieldType();
244 }
245 return type;
246 }
247
248
249
250
251 protected Class<?> getDefinitionType() {
252 if (StringUtils.isNotBlank(definition.getType())) {
253 return DefaultPropertyUtil.getFieldTypeClass(definition.getType());
254 }
255 return null;
256 }
257
258
259
260
261 protected Class<?> getDefaultFieldType() {
262 return UndefinedPropertyType.class;
263 }
264
265 @Override
266 protected String getI18nBasename() {
267 return definition.getI18nBasename();
268 }
269
270
271
272
273
274
275
276 private void setConstraints() {
277
278 for (FieldValidatorDefinition validatorDefinition : definition.getValidators()) {
279 FieldValidatorFactory validatorFactory = this.fieldValidatorFactoryFactory.createFieldValidatorFactory(validatorDefinition, item);
280 if (validatorFactory != null) {
281 this.field.addValidator(validatorFactory.createValidator());
282 } else {
283 log.warn("Not able to create Validation for the following definition {}", definition.toString());
284 }
285 }
286
287 if (definition.isRequired()) {
288 field.setRequired(true);
289 field.setRequiredError(definition.getRequiredErrorMessage());
290 }
291
292
293 if (field.getPropertyDataSource() != null) {
294 field.getPropertyDataSource().setReadOnly(definition.isReadOnly());
295 }
296 }
297
298 @Override
299 public void setComponentProvider(ComponentProvider componentProvider) {
300 this.componentProvider = componentProvider;
301 }
302
303
304
305
306
307
308
309
310 @Deprecated
311 private static class StringToLongConverter extends AbstractStringToNumberConverter<Long> {
312
313 @Override
314 public Long convertToModel(String value, Class<? extends Long> targetType, Locale locale) throws ConversionException {
315 Number n = convertToNumber(value, targetType, locale);
316 return n == null ? null : n.longValue();
317 }
318
319 @Override
320 public Class<Long> getModelType() {
321 return Long.class;
322 }
323 }
324
325 }