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