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.stream.Collectors.toSet;
37
38 import info.magnolia.ui.contentapp.DataFilter;
39 import info.magnolia.ui.contentapp.FilterableHierarchicalDataProvider;
40 import info.magnolia.ui.contentapp.browser.context.ValueContext;
41 import info.magnolia.ui.contentapp.browser.drop.RowDragger;
42 import info.magnolia.ui.contentapp.configuration.TreeViewDefinition;
43 import info.magnolia.ui.framework.ContextProperty;
44 import info.magnolia.ui.framework.FilterContext;
45 import info.magnolia.ui.framework.datasource.DatasourceComponent;
46 import info.magnolia.ui.framework.datasource.components.SelectedItems;
47 import info.magnolia.util.OptionalConsumer;
48
49 import java.util.Collection;
50 import java.util.HashSet;
51 import java.util.Optional;
52 import java.util.stream.Stream;
53
54 import javax.inject.Inject;
55
56 import com.vaadin.shared.ui.grid.DropMode;
57 import com.vaadin.ui.CustomComponent;
58 import com.vaadin.ui.Grid;
59 import com.vaadin.ui.TextField;
60 import com.vaadin.ui.TreeGrid;
61 import com.vaadin.ui.components.grid.HeaderRow;
62
63
64
65
66
67 public class TreeView<T> extends CustomComponent implements ContentView {
68
69 private final TreeGrid<T> treeGrid;
70 private final TreePresenter<T> treePresenter;
71 private final boolean multiSelect;
72
73 @SuppressWarnings("unchecked")
74 @Inject
75 public TreeView(
76 ValueContext<T> valueContext,
77 TreeViewDefinition<T> definition,
78 @DatasourceComponent ItemInteractionAvailability<T> itemInteractionAvailability) {
79
80 this.multiSelect = definition.isMultiSelect();
81
82 final ContextProperty<DataFilter> filter = bindContext(FilterContext.class).getFilter();
83 filter.set(new DataFilter());
84
85 this.treePresenter = create(TreePresenter.class, this, definition);
86 bindInstance(TreePresenter.class, treePresenter);
87
88 final FilterableHierarchicalDataProvider<T> dataProvider = treePresenter.getDataProvider();
89 this.treeGrid = new MagnoliaTreeGrid<>(this.treePresenter.getPropertySet(), itemInteractionAvailability::isItemAvailable, this.treePresenter.getCellEditorAvailability());
90 this.treeGrid.setDataProvider(dataProvider);
91 this.treeGrid.addCollapseListener(e -> treeGrid.getEditor().cancel());
92 this.treeGrid.setSizeFull();
93 this.treeGrid.setSelectionMode(this.multiSelect ? Grid.SelectionMode.MULTI : Grid.SelectionMode.SINGLE);
94 this.treeGrid.addSelectionListener(event -> valueContext.current().set(SelectedItems.of(event.getAllSelectedItems())));
95 this.treeGrid.addSelectionListener(e -> e.getAllSelectedItems().forEach(this::expandParents));
96 this.treeGrid.addItemClickListener(event -> {
97 this.treeGrid.deselectAll();
98 this.treeGrid.select(event.getItem());
99 });
100 this.treeGrid.getEditor().addSaveListener(e -> {
101 this.treePresenter.saveInlineEditingResults(e.getBean());
102 this.treeGrid.getDataProvider().refreshAll();
103 });
104 this.treePresenter.createColumns(treeGrid);
105
106
107 Optional.ofNullable(definition.getDropConstraint()).ifPresent(dropConstraint -> getComponentProvider().newInstance(RowDragger.class, treeGrid, DropMode.ON_TOP_OR_BETWEEN, dropConstraint));
108 Optional.ofNullable(treeGrid.getColumn("jcrPath")).ifPresent(tColumn -> {
109 final HeaderRow headerRow = this.treeGrid.appendHeaderRow();
110 headerRow
111 .getCell(tColumn)
112 .setComponent(new TextField(e -> filter.mutate(dataFilter -> dataFilter.setPathFilter(e.getValue()))));
113
114 });
115
116 valueContext.current()
117 .observe(selectedItemsOptional -> OptionalConsumer.of(selectedItemsOptional)
118 .ifNotPresent(treeGrid::deselectAll)
119 .ifPresent(selectedItems -> {
120 selectedItems.stream().forEach(this::expandParents);
121 select(selectedItems.stream());
122 }));
123
124 setSizeFull();
125 setCompositionRoot(treeGrid);
126 }
127
128 private void expandParents(T item) {
129 final Collection<T> parents = this.treePresenter.getParents(item).collect(toSet());
130 this.treeGrid.expand(parents);
131 }
132
133 private void select(Stream<T> values) {
134 if (this.multiSelect) {
135 this.treeGrid.asMultiSelect().updateSelection(values.collect(toSet()), new HashSet<>());
136 } else {
137 values.findFirst().ifPresent(this.treeGrid.asSingleSelect()::setValue);
138 }
139 }
140 }