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.contentapp.browser;
35
36 import static java.util.function.Function.identity;
37 import static java.util.stream.Collectors.toMap;
38
39 import info.magnolia.objectfactory.ComponentProvider;
40 import info.magnolia.ui.api.availability.AvailabilityChecker;
41 import info.magnolia.ui.contentapp.DataFilter;
42 import info.magnolia.ui.contentapp.configuration.ContentViewDefinition;
43 import info.magnolia.ui.contentapp.configuration.column.ColumnDefinition;
44 import info.magnolia.ui.contentapp.configuration.column.ColumnEditorDefinition;
45 import info.magnolia.ui.framework.databinding.ConfiguredBinder;
46 import info.magnolia.ui.field.FieldDefinition;
47 import info.magnolia.ui.field.factory.FormFieldFactory;
48 import info.magnolia.ui.framework.datasource.DatasourceComponent;
49 import info.magnolia.ui.framework.datasource.components.PropertySetFactory;
50 import info.magnolia.ui.framework.ioc.Destructible;
51
52 import java.util.Collections;
53 import java.util.LinkedHashMap;
54 import java.util.Locale;
55 import java.util.Map;
56 import java.util.Objects;
57 import java.util.Optional;
58
59 import javax.inject.Inject;
60
61 import com.vaadin.data.Binder;
62 import com.vaadin.data.HasValue;
63 import com.vaadin.data.PropertyDefinition;
64 import com.vaadin.data.PropertySet;
65 import com.vaadin.data.ValueProvider;
66 import com.vaadin.data.provider.DataProvider;
67 import com.vaadin.ui.CustomComponent;
68 import com.vaadin.ui.Grid;
69 import com.vaadin.ui.renderers.AbstractRenderer;
70
71
72
73
74
75 public class ListPresenter<T> extends CustomComponent implements ContentView, Destructible {
76
77 private final AvailabilityChecker availabilityChecker;
78 private final DataProvider<T, DataFilter> dataProvider;
79 private final ComponentProvider componentProvider;
80 private final Map<ColumnDefinition, AbstractRenderer> columns;
81 private final FormFieldFactory formFieldFactory;
82 private final ContentViewDefinition<T> definition;
83 private PropertySet<T> propertySet;
84
85 @Inject
86 public ListPresenter(
87 ComponentProvider componentProvider,
88 ContentViewDefinition<T> definition,
89 FormFieldFactory formFieldFactory,
90 AvailabilityChecker availabilityChecker,
91
92 @DatasourceComponent DataProvider<T, DataFilter> dataProvider,
93 @DatasourceComponent PropertySetFactory<T> propertySetFactory) {
94 this.availabilityChecker = availabilityChecker;
95 this.definition = definition;
96
97 this.dataProvider = dataProvider;
98 this.componentProvider = componentProvider;
99 this.columns = definition
100 .getColumns().stream()
101 .collect(toMap(identity(), this::createRenderer, (e1, e2) -> e1, LinkedHashMap::new));
102 this.formFieldFactory = formFieldFactory;
103
104 this.propertySet = propertySetFactory.withProperties(columns.entrySet().stream().collect(toMap(e -> e.getKey().getName(), e -> e.getValue().getPresentationType())));
105 }
106
107 private AbstractRenderer createRenderer(ColumnDefinition<T> columnDefinition) {
108 return this.componentProvider.newInstance(columnDefinition.getRenderer());
109 }
110
111 PropertySet<T> getPropertySet() {
112 return propertySet;
113 }
114
115 void createColumns(Grid<T> grid) {
116 grid.removeAllColumns();
117 columns
118 .forEach((columnDefinition, renderer) -> {
119 ValueProvider valueProvider = propertySet.getProperty(columnDefinition.getName()).map(PropertyDefinition::getGetter).orElse(null);
120 if (columnDefinition.getValueProvider() != null) {
121 valueProvider = getComponentProvider().newInstance((Class<ValueProvider>) columnDefinition.getValueProvider(), columnDefinition, valueProvider, formFieldFactory);
122 }
123
124 final Grid.Column column = grid.addColumn(valueProvider, (AbstractRenderer<T, T>) renderer);
125 column.setId(columnDefinition.getName());
126 if (columnDefinition.getLargeContentColumnWidth() != null) {
127 column.setMinimumWidthFromContent(false);
128 column.setMinimumWidth(columnDefinition.getLargeContentColumnWidth());
129 }
130 column.setCaption(columnDefinition.getCaption());
131
132 if (!definition.isReadOnly() && columnDefinition.isEditable()) {
133 final ColumnEditorDefinition<?> editor = columnDefinition.getEditor();
134 Optional.ofNullable(editor).map(ColumnEditorDefinition::getField).ifPresent(field -> {
135 final HasValue component = formFieldFactory.createField(field, Locale.getDefault());
136 final Binder.BindingBuilder<T, ?> bindingBuilder = grid.getEditor().getBinder().forField(component);
137
138 new ConfiguredBinder<>(Collections.singletonList(field), componentProvider, propertySet).applyConfiguration(bindingBuilder, (FieldDefinition) field, component);
139 column.setEditorBinding(bindingBuilder.bind(columnDefinition.getName()));
140 });
141 }
142 });
143
144 grid.getEditor().setEnabled(false);
145 grid.getColumns().stream()
146 .map(Grid.Column::getEditorBinding).filter(Objects::nonNull).findFirst()
147 .ifPresent(any -> {
148 grid.getEditor().setBuffered(true);
149 grid.getEditor().setEnabled(true);
150 });
151 }
152
153 protected AvailabilityChecker getAvailabilityChecker() {
154 return availabilityChecker;
155 }
156
157 protected DataProvider<T, DataFilter> getDataProvider() {
158 return dataProvider;
159 }
160
161 public Map<ColumnDefinition, AbstractRenderer> getColumns() {
162 return columns;
163 }
164
165 @Override
166 public void destroy() {
167 if (dataProvider instanceof Destructible) {
168 ((Destructible) dataProvider).destroy();
169 }
170 }
171 }