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 grid.setHeaderRowHeight(23);
101 grid.getDefaultHeaderRow().setStyleName("v-grid-first-row");
102 filterRow.setStyleName("v-grid-filter-row");
103
104 filterContext.getFilter().observe(dataFilter -> {
105 ((ConfigurableFilterDataProvider) grid.getDataProvider()).setFilter(dataFilter.orElse(null));
106 grid.getDataProvider().refreshAll();
107 definition.getColumns().stream()
108 .filter(columnDefinition -> columnDefinition.getFilterComponent() != null)
109 .map(filterableColumnDefinition -> grid.getColumn(filterableColumnDefinition.getName()))
110 .forEach(filterableColumn -> setColumnValue(filterRow, filterableColumn, dataFilter.orElse(null)));
111 });
112 }
113 }
114
115 private void setColumnValue(HeaderRow filterRow, Grid.Column filterableColumn, DataFilter dataFilter) {
116 HeaderCell filterCell = filterRow.getCell(filterableColumn);
117 if (filterCell.getComponent() instanceof HasValue && filterCell.getCellType() == WIDGET) {
118 HasValue hasValue = (HasValue) filterCell.getComponent();
119 hasValue.setValue(dataFilter == null || dataFilter.getPropertyFilters().get(filterableColumn.getId()) == null ?
120 hasValue.getEmptyValue() : dataFilter.getPropertyFilters().get(filterableColumn.getId()));
121 }
122 }
123
124 @SuppressWarnings("unchecked")
125 private void createTitleColumn(Grid<T> grid, ColumnDefinition columnDefinition) {
126 AbstractRenderer renderer = componentProvider.newInstance((Class<AbstractRenderer>) columnDefinition.getRenderer());
127 ValueProvider valueProvider = propertySet.getProperty(columnDefinition.getName()).map(PropertyDefinition::getGetter).orElse(null);
128 if (columnDefinition.getValueProvider() != null) {
129 valueProvider = componentProvider.newInstance(
130 (Class<ValueProvider>) columnDefinition.getValueProvider(),
131 columnDefinition,
132 valueProvider);
133 }
134
135 final Grid.Column column = grid.addColumn(valueProvider, renderer);
136 column.setId(columnDefinition.getName());
137 column.setMinimumWidthFromContent(columnDefinition.isMinimumWidthFromContent());
138 if (columnDefinition.getWidth() > 0) {
139 column.setWidth(columnDefinition.getWidth());
140 }
141 if (columnDefinition.getExpandRatio() > 0) {
142 column.setExpandRatio(columnDefinition.getExpandRatio());
143 }
144 if (columnDefinition.getMinimumWidth() > 0) {
145 column.setMinimumWidth(columnDefinition.getMinimumWidth());
146 }
147 if (columnDefinition.getMaximumWidth() > 0) {
148 column.setMaximumWidth(columnDefinition.getMaximumWidth());
149 }
150 column.setCaption(columnDefinition.getLabel());
151
152 if (!definition.isReadOnly() && columnDefinition.isEditable()) {
153 final ColumnEditorDefinition<T> editor = columnDefinition.getEditor();
154 Optional.ofNullable(editor).map(ColumnEditorDefinition::getField).ifPresent(field -> {
155 UiComponentProvider childComponentProvider = this.componentProvider.inChildContext(columnDefinition.getName() + "editor", field);
156 FieldFactory fieldFactory = childComponentProvider.newInstance(field.getFactoryClass());
157 Binder.BindingBuilder bindingBuilder = grid.getEditor().getBinder().forField(fieldFactory.createField());
158
159 FieldBinder<T> fieldBinder = childComponentProvider.newInstance(field.getFieldBinderClass());
160 bindingBuilder = fieldBinder.<T>configureBinding(field, bindingBuilder);
161
162 column.setEditorBinding(bindingBuilder.bind(columnDefinition.getName()));
163 });
164 }
165
166 Optional.ofNullable(columnDefinition.getDescriptionGenerator())
167 .map(componentProvider::newInstance)
168 .ifPresent(descriptionGenerator -> column.setDescriptionGenerator((DescriptionGenerator) descriptionGenerator, ContentMode.HTML));
169 }
170
171 private void createFilterColumn(HeaderRow filterRow, ColumnDefinition columnDefinition) {
172 FieldDefinition<T> filterComponent = columnDefinition.getFilterComponent();
173 UiComponentProvider childComponentProvider = this.componentProvider.inChildContext(columnDefinition.getName() + "filter", filterComponent);
174
175 FieldFactory factory = childComponentProvider.newInstance(filterComponent.getFactoryClass());
176 HasValue<T> field = (HasValue<T>) factory.createField();
177
178 field.addValueChangeListener(e -> {
179 DataFilterDataFilterter = filterContext.getFilter().value().orElse(new DataFilter());
180 dataFilter.filter(columnDefinition.getName(), field.getValue());
181 filterContext.getFilter().set(dataFilter, true);
182 });
183 filterRow.getCell(columnDefinition.getName()).setComponent((Component) field);
184 }
185 }