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.field.AbstractSelectFieldDefinition;
38 import info.magnolia.ui.field.SelectFieldSupport;
39 import info.magnolia.ui.datasource.DatasourceDefinition;
40
41 import java.lang.reflect.InvocationTargetException;
42 import java.lang.reflect.Method;
43 import java.util.function.Consumer;
44 import java.util.function.Predicate;
45 import java.util.stream.Stream;
46
47 import javax.inject.Inject;
48
49 import org.apache.commons.lang3.StringUtils;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 import com.vaadin.data.HasDataProvider;
54 import com.vaadin.data.HasFilterableDataProvider;
55 import com.vaadin.data.HasValue;
56 import com.vaadin.data.provider.DataProvider;
57 import com.vaadin.data.provider.DataProviderWrapper;
58 import com.vaadin.data.provider.HierarchicalDataProvider;
59 import com.vaadin.data.provider.HierarchicalQuery;
60 import com.vaadin.data.provider.Query;
61 import com.vaadin.ui.AbstractListing;
62 import com.vaadin.ui.IconGenerator;
63 import com.vaadin.ui.ItemCaptionGenerator;
64
65
66
67
68
69
70
71 public abstract class AbstractSelectFieldFactory<D extends AbstractSelectFieldDefinition<T, DatasourceDefinition>, T> extends AbstractFieldFactory<T, D> {
72
73 protected static final Logger log = LoggerFactory.getLogger(AbstractSelectFieldFactory.class);
74
75 private final SelectFieldSupport<T> selectFieldSupport;
76
77 @Inject
78 public AbstractSelectFieldFactory(D definition, ComponentProvider componentProvider, SelectFieldSupport<T> selectFieldSupport) {
79 super(definition, componentProvider);
80 this.selectFieldSupport = selectFieldSupport;
81 }
82
83 @Override
84 public HasValue<T> createField() {
85 HasValue<T> selectField = super.createField();
86
87 if (selectField instanceof HasDataProvider) {
88 ((HasDataProvider<T>) selectField).setDataProvider(getDataProvider());
89 }
90
91 if (selectField instanceof HasFilterableDataProvider) {
92 ((HasFilterableDataProvider) selectField).setDataProvider(getDataProvider());
93 }
94
95 if (selectField instanceof AbstractListing) {
96 accessGeneratorSetter("setItemCaptionGenerator", ItemCaptionGenerator.class, selectField).accept(getCaptionGenerator());
97 accessGeneratorSetter("setItemIconGenerator", IconGenerator.class, selectField).accept(selectFieldSupport.getIconGenerator());
98 }
99
100 return selectField;
101 }
102
103 protected ItemCaptionGenerator<T> getCaptionGenerator() {
104 return selectFieldSupport.getItemCaptionGenerator();
105 }
106
107 protected DataProvider<T, ?> getDataProvider() {
108 final DataProvider wrappedDataProvider = this.selectFieldSupport.getDataProvider();
109 return new DataProviderWrapper<T, String, Object>(wrappedDataProvider) {
110 @Override
111 protected Object getFilter(Query<T, String> query) {
112 return null;
113 }
114
115 @Override
116 public Stream<T> fetch(Query<T, String> t) {
117 if (dataProvider instanceof HierarchicalDataProvider) {
118 return dataProvider.fetch(new HierarchicalQuery<>(t.getOffset(), t.getLimit(),
119 t.getSortOrders(), t.getInMemorySorting(), null, null)).filter(getFilterPredicate(t));
120 }
121 return super.fetch(t).filter(getFilterPredicate(t));
122 }
123
124 @Override
125 public int size(Query<T, String> t) {
126 return (int) fetch(t).count();
127 }
128
129 private Predicate<T> getFilterPredicate(Query<T, String> t) {
130 switch (getDefinition().getFilteringMode()) {
131 case CONTAINS:
132 return item -> StringUtils.containsIgnoreCase(getCaptionGenerator().apply(item), t.getFilter().orElse(""));
133 case STARTSWITH:
134 return item -> StringUtils.startsWithIgnoreCase(getCaptionGenerator().apply(item), t.getFilter().orElse(""));
135 default:
136 return anEnum -> true;
137 }
138 }
139 };
140 }
141
142
143
144 private <GENERATOR> Consumer<GENERATOR> accessGeneratorSetter(String methodName, Class<GENERATOR> argType, Object field) {
145 try {
146 final Method method = field.getClass().getMethod(methodName, argType);
147 method.setAccessible(true);
148 return generator -> {
149 try {
150 method.invoke(field, generator);
151 } catch (IllegalAccessException | InvocationTargetException e) {
152 log.error("An error occurred while trying to invoke method", e);
153 }
154 };
155 } catch (NoSuchMethodException e) {
156 return generator -> {
157 };
158 } catch (Exception e) {
159 throw new RuntimeException("An error occurred while trying to access method", e);
160 }
161 }
162 }