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.event.EventBus;
37 import info.magnolia.ui.actionbar.ActionbarPresenter;
38 import info.magnolia.ui.actionbar.definition.ActionbarDefinition;
39 import info.magnolia.ui.actionbar.definition.ActionbarGroupDefinition;
40 import info.magnolia.ui.actionbar.definition.ActionbarItemDefinition;
41 import info.magnolia.ui.actionbar.definition.ActionbarSectionDefinition;
42 import info.magnolia.ui.api.action.ActionDefinition;
43 import info.magnolia.ui.api.action.ActionExecutor;
44 import info.magnolia.ui.api.app.SubAppContext;
45 import info.magnolia.ui.api.app.SubAppEventBus;
46 import info.magnolia.ui.api.availability.AvailabilityChecker;
47 import info.magnolia.ui.api.availability.AvailabilityDefinition;
48 import info.magnolia.ui.api.event.AdmincentralEventBus;
49 import info.magnolia.ui.api.location.Location;
50 import info.magnolia.ui.api.location.LocationChangedEvent;
51 import info.magnolia.ui.contentapp.ContentSubAppView;
52 import info.magnolia.ui.framework.app.BaseSubApp;
53 import info.magnolia.ui.vaadin.actionbar.ActionPopup;
54 import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
55 import info.magnolia.ui.workbench.event.ItemRightClickedEvent;
56 import info.magnolia.ui.workbench.event.SearchEvent;
57 import info.magnolia.ui.workbench.event.SelectionChangedEvent;
58 import info.magnolia.ui.workbench.event.ViewTypeChangedEvent;
59 import info.magnolia.ui.workbench.search.SearchPresenterDefinition;
60
61 import java.util.Arrays;
62 import java.util.Iterator;
63 import java.util.List;
64 import java.util.Set;
65
66 import javax.inject.Inject;
67 import javax.inject.Named;
68
69 import org.apache.commons.lang3.StringUtils;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 import com.vaadin.ui.MenuBar.MenuItem;
74 import com.vaadin.server.ExternalResource;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public class BrowserSubApp extends BaseSubApp<ContentSubAppView> {
109
110 private static final Logger log = LoggerFactory.getLogger(BrowserSubApp.class);
111
112 private final BrowserPresenter browser;
113 private final EventBus subAppEventBus;
114 private ActionExecutor actionExecutor;
115 protected ContentConnector contentConnector;
116 private AvailabilityChecker checker;
117
118 @Inject
119 public BrowserSubApp(ActionExecutor actionExecutor, final SubAppContext subAppContext, final ContentSubAppView view, final BrowserPresenter browser, final @Named(SubAppEventBus.NAME) EventBus subAppEventBus, @Named(AdmincentralEventBus.NAME) EventBus adminCentralEventBus, ContentConnector contentConnector, AvailabilityChecker checker) {
120 super(subAppContext, view);
121 this.checker = checker;
122 if (subAppContext == null || view == null || browser == null || subAppEventBus == null) {
123 throw new IllegalArgumentException("Constructor does not allow for null args. Found SubAppContext = " + subAppContext + ", ContentSubAppView = " + view + ", BrowserPresenter = " + browser + ", EventBus = " + subAppEventBus);
124 }
125 this.browser = browser;
126 this.subAppEventBus = subAppEventBus;
127 this.actionExecutor = actionExecutor;
128 this.contentConnector = contentConnector;
129
130
131
132
133
134
135
136 adminCentralEventBus.addHandler(LocationChangedEvent.class, new LocationChangedEvent.Handler() {
137 @Override
138 public void onLocationChanged(LocationChangedEvent event) {
139
140
141
142
143
144 if (event.getNewLocation().equals(getCurrentLocation())) {
145 restoreBrowser(getCurrentLocation());
146 }
147 }
148 });
149 }
150
151
152
153
154
155
156
157
158
159
160
161 @Override
162 public ContentSubAppView start(final Location location) {
163 BrowserLocation l = BrowserLocation.wrap(location);
164 super.start(l);
165 getView().setContentView(browser.start());
166 restoreBrowser(l);
167 registerSubAppEventsHandlers(subAppEventBus);
168
169 return getView();
170 }
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192 protected void restoreBrowser(final BrowserLocation location) {
193 String path = location.getNodePath();
194 String viewType = location.getViewType();
195
196 if (!getBrowser().hasViewType(viewType)) {
197 if (!StringUtils.isBlank(viewType)) {
198 log.warn("Unknown view type [{}], returning to default view type.", viewType);
199 }
200 viewType = getBrowser().getDefaultViewType();
201 location.updateViewType(viewType);
202 getAppContext().updateSubAppLocation(getSubAppContext(), location);
203 }
204 String query = location.getQuery();
205
206 Object itemId = contentConnector.getItemIdByUrlFragment(path);
207
208
209 if (!contentConnector.canHandleItem(itemId)) {
210 itemId = contentConnector.getDefaultItemId();
211 BrowserLocation newLocation = getCurrentLocation();
212 newLocation.updateNodePath("/");
213 getAppContext().updateSubAppLocation(getSubAppContext(), newLocation);
214 }
215
216 getBrowser().resync(Arrays.asList(itemId), viewType, query);
217 updateActionbar(getBrowser().getActionbarPresenter());
218 }
219
220
221
222
223
224 public void showActionPopup(Object itemId, int x, int y) {
225
226
227 BrowserSubAppDescriptora/ui/contentapp/browser/BrowserSubAppDescriptor.html#BrowserSubAppDescriptor">BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
228 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
229 if (actionbarDefinition == null) {
230 return;
231 }
232
233 ActionPopup actionPopup = browser.getView().getActionPopup();
234
235 updateActionPopup(actionPopup);
236 actionPopup.open(x, y);
237 }
238
239
240
241
242
243 private void updateActionPopup(ActionPopup actionPopup) {
244
245 actionPopup.removeItems();
246
247 BrowserSubAppDescriptora/ui/contentapp/browser/BrowserSubAppDescriptor.html#BrowserSubAppDescriptor">BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
248 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
249 if (actionbarDefinition == null) {
250 return;
251 }
252 List<ActionbarSectionDefinition> sections = actionbarDefinition.getSections();
253
254
255 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections);
256
257
258 if (sectionDefinition == null) {
259 return;
260 }
261
262
263 for (final Iterator<ActionbarGroupDefinition> groupDefinitionIterator = sectionDefinition.getGroups().iterator(); groupDefinitionIterator.hasNext();) {
264 final ActionbarGroupDefinition groupDefinition = groupDefinitionIterator.next();
265 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
266
267 final String actionName = itemDefinition.getName();
268 final MenuItem menuItem = addActionPopupItem(subAppDescriptor, itemDefinition);
269 ActionDefinition actionDefinition = actionExecutor.getActionDefinition(actionName);
270 if (actionDefinition != null) {
271 AvailabilityDefinition availability = actionDefinition.getAvailability();
272 menuItem.setEnabled(checker.isAvailable(availability, browser.getSelectedItemIds()));
273 }
274 }
275
276
277 if (groupDefinitionIterator.hasNext()) {
278 getBrowser().getView().getActionPopup().addSeparator();
279 }
280 }
281 }
282
283
284
285
286 private MenuItem addActionPopupItem(BrowserSubAppDescriptor subAppDescriptor, ActionbarItemDefinition itemDefinition) {
287 String actionName = itemDefinition.getName();
288
289 ActionDefinition action = subAppDescriptor.getActions().get(actionName);
290 String label = action.getLabel();
291 String iconFontCode = ActionPopup.ICON_FONT_CODE + action.getIcon();
292 ExternalResource iconFontResource = new ExternalResource(iconFontCode);
293
294 return getBrowser().getView().getActionPopup().addItem(label, iconFontResource, item -> getBrowser().onActionbarItemClicked(actionName));
295 }
296
297
298
299
300
301
302
303
304
305 public void updateActionbar(ActionbarPresenter actionbar) {
306
307 BrowserSubAppDescriptora/ui/contentapp/browser/BrowserSubAppDescriptor.html#BrowserSubAppDescriptor">BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
308 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
309 if (actionbarDefinition == null) {
310 return;
311 }
312 List<ActionbarSectionDefinition> sections = actionbarDefinition.getSections();
313
314 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections);
315
316
317 for (ActionbarSectionDefinition section : sections) {
318 actionbar.hideSection(section.getName());
319 }
320
321 if (sectionDefinition != null) {
322
323 actionbar.showSection(sectionDefinition.getName());
324
325
326 for (ActionbarGroupDefinition groupDefinition : sectionDefinition.getGroups()) {
327 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
328
329 String actionName = itemDefinition.getName();
330 ActionDefinition actionDefinition = actionExecutor.getActionDefinition(actionName);
331 if (actionDefinition != null) {
332 AvailabilityDefinition availability = actionDefinition.getAvailability();
333 if (checker.isAvailable(availability, browser.getSelectedItemIds())) {
334 actionbar.enable(actionName);
335 } else {
336 actionbar.disable(actionName);
337 }
338 } else {
339 log.warn("Action bar expected an action named {}, but no such action is currently configured.", actionName);
340 }
341 }
342 }
343 }
344 }
345
346 private ActionbarSectionDefinition getVisibleSection(List<ActionbarSectionDefinition> sections) {
347 for (ActionbarSectionDefinition section : sections) {
348 if (isSectionVisible(section))
349 return section;
350 }
351 return null;
352 }
353
354 private boolean isSectionVisible(ActionbarSectionDefinition section) {
355 return checker.isAvailable(section.getAvailability(), browser.getSelectedItemIds());
356 }
357
358 protected final BrowserPresenter getBrowser() {
359 return browser;
360 }
361
362
363
364
365 @Override
366 public void locationChanged(final Location location) {
367 super.locationChanged(location);
368 restoreBrowser(BrowserLocation.wrap(location));
369 }
370
371
372
373
374 @Override
375 public BrowserLocation getCurrentLocation() {
376 return BrowserLocation.wrap(super.getCurrentLocation());
377 }
378
379
380
381
382
383
384
385
386
387 private void registerSubAppEventsHandlers(final EventBus subAppEventBus) {
388 final ActionbarPresenter actionbar = getBrowser().getActionbarPresenter();
389 subAppEventBus.addHandler(SelectionChangedEvent.class, new SelectionChangedEvent.Handler() {
390
391 @Override
392 public void onSelectionChanged(SelectionChangedEvent event) {
393 handleSelectionChange(event.getItemIds(), actionbar);
394 }
395 });
396
397 subAppEventBus.addHandler(ItemRightClickedEvent.class, new ItemRightClickedEvent.Handler() {
398
399 @Override
400 public void onItemRightClicked(ItemRightClickedEvent event) {
401 showActionPopup(event.getItemId(), event.getClickX(), event.getClickY());
402 }
403 });
404
405 subAppEventBus.addHandler(ViewTypeChangedEvent.class, new ViewTypeChangedEvent.Handler() {
406
407 @Override
408 public void onViewChanged(ViewTypeChangedEvent event) {
409 BrowserLocation location = getCurrentLocation();
410
411 if (location.getViewType().equals(SearchPresenterDefinition.VIEW_TYPE)
412 && !event.getViewType().equals(SearchPresenterDefinition.VIEW_TYPE)) {
413 location.updateQuery("");
414 }
415 location.updateViewType(event.getViewType());
416 getAppContext().updateSubAppLocation(getSubAppContext(), location);
417 updateActionbar(actionbar);
418 }
419 });
420
421 subAppEventBus.addHandler(SearchEvent.class, new SearchEvent.Handler() {
422
423 @Override
424 public void onSearch(SearchEvent event) {
425 BrowserLocation location = getCurrentLocation();
426 if (StringUtils.isNotBlank(event.getSearchExpression())) {
427 location.updateViewType(SearchPresenterDefinition.VIEW_TYPE);
428 }
429 location.updateQuery(event.getSearchExpression());
430 getAppContext().updateSubAppLocation(getSubAppContext(), location);
431 updateActionbar(actionbar);
432 }
433 });
434 }
435
436 private void handleSelectionChange(Set<Object> selectionIds, ActionbarPresenter actionbar) {
437 BrowserLocation location = getCurrentLocation();
438 applySelectionToLocation(location, selectionIds.isEmpty() ? contentConnector.getDefaultItemId() : selectionIds.iterator().next());
439 getAppContext().updateSubAppLocation(getSubAppContext(), location);
440 updateActionbar(actionbar);
441
442 }
443
444 protected void applySelectionToLocation(BrowserLocation location, Object selectedId) {
445 location.updateNodePath("");
446 if (!contentConnector.canHandleItem(selectedId)) {
447
448 } else {
449 location.updateNodePath(contentConnector.getItemUrlFragment(selectedId));
450 }
451 }
452 }