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.field.factory;
35
36 import info.magnolia.objectfactory.ComponentProvider;
37 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
38 import info.magnolia.ui.contentapp.DataFilter;
39 import info.magnolia.ui.field.AbstractSelectFieldDefinition;
40 import info.magnolia.ui.framework.datasource.DatasourceBundle;
41 import info.magnolia.ui.framework.datasource.DatasourceSupport;
42 import info.magnolia.ui.framework.datasource.components.ItemDescriber;
43 import info.magnolia.ui.framework.datasource.components.SelectedItems;
44
45 import java.lang.reflect.InvocationTargetException;
46 import java.lang.reflect.Method;
47 import java.util.Locale;
48 import java.util.Optional;
49 import java.util.function.Consumer;
50
51 import javax.inject.Inject;
52
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.vaadin.data.HasDataProvider;
57 import com.vaadin.data.HasFilterableDataProvider;
58 import com.vaadin.data.HasValue;
59 import com.vaadin.data.provider.DataProvider;
60 import com.vaadin.ui.AbstractListing;
61 import com.vaadin.ui.Component;
62 import com.vaadin.ui.ItemCaptionGenerator;
63
64
65
66
67
68
69
70
71
72 public abstract class AbstractSelectFieldFactory<DEF, D extends AbstractSelectFieldDefinition<T, DEF>, T, F extends Component & HasValue<T>> extends AbstractFieldFactory<D, T, F> {
73 protected static final Logger log = LoggerFactory.getLogger(AbstractSelectFieldFactory.class);
74
75 private final DatasourceBundle<DEF> dataSourceBundle;
76
77 @Inject
78 public AbstractSelectFieldFactory(ComponentProvider componentProvider, D definition, Locale locale, I18NAuthoringSupport i18NAuthoringSupport, DatasourceSupport datasourceSupport) {
79 super(definition, componentProvider, locale, i18NAuthoringSupport);
80 dataSourceBundle = Optional.ofNullable(definition.getDatasource()).map(datasourceSupport::getDatasourceBundle).orElse(null);
81
82 if (dataSourceBundle == null) {
83 log.info("Select definition named [{}] doesn't provide a datasource. Option values may not be available.", definition.getName());
84 }
85 }
86
87 @Override
88 public F createFieldComponent() {
89 final F selectionField = createSelectionField();
90
91 if (selectionField instanceof HasDataProvider) {
92 getDataProvider().ifPresent(((HasDataProvider<T>) selectionField)::setDataProvider);
93 }
94
95 if (selectionField instanceof HasFilterableDataProvider) {
96 getDataProvider().ifPresent(((HasFilterableDataProvider<T, DataFilter<DEF>>) selectionField)::setDataProvider);
97 }
98
99 if (selectionField instanceof AbstractListing) {
100 getItemDescriber().ifPresent(describer -> {
101 final ItemCaptionGenerator<T> itemCaptionGenerator = item -> describer.describe(SelectedItems.of((T) item));
102 accessItemCaptionGeneratorSetter(selectionField).accept(itemCaptionGenerator);
103 });
104 }
105
106
107 return selectionField;
108 }
109
110
111
112
113 abstract protected F createSelectionField();
114
115 protected Optional<? extends ItemDescriber> getItemDescriber() {
116 return Optional.ofNullable(dataSourceBundle)
117 .flatMap(dsb -> dsb.lookup(ItemDescriber.class, getDefinition().getDatasource()));
118 }
119
120 protected Optional<? extends DataProvider> getDataProvider() {
121 return Optional.ofNullable(dataSourceBundle)
122 .flatMap(bundle -> bundle.lookup(DataProvider.class, getDefinition().getDatasource()))
123
124
125
126 .map(dataProvider -> dataProvider.withConvertedFilter(this::createDataFilter));
127 }
128
129 private DataFilter<DEF> createDataFilter(Object value) {
130 final DataFilter<DEF> filter = new DataFilter<>();
131 filter.setValue(value);
132 filter.setFilteringMode(getDefinition().getFilteringMode());
133 return filter;
134 }
135
136
137
138 private Consumer<ItemCaptionGenerator<T>> accessItemCaptionGeneratorSetter(Object field) {
139 try {
140 final Method method = field.getClass().getMethod("setItemCaptionGenerator", ItemCaptionGenerator.class);
141 method.setAccessible(true);
142 return itemCaptionGenerator -> {
143 try {
144 method.invoke(field, itemCaptionGenerator);
145 } catch (IllegalAccessException | InvocationTargetException e) {
146 log.error("An error occurred while trying to invoke method", e);
147 }
148 };
149 } catch (NoSuchMethodException e) {
150 log.error("An error occurred while trying to access method", e);
151 return itemCaptionGenerator -> {};
152 }
153 }
154 }