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 info.magnolia.icons.MagnoliaIcons;
37 import info.magnolia.ui.contentapp.browser.Workbench.WorkbenchContext;
38 import info.magnolia.ui.contentapp.configuration.ExtensionViewDefinition;
39 import info.magnolia.ui.contentapp.configuration.ContentViewDefinition;
40 import info.magnolia.ui.contentapp.configuration.ContentViewsDefinition;
41 import info.magnolia.ui.UIComponent;
42 import info.magnolia.ui.framework.ioc.SessionStore;
43 import info.magnolia.ui.theme.ResurfaceTheme;
44
45 import java.util.HashMap;
46 import java.util.LinkedHashMap;
47 import java.util.List;
48 import java.util.Map;
49 import java.util.Optional;
50
51 import javax.inject.Inject;
52
53 import com.vaadin.shared.ui.ContentMode;
54 import com.vaadin.ui.Alignment;
55 import com.vaadin.ui.Button;
56 import com.vaadin.ui.Component;
57 import com.vaadin.ui.CssLayout;
58 import com.vaadin.ui.HorizontalLayout;
59 import com.vaadin.ui.Label;
60 import com.vaadin.ui.VerticalLayout;
61
62
63
64
65
66
67
68 public class ContentViews<T> extends VerticalLayout implements UIComponent {
69
70 private final Map<String, Component> contentViewToggleControls = new HashMap<>();
71 private final Map<String, Component> extensionViewToggleControls = new HashMap<>();
72 private HashMap<ContentViewDefinition<?>, Component> contentViews = new HashMap<>();
73 private final ContentViewsDefinition<T> definition;
74 private final Map<String, ExtensionViewDefinition> extensionViews;
75 private final HorizontalLayout toolBar;
76 private final Label title;
77
78 private Component currentActiveContentView;
79 private WorkbenchContext workbenchContext;
80
81 private String currentActiveExtensionViewId;
82 private UIComponent currentActiveExtensionView;
83
84 @Inject
85 public ContentViews(WorkbenchContext workbenchContext, ContentViewsDefinition<T> definition, List<ExtensionViewDefinition> extensionViews) {
86
87 this.workbenchContext = workbenchContext;
88 this.definition = definition;
89 this.extensionViews = extensionViews.stream().collect(LinkedHashMap::new, (map, item) -> map.put(item.getView().getName(), item), Map::putAll);
90
91 setSizeFull();
92 setSpacing(false);
93 setMargin(false);
94 addStyleName("content-views");
95
96 title = new Label();
97 title.addStyleName("heading-1 tab-header");
98
99 toolBar = new HorizontalLayout();
100 toolBar.addStyleName("toolbar");
101 toolBar.setWidth(100, Unit.PERCENTAGE);
102
103 toolBar.setSpacing(true);
104 toolBar.setDefaultComponentAlignment(Alignment.BOTTOM_LEFT);
105
106 toolBar.addComponent(title);
107 toolBar.setExpandRatio(title, 0);
108
109 final HorizontalLayout viewsWrapper = new HorizontalLayout();
110 viewsWrapper.addStyleName("tools");
111 toolBar.addComponent(viewsWrapper);
112 toolBar.setComponentAlignment(viewsWrapper, Alignment.BOTTOM_RIGHT);
113
114 final CssLayout viewModes = new CssLayout();
115 viewModes.addStyleName("view-modes");
116 viewsWrapper.addComponent(viewModes);
117
118 addComponents(toolBar);
119
120 definition.getViews().forEach((id, viewDefinition) -> {
121 final Component contentViewIcon = createViewIcon(id, false, viewDefinition.getIcon());
122 contentViewToggleControls.put(id, contentViewIcon);
123 viewModes.addComponent(contentViewIcon);
124 });
125
126 workbenchContext.displayedContentViewId().observe(viewId -> {
127 this.contentViewToggleControls.values().forEach(control -> control.removeStyleName("active"));
128 viewId.ifPresent(this::switchView);
129 });
130
131 if (!this.extensionViews.isEmpty()) {
132 final CssLayout extensionViewModes = new CssLayout();
133 extensionViewModes.addStyleName("extension-views");
134
135 this.extensionViews.forEach((id, extensionViewDefinition) -> {
136 final Component contentViewIcon = createViewIcon(id, true, extensionViewDefinition.getIcon());
137 extensionViewToggleControls.put(id, contentViewIcon);
138 extensionViewModes.addComponent(contentViewIcon);
139 });
140 viewsWrapper.addComponent(extensionViewModes, 0);
141 }
142 }
143
144 private void switchView(String viewId) {
145 ContentViewDefinition<T> contentViewDefinition = definition.getViews().get(viewId);
146 Optional.ofNullable(currentActiveContentView).ifPresent(component -> component.setVisible(false));
147 currentActiveContentView = contentViews.computeIfAbsent(contentViewDefinition, viewDefinition -> {
148 final Component component = create(viewDefinition).asVaadinComponent();
149 addComponent(component);
150 return component;
151 });
152 currentActiveContentView.setVisible(true);
153 this.contentViewToggleControls.get(viewId).addStyleName("active");
154
155 setExpandRatio(currentActiveContentView, 1f);
156 }
157
158 private void showHideExtensionViews(String viewId) {
159 boolean hideOnly = viewId.equals(currentActiveExtensionViewId);
160
161 Optional.ofNullable(currentActiveExtensionView)
162 .map(UIComponent::getCurrentViewReference)
163 .ifPresent(contentView -> {
164 SessionStore.access().releaseBeanStore(contentView);
165 extensionViewToggleControls.values().forEach(control -> control.removeStyleName("active"));
166 currentActiveExtensionViewId = null;
167 currentActiveExtensionView = null;
168 });
169
170 if (!hideOnly) {
171 ExtensionViewDefinition<?> extensionViewDefinition = extensionViews.get(viewId);
172 currentActiveExtensionView = create(extensionViewDefinition.getView());
173 currentActiveExtensionViewId = viewId;
174 extensionViewToggleControls.get(viewId).addStyleName("active");
175 currentActiveExtensionView.asVaadinComponent().addStyleName("extension-view");
176
177 addComponent(currentActiveExtensionView.asVaadinComponent(), 1);
178 setExpandRatio(currentActiveExtensionView.asVaadinComponent(), extensionViewDefinition.getExpandRatio());
179 }
180 }
181
182 protected Button createViewIcon(final String viewType, final boolean extension, final String icon, final MagnoliaIcons defaultIcon) {
183 Button button = new Button(MagnoliaIcons.forCssClass(icon).orElse(defaultIcon),
184 extension ? clickEvent -> showHideExtensionViews(viewType) : clickEvent -> workbenchContext.displayedContentViewId().set(viewType));
185 button.addStyleName(ResurfaceTheme.BUTTON_ICON);
186 return button;
187 }
188
189 protected Component createViewIcon(final String viewType, final boolean extension, final String icon) {
190 return createViewIcon(viewType, extension, icon, MagnoliaIcons.VIEW_LIST);
191 }
192
193 public void setTitle(String title) {
194 this.title.setValue(title);
195 }
196
197 public void setTitle(String title, boolean isHtml) {
198 if (isHtml) {
199 this.title.setContentMode(ContentMode.HTML);
200 }
201 setTitle(title);
202 }
203
204 protected ContentViewsDefinition<T> getDefinition() {
205 return definition;
206 }
207
208 protected Map<String, ExtensionViewDefinition> getExtensionViews() {
209 return extensionViews;
210 }
211 }