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 com.vaadin.shared.ui.grid.GridStaticCellType.WIDGET;
37
38 import info.magnolia.ui.contentapp.DataFilter;
39 import info.magnolia.ui.contentapp.FilterableDataProvider;
40 import info.magnolia.ui.contentapp.configuration.GridViewDefinition;
41 import info.magnolia.ui.contentapp.configuration.column.ColumnDefinition;
42 import info.magnolia.ui.contentapp.configuration.column.ColumnEditorDefinition;
43 import info.magnolia.ui.field.FieldDefinition;
44 import info.magnolia.ui.field.factory.FieldBinder;
45 import info.magnolia.ui.field.factory.FieldFactory;
46 import info.magnolia.ui.framework.FilterContext;
47 import info.magnolia.ui.framework.ioc.UiContextBoundComponentProvider;
48
49 import java.util.Objects;
50 import java.util.Optional;
51
52 import com.vaadin.data.Binder;
53 import com.vaadin.data.HasValue;
54 import com.vaadin.data.PropertyDefinition;
55 import com.vaadin.data.PropertySet;
56 import com.vaadin.data.ValueProvider;
57 import com.vaadin.shared.ui.ContentMode;
58 import com.vaadin.ui.Component;
59 import com.vaadin.ui.DescriptionGenerator;
60 import com.vaadin.ui.Grid;
61 import com.vaadin.ui.components.grid.HeaderCell;
62 import com.vaadin.ui.components.grid.HeaderRow;
63 import com.vaadin.ui.renderers.AbstractRenderer;
64
65
66
67
68 public class GridColumnConfigurer<T> {
69 private final GridViewDefinition<T> definition;
70 private final UiContextBoundComponentProvider componentProvider;
71 private final PropertySet<T> propertySet;
72 private final FilterContext filterContext;
73
74 public GridColumnConfigurer(GridViewDefinition<T> definition,
75 UiContextBoundComponentProvider componentProvider,
76 PropertySet<T> propertySet,
77 FilterContext filterContext
78 ) {
79 this.definition = definition;
80 this.componentProvider = componentProvider;
81 this.propertySet = propertySet;
82 this.filterContext = filterContext;
83 }
84
85 public void configureColumns(Grid<T> grid) {
86 grid.removeAllColumns();
87 definition.getColumns().forEach((columnDefinition) -> createTitleColumn(grid, columnDefinition));
88 if (definition.getColumns().stream()
89 .map(ColumnDefinition::getFilterComponent)
90 .anyMatch(Objects::nonNull)) {
91 if (!(grid.getDataProvider() instanceof FilterableDataProvider)) {
92 throw new IllegalArgumentException(
93 String.format("Filter component is defined for at least one column but grid's %s is not an instance of %s.", grid.getDataProvider(), FilterableDataProvider.class));
94 }
95 HeaderRow filterRow = grid.addHeaderRowAt(1);
96 definition.getColumns().stream()
97 .filter(columnDefinition -> columnDefinition.getFilterComponent() != null)
98 .forEach(columnDefinition -> createFilterColumn(filterRow, columnDefinition));
99 grid.setHeaderRowHeight(23);
100 grid.getDefaultHeaderRow().setStyleName("v-grid-first-row");
101 filterRow.setStyleName("v-grid-filter-row");
102
103 filterContext.getFilter().observe(dataFilter -> {
104 ((FilterableDataProvider) grid.getDataProvider()).setDataFilter(dataFilter.orElse(null));
105 grid.getDataProvider().refreshAll();
106 definition.getColumns().stream()
107 .filter(columnDefinition -> columnDefinition.getFilterComponent() != null)
108 .map(filterableColumnDefinition -> grid.getColumn(filterableColumnDefinition.getName()))
109 .forEach(filterableColumn -> setColumnValue(filterRow, filterableColumn, dataFilter.orElse(null)));
110 });
111 }
112 }
113
114 private void setColumnValue(HeaderRow filterRow, Grid.Column filterableColumn, DataFilter dataFilter) {
115 HeaderCell filterCell = filterRow.getCell(filterableColumn);
116 if (filterCell.getComponent() instanceof HasValue && filterCell.getCellType() == WIDGET) {
117 HasValue hasValue = (HasValue) filterCell.getComponent();
118 hasValue.setValue(dataFilter == null || dataFilter.getPropertyFilters().get(filterableColumn.getId()) == null ?
119 hasValue.getEmptyValue() : dataFilter.getPropertyFilters().get(filterableColumn.getId()));
120 }
121 }
122
123 @SuppressWarnings("unchecked")
124 private void createTitleColumn(Grid<T> grid, ColumnDefinition columnDefinition) {
125 AbstractRenderer renderer = componentProvider.newInstance((Class<AbstractRenderer>) columnDefinition.getRenderer());
126 ValueProvider valueProvider = propertySet.getProperty(columnDefinition.getName()).map(PropertyDefinition::getGetter).orElse(null);
127 if (columnDefinition.getValueProvider() != null) {
128 valueProvider = componentProvider.newInstance(
129 (Class<ValueProvider>) columnDefinition.getValueProvider(),
130 columnDefinition,
131 valueProvider);
132 }
133
134 final Grid.Column column = grid.addColumn(valueProvider, renderer);
135 column.setId(columnDefinition.getName());
136 if (columnDefinition.getLargeContentColumnWidth() != null) {
137 column.setMinimumWidthFromContent(false);
138 column.setMinimumWidth(columnDefinition.getLargeContentColumnWidth());
139 }
140 column.setCaption(columnDefinition.getCaption());
141
142 if (!definition.isReadOnly() && columnDefinition.isEditable()) {
143 final ColumnEditorDefinition<T> editor = columnDefinition.getEditor();
144 Optional.ofNullable(editor).map(ColumnEditorDefinition::getField).ifPresent(field -> {
145 UiContextBoundComponentProvider childComponentProvider = this.componentProvider.inChildContext(columnDefinition.getName() + "editor", field);
146 FieldFactory fieldFactory = childComponentProvider.newInstance(field.getFactoryClass());
147 Binder.BindingBuilder bindingBuilder = grid.getEditor().getBinder().forField(fieldFactory.createField());
148
149 FieldBinder<T> fieldBinder = childComponentProvider.newInstance(field.getFieldBinderClass());
150 bindingBuilder = fieldBinder.<T>configureBinding(field, bindingBuilder);
151
152 column.setEditorBinding(bindingBuilder.bind(columnDefinition.getName()));
153 });
154 }
155
156 Optional.ofNullable(columnDefinition.getDescriptionGenerator())
157 .map(componentProvider::newInstance)
158 .ifPresent(descriptionGenerator -> column.setDescriptionGenerator((DescriptionGenerator) descriptionGenerator, ContentMode.HTML));
159 }
160
161 private void createFilterColumn(HeaderRow filterRow, ColumnDefinition columnDefinition) {
162 FieldDefinition<T> filterComponent = columnDefinition.getFilterComponent();
163 UiContextBoundComponentProvider childComponentProvider = this.componentProvider.inChildContext(columnDefinition.getName() + "filter", filterComponent);
164
165 FieldFactory factory = childComponentProvider.newInstance(filterComponent.getFactoryClass());
166 HasValue<T> field = (HasValue<T>) factory.createField();
167
168 field.addValueChangeListener(e -> {
169 DataFiltDataFilteraFilter = filterContext.getFilter().value().orElse(new DataFilter());
170 dataFilter.filter(columnDefinition.getName(), field.getValue());
171 filterContext.getFilter().set(dataFilter, true);
172 });
173 filterRow.getCell(columnDefinition.getName()).setComponent((Component) field);
174 }
175 }