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 if (StringUtils.isNotBlank(getFieldDefinition().getLabel())) {
122 this.field.setCaption(getFieldDefinition().getLabel() + (getFieldDefinition().isRequired() ? "<span class=\"requiredfield\">*</span>" : ""));
123 }
124
125 setConstraints();
126
127 }
128 return this.field;
129 }
130
131
132
133
134
135
136
137
138 public void setPropertyDataSourceAndDefaultValue(Property<?> property) {
139 this.field.setPropertyDataSource(property);
140
141 if ((item instanceof ItemAdapter && ((ItemAdapter) item).isNew()) || (!(item instanceof ItemAdapter) && property.getValue() == null)) {
142 setPropertyDataSourceDefaultValue(property);
143 }
144 }
145
146
147
148
149 protected void setPropertyDataSourceDefaultValue(Property property) {
150 Object defaultValue = createDefaultValue(property);
151 if (defaultValue != null && !definition.isReadOnly()) {
152 if (defaultValue.getClass().isAssignableFrom(property.getType())) {
153 property.setValue(defaultValue);
154 } else {
155 log.warn("Default value {} is not assignable to the field of type {}.", defaultValue, field.getPropertyDataSource().getType().getName());
156 }
157 }
158 }
159
160
161
162
163 protected Object createDefaultValue(Property<?> property) {
164 String defaultValue = definition.getDefaultValue();
165 if (StringUtils.isNotBlank(defaultValue)) {
166 return DefaultPropertyUtil.createTypedValue(property.getType(), defaultValue);
167 }
168 return null;
169 }
170
171 @Override
172 public D getFieldDefinition() {
173 return this.definition;
174 }
175
176
177
178
179 protected abstract Field<T> createFieldComponent();
180
181 @Override
182 public View getView() {
183 Property<?> property = initializeProperty();
184
185 final CssLayout fieldView = new CssLayout();
186 fieldView.setStyleName("field-view");
187
188 Label label = new Label();
189 label.setSizeUndefined();
190 label.setCaption(getFieldDefinition().getLabel());
191
192 if (getFieldDefinition().getClass().isAssignableFrom(TextFieldDefinition.class)) {
193 final TextFieldDefinition textFieldDefinition = (TextFieldDefinition) getFieldDefinition();
194 if (textFieldDefinition.getRows() > 0) {
195 label.addStyleName("textarea");
196 }
197 }
198 label.setPropertyDataSource(property);
199
200 fieldView.addComponent(label);
201
202 return new View() {
203 @Override
204 public Component asVaadinComponent() {
205 return fieldView;
206 }
207 };
208 }
209
210
211
212
213
214 @SuppressWarnings("unchecked")
215 private Property<?> initializeProperty() {
216 Class<? extends Transformer<?>> transformerClass = definition.getTransformerClass();
217
218 if (transformerClass == null) {
219
220 transformerClass = (Class<? extends Transformer<?>>) (Object) BasicTransformer.class;
221 }
222 Transformer<?> transformer = initializeTransformer(transformerClass);
223
224 return new TransformedProperty(transformer);
225 }
226
227
228
229
230
231 protected Transformer<?> initializeTransformer(Class<? extends Transformer<?>> transformerClass) {
232 return this.componentProvider.newInstance(transformerClass, item, definition, getFieldType());
233 }
234
235
236
237
238
239
240
241
242 protected Class<?> getFieldType() {
243 Class<?> type = getDefinitionType();
244 if (type == null) {
245 type = getDefaultFieldType();
246 }
247 return type;
248 }
249
250
251
252
253 protected Class<?> getDefinitionType() {
254 if (StringUtils.isNotBlank(definition.getType())) {
255 return DefaultPropertyUtil.getFieldTypeClass(definition.getType());
256 }
257 return null;
258 }
259
260
261
262
263 protected Class<?> getDefaultFieldType() {
264 return UndefinedPropertyType.class;
265 }
266
267 @Override
268 protected String getI18nBasename() {
269 return definition.getI18nBasename();
270 }
271
272
273
274
275
276
277
278 private void setConstraints() {
279
280 for (FieldValidatorDefinition validatorDefinition : definition.getValidators()) {
281 FieldValidatorFactory validatorFactory = this.fieldValidatorFactoryFactory.createFieldValidatorFactory(validatorDefinition, item);
282 if (validatorFactory != null) {
283 field.addValidator(validatorFactory.createValidator());
284 } else {
285 log.warn("Not able to create Validation for the following definition {}", definition.toString());
286 }
287 }
288
289 if (definition.isRequired()) {
290 field.setInvalidCommitted(true);
291 field.setRequired(true);
292 field.setRequiredError(definition.getRequiredErrorMessage());
293 }
294
295
296 if (field.getPropertyDataSource() != null) {
297 field.getPropertyDataSource().setReadOnly(definition.isReadOnly());
298 }
299 }
300
301 @Override
302 public void setComponentProvider(ComponentProvider componentProvider) {
303 this.componentProvider = componentProvider;
304 }
305
306
307
308
309
310
311
312
313 @Deprecated
314 private static class StringToLongConverter extends AbstractStringToNumberConverter<Long> {
315
316 @Override
317 public Long convertToModel(String value, Class<? extends Long> targetType, Locale locale) throws ConversionException {
318 Number n = convertToNumber(value, targetType, locale);
319 return n == null ? null : n.longValue();
320 }
321
322 @Override
323 public Class<Long> getModelType() {
324 return Long.class;
325 }
326 }
327
328 }