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