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.Classes;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.objectfactory.Components;
40 import info.magnolia.ui.api.app.SubAppContext;
41 import info.magnolia.ui.api.context.UiContext;
42 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
43 import info.magnolia.ui.api.view.View;
44 import info.magnolia.ui.form.AbstractFormItem;
45 import info.magnolia.ui.form.field.converter.Vaadin7FieldValueConverterAdapter;
46 import info.magnolia.ui.form.field.definition.FieldDefinition;
47 import info.magnolia.ui.form.field.definition.TextFieldDefinition;
48 import info.magnolia.ui.form.field.transformer.TransformedProperty;
49 import info.magnolia.ui.form.field.transformer.Transformer;
50 import info.magnolia.ui.form.field.transformer.UndefinedPropertyType;
51 import info.magnolia.ui.form.field.transformer.basic.BasicTransformer;
52 import info.magnolia.ui.form.validator.definition.FieldValidatorDefinition;
53 import info.magnolia.ui.form.validator.factory.FieldValidatorFactory;
54 import info.magnolia.ui.form.validator.registry.FieldValidatorFactoryFactory;
55 import info.magnolia.ui.vaadin.integration.ItemAdapter;
56 import info.magnolia.ui.vaadin.integration.jcr.DefaultPropertyUtil;
57 import info.magnolia.util.EnumCaseInsensitive;
58
59 import java.util.Locale;
60
61 import javax.inject.Inject;
62
63 import org.apache.commons.lang3.StringUtils;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import com.vaadin.server.Sizeable.Unit;
68 import com.vaadin.ui.Component;
69 import com.vaadin.ui.CssLayout;
70 import com.vaadin.v7.data.Item;
71 import com.vaadin.v7.data.Property;
72 import com.vaadin.v7.data.util.BeanItem;
73 import com.vaadin.v7.data.util.ObjectProperty;
74 import com.vaadin.v7.data.util.converter.Converter;
75 import com.vaadin.v7.data.util.converter.ConverterUtil;
76 import com.vaadin.v7.ui.AbstractField;
77 import com.vaadin.v7.ui.Field;
78 import com.vaadin.v7.ui.Label;
79
80
81
82
83
84
85
86
87
88
89
90
91 @Deprecated
92 public abstract class AbstractFieldFactory<D extends FieldDefinition, T> extends AbstractFormItem implements FieldFactory {
93
94 private static final Logger log = LoggerFactory.getLogger(AbstractFieldFactory.class);
95
96 protected Field<T> field;
97 protected D definition;
98 protected Item item;
99
100 private FieldValidatorFactoryFactory fieldValidatorFactoryFactory;
101 private I18NAuthoringSupport i18NAuthoringSupport;
102 private ComponentProvider componentProvider;
103 private UiContext uiContext;
104 private Locale locale;
105 private Converter<?, ?> converter;
106
107 @Inject
108 public AbstractFieldFactory(D definition, Item relatedFieldItem, UiContext uiContext, I18NAuthoringSupport i18NAuthoringSupport) {
109 this.definition = definition;
110 this.item = relatedFieldItem;
111 this.uiContext = uiContext;
112 this.i18NAuthoringSupport = i18NAuthoringSupport;
113 }
114
115
116
117
118 @Deprecated
119 public AbstractFieldFactory(D definition, Item relatedFieldItem) {
120
121
122 this(definition, relatedFieldItem, null, Components.getComponent(I18NAuthoringSupport.class));
123 }
124
125 @Override
126 public void setFieldValidatorFactoryFactory(FieldValidatorFactoryFactory fieldValidatorFactoryFactory) {
127 this.fieldValidatorFactoryFactory = fieldValidatorFactoryFactory;
128 }
129
130
131
132
133
134 @Override
135 @Deprecated
136 public void setI18nContentSupport(I18nContentSupport i18nContentSupport) {
137 }
138
139 @Override
140 public Field<T> createField() {
141 if (locale == null) {
142 if (uiContext instanceof SubAppContext) {
143 final Locale authoringLocale = ((SubAppContext) uiContext).getAuthoringLocale();
144 setLocale(authoringLocale == null ? i18NAuthoringSupport.getDefaultLocale(item) : authoringLocale);
145 }
146 }
147
148 if (field == null) {
149
150 this.field = createFieldComponent();
151
152 if (field instanceof AbstractField) {
153 final AbstractField field = (AbstractField) this.field;
154 if (definition.getConverterClass() != null) {
155 Converter<?, ?> converter = initializeConverter(definition.getConverterClass());
156 if (!field.getType().isAssignableFrom(converter.getModelType())) {
157
158
159 field.setConverter(converter);
160 }
161 }
162 field.setLocale(locale);
163 }
164
165 Property<?> property = initializeProperty();
166
167 setPropertyDataSourceAndDefaultValue(property);
168
169 if (StringUtils.isNotBlank(definition.getStyleName())) {
170 this.field.addStyleName(definition.getStyleName());
171 }
172
173 field.setWidth(100, Unit.PERCENTAGE);
174
175 setFieldCaption();
176 setConstraints();
177
178 }
179 return this.field;
180 }
181
182
183 private void setFieldCaption() {
184
185 if (StringUtils.isNotBlank(getFieldDefinition().getLabel())) {
186 String caption = getFieldDefinition().getLabel();
187
188 if (locale != null && definition.isI18n()) {
189 caption = String.format("%s (%s)", caption, locale.toString());
190 }
191
192 this.field.setCaption(caption);
193 }
194 }
195
196
197
198
199
200
201
202
203 public void setPropertyDataSourceAndDefaultValue(Property property) {
204 this.field.setPropertyDataSource(property);
205
206 if ((item instanceof ItemAdapterItemAdapterinfo/magnolia/ui/vaadin/integration/ItemAdapter.html#ItemAdapter">ItemAdapter && ((ItemAdapterItemAdapterNew() && property.getValue() == null) || (!(item instanceof ItemAdapter) && property.getValue() == null)) {
207 setPropertyDataSourceDefaultValue(property);
208 }
209 }
210
211
212
213
214 protected void setPropertyDataSourceDefaultValue(Property property) {
215 Object defaultValue = createDefaultValue(property);
216 if (defaultValue != null && !property.isReadOnly()) {
217 if (property.getType().isAssignableFrom(defaultValue.getClass())) {
218 property.setValue(defaultValue);
219 } else {
220 log.warn("Default value {} cannot be assigned to property of type {}.", defaultValue, property.getType());
221 }
222 }
223 }
224
225 protected Object createDefaultValue(Property property) {
226 Object defaultValue = getConfiguredDefaultValue();
227 Class<?> propertyType = property != null ? property.getType() : getFieldType();
228 return createTypedValue(defaultValue, propertyType);
229 }
230
231
232
233
234
235 protected Object createTypedValue(Object defaultValue, Class<?> propertyType) {
236
237 if (defaultValue instanceof String && DefaultPropertyUtil.canConvertStringValue(propertyType)) {
238 return DefaultPropertyUtil.createTypedValue(propertyType, (String) defaultValue);
239
240 } else if (defaultValue != null && definition.getConverterClass() != null) {
241
242
243 Converter converter = initializeConverter(definition.getConverterClass());
244 Class<?> modelType = propertyType != null ? propertyType : converter.getModelType();
245 Locale locale = Locale.ENGLISH;
246 try {
247 defaultValue = ConverterUtil.convertToModel(defaultValue, modelType, converter, locale);
248 } catch (Converter.ConversionException e) {
249 log.error("Default value {} could not be converted to property type {}.", defaultValue, propertyType, e);
250 }
251
252 } else if (propertyType != null && propertyType.isEnum() && defaultValue instanceof String) {
253 Class<? extends Enum> enumType = (Class<? extends Enum>) propertyType;
254 EnumCaseInsensitive enumFinder = new EnumCaseInsensitive();
255 defaultValue = enumFinder.valueOf(enumType, (String) defaultValue);
256 }
257
258 return defaultValue;
259 }
260
261
262
263
264
265
266 protected Object getConfiguredDefaultValue() {
267 return definition.getDefaultValue();
268 }
269
270 @Override
271 public D getFieldDefinition() {
272 return this.definition;
273 }
274
275
276
277
278 protected abstract Field<T> createFieldComponent();
279
280 @Override
281 public View getView() {
282 final CssLayout fieldView = new CssLayout();
283 fieldView.setStyleName("field-view");
284
285 Label label = new Label();
286 label.setSizeUndefined();
287 label.setCaption(getFieldDefinition().getLabel());
288
289 if (getFieldDefinition().getClass().isAssignableFrom(TextFieldDefinition.class)) {
290 final TextFieldDefinitionnolia/ui/form/field/definition/TextFieldDefinition.html#TextFieldDefinition">TextFieldDefinition textFieldDefinition = (TextFieldDefinition) getFieldDefinition();
291 if (textFieldDefinition.getRows() > 0) {
292 label.addStyleName("textarea");
293 }
294 }
295 if (definition.getConverterClass() != null) {
296 Converter converter = initializeConverter(definition.getConverterClass());
297 label.setConverter(converter);
298 }
299
300 Property<?> property = initializeProperty();
301
302 label.setPropertyDataSource(property);
303
304 fieldView.addComponent(label);
305
306 return new View() {
307 @Override
308 public Component asVaadinComponent() {
309 return fieldView;
310 }
311 };
312 }
313
314
315
316
317
318 @SuppressWarnings("unchecked")
319 protected Property<T> initializeProperty() {
320
321 boolean useTransformers = !(item instanceof BeanItem);
322
323 if (useTransformers) {
324 Class<? extends Transformer<?>> transformerClass = definition.getTransformerClass();
325 if (transformerClass == null) {
326
327
328
329
330 transformerClass = (Class<? extends Transformer<?>>) (Object) BasicTransformer.class;
331 }
332 Transformer<?> transformer = initializeTransformer(transformerClass);
333 transformer.setLocale(locale);
334 return new TransformedProperty(transformer);
335
336 } else {
337
338 Property property = item.getItemProperty(definition.getName());
339 if (property == null) {
340 log.warn(String.format("BeanItem doesn't have any property for id %s, returning default property", definition.getName()));
341 Class<?> propertyType = DefaultPropertyUtil.getFieldTypeClass(definition.getType());
342 property = new ObjectProperty<>(null, propertyType);
343 item.addItemProperty(definition.getName(), property);
344 }
345 return property;
346 }
347 }
348
349
350
351
352
353 protected Transformer<?> initializeTransformer(Class<? extends Transformer<?>> transformerClass) {
354 return this.componentProvider.newInstance(transformerClass, item, definition, getFieldType(), i18NAuthoringSupport);
355 }
356
357
358
359
360
361 protected Converter<?, ?> initializeConverter(Class<?> converterClass) {
362 if (converter == null) {
363 converter = Vaadin7FieldValueConverterAdapter.wrap(componentProvider.newInstance(converterClass));
364 }
365 return converter;
366 }
367
368
369
370
371
372
373
374
375 protected Class<?> getFieldType() {
376 Class<?> type = getDefinitionType();
377 if (type == null && definition.getConverterClass() != null) {
378 Converter converter = initializeConverter(definition.getConverterClass());
379 type = converter.getModelType();
380 }
381 if (type == null) {
382 type = getDefaultFieldType();
383 }
384 return type;
385 }
386
387
388
389
390 protected Class<?> getDefinitionType() {
391 if (StringUtils.isNotBlank(definition.getType())) {
392 if (DefaultPropertyUtil.isKnownJcrTypeName(definition.getType())) {
393 return DefaultPropertyUtil.getFieldTypeClass(definition.getType());
394 } else try {
395 return Classes.getClassFactory().forName(definition.getType());
396 } catch (ClassNotFoundException e) {
397 log.warn("Unknown configured type {}", definition.getType());
398 }
399 }
400 return null;
401 }
402
403
404
405
406 protected Class<?> getDefaultFieldType() {
407 return UndefinedPropertyType.class;
408 }
409
410 @Override
411 protected String getI18nBasename() {
412 return definition.getI18nBasename();
413 }
414
415
416
417
418
419
420 protected boolean isMessageKey(String key) {
421 return !StringUtils.endsWith(key, ".") && StringUtils.contains(key, ".") && !StringUtils.contains(key, " ");
422 }
423
424
425
426
427
428
429
430 private void setConstraints() {
431
432 for (FieldValidatorDefinition validatorDefinition : definition.getValidators()) {
433 FieldValidatorFactory validatorFactory = this.fieldValidatorFactoryFactory.createFieldValidatorFactory(validatorDefinition, item);
434 if (validatorFactory != null) {
435 field.addValidator(validatorFactory.createValidator());
436 } else {
437 log.warn("Not able to create Validation for the following definition {}", definition.toString());
438 }
439 }
440
441 if (definition.isRequired()) {
442 field.setInvalidCommitted(true);
443 field.setRequired(true);
444 field.setRequiredError(definition.getRequiredErrorMessage());
445 }
446
447
448
449
450 if (definition.isReadOnly()) {
451 field.setReadOnly(true);
452 }
453 }
454
455 @Override
456 public void setComponentProvider(ComponentProvider componentProvider) {
457 this.componentProvider = componentProvider;
458 if (uiContext == null) {
459 uiContext = componentProvider.getComponent(UiContext.class);
460 }
461 }
462
463 protected ComponentProvider getComponentProvider() {
464 return componentProvider;
465 }
466
467 public void setLocale(Locale locale) {
468 this.locale = locale;
469 }
470
471 public Locale getLocale() {
472 return locale;
473 }
474 }