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.context.MgnlContext;
37 import info.magnolia.event.EventBus;
38 import info.magnolia.jcr.util.NodeUtil;
39 import info.magnolia.jcr.util.SessionUtil;
40 import info.magnolia.objectfactory.ComponentProvider;
41 import info.magnolia.ui.actionbar.ActionbarPresenter;
42 import info.magnolia.ui.actionbar.definition.ActionbarDefinition;
43 import info.magnolia.ui.actionbar.definition.ActionbarGroupDefinition;
44 import info.magnolia.ui.actionbar.definition.ActionbarItemDefinition;
45 import info.magnolia.ui.actionbar.definition.ActionbarSectionDefinition;
46 import info.magnolia.ui.api.action.ActionDefinition;
47 import info.magnolia.ui.api.action.ActionExecutor;
48 import info.magnolia.ui.api.app.SubAppContext;
49 import info.magnolia.ui.api.app.SubAppEventBus;
50 import info.magnolia.ui.api.availability.AvailabilityDefinition;
51 import info.magnolia.ui.api.availability.AvailabilityRule;
52 import info.magnolia.ui.api.location.Location;
53 import info.magnolia.ui.api.view.View;
54 import info.magnolia.ui.contentapp.ContentSubAppView;
55 import info.magnolia.ui.framework.app.BaseSubApp;
56 import info.magnolia.ui.vaadin.actionbar.ActionPopup;
57 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
58 import info.magnolia.ui.workbench.definition.WorkbenchDefinition;
59 import info.magnolia.ui.workbench.event.ItemRightClickedEvent;
60 import info.magnolia.ui.workbench.event.SearchEvent;
61 import info.magnolia.ui.workbench.event.SelectionChangedEvent;
62 import info.magnolia.ui.workbench.event.ViewTypeChangedEvent;
63 import info.magnolia.ui.workbench.search.SearchPresenterDefinition;
64
65 import java.util.ArrayList;
66 import java.util.List;
67
68 import javax.inject.Inject;
69 import javax.inject.Named;
70 import javax.jcr.Item;
71 import javax.jcr.Node;
72 import javax.jcr.RepositoryException;
73
74 import org.apache.commons.lang.StringUtils;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77 import org.vaadin.peter.contextmenu.ContextMenu;
78
79 import com.vaadin.server.ExternalResource;
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
109
110
111
112
113 public class BrowserSubApp extends BaseSubApp {
114
115 private static final Logger log = LoggerFactory.getLogger(BrowserSubApp.class);
116
117 private final BrowserPresenter browser;
118 private final EventBus subAppEventBus;
119 private ActionExecutor actionExecutor;
120 private ComponentProvider componentProvider;
121 private String workbenchRoot;
122
123 @Inject
124 public BrowserSubApp(ActionExecutor actionExecutor, final SubAppContext subAppContext, final ContentSubAppView view, final BrowserPresenter browser, final @Named(SubAppEventBus.NAME) EventBus subAppEventBus, final ComponentProvider componentProvider) {
125 super(subAppContext, view);
126 if (subAppContext == null || view == null || browser == null || subAppEventBus == null) {
127 throw new IllegalArgumentException("Constructor does not allow for null args. Found SubAppContext = " + subAppContext + ", ContentSubAppView = " + view + ", BrowserPresenter = " + browser + ", EventBus = " + subAppEventBus);
128 }
129 this.browser = browser;
130 this.subAppEventBus = subAppEventBus;
131 this.actionExecutor = actionExecutor;
132 this.componentProvider = componentProvider;
133 this.workbenchRoot = ((BrowserSubAppDescriptor) subAppContext.getSubAppDescriptor()).getWorkbench().getPath();
134 }
135
136
137
138
139
140
141
142
143
144
145
146 @Override
147 public final View start(final Location location) {
148 BrowserLocation l = BrowserLocation.wrap(location);
149 super.start(l);
150 getView().setContentView(browser.start());
151 restoreBrowser(l);
152 registerSubAppEventsHandlers(subAppEventBus, this);
153
154 return getView();
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 protected final void restoreBrowser(final BrowserLocation location) {
178 String path = ("/".equals(workbenchRoot) ? "" : workbenchRoot) + location.getNodePath();
179 String viewType = location.getViewType();
180
181 if (!getBrowser().hasViewType(viewType)) {
182 if (!StringUtils.isBlank(viewType)) {
183 log.warn("Unknown view type [{}], returning to default view type.", viewType);
184 }
185 viewType = getBrowser().getDefaultViewType();
186 location.updateViewType(viewType);
187 getAppContext().updateSubAppLocation(getSubAppContext(), location);
188 }
189 String query = location.getQuery();
190
191 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
192 final String workspaceName = subAppDescriptor.getWorkbench().getWorkspace();
193
194 String itemId = null;
195 try {
196 itemId = JcrItemUtil.getItemId(SessionUtil.getNode(workspaceName, path));
197
198
199 if (itemId == null) {
200 itemId = JcrItemUtil.getItemId(SessionUtil.getNode(workspaceName, workbenchRoot));
201 BrowserLocation newLocation = getCurrentLocation();
202 newLocation.updateNodePath("/");
203
204 getAppContext().updateSubAppLocation(getSubAppContext(), newLocation);
205 }
206 } catch (RepositoryException e) {
207 log.warn("Could not retrieve item at path {} in workspace {}", path, workspaceName);
208 }
209 List<String> ids = new ArrayList<String>();
210 ids.add(itemId);
211 getBrowser().resync(ids, viewType, query);
212 updateActionbar(getBrowser().getActionbarPresenter());
213 }
214
215
216
217
218 public void showActionPopup(String absItemPath, int x, int y) {
219
220
221 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
222 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
223 if (actionbarDefinition == null) {
224 return;
225 }
226
227 ActionPopup actionPopup = browser.getView().getActionPopup();
228
229 updateActionPopup(actionPopup);
230 actionPopup.open(x, y);
231 }
232
233
234
235
236
237 private void updateActionPopup(ActionPopup actionPopup) {
238
239 actionPopup.removeAllItems();
240
241 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
242 WorkbenchDefinition workbench = subAppDescriptor.getWorkbench();
243 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
244 if (actionbarDefinition == null) {
245 return;
246 }
247 List<ActionbarSectionDefinition> sections = actionbarDefinition.getSections();
248
249 try {
250 String workbenchRootItemId = JcrItemUtil.getItemId(workbench.getWorkspace(), workbench.getPath());
251 List<String> selectedItemIds = getBrowser().getSelectedItemIds();
252 List<Item> items = getJcrItemsExceptOne(workbench.getWorkspace(), selectedItemIds, workbenchRootItemId);
253
254
255 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections, items);
256
257
258 if (sectionDefinition == null) {
259 return;
260 }
261
262
263 ContextMenu.ContextMenuItem menuItem = null;
264 for (ActionbarGroupDefinition groupDefinition : sectionDefinition.getGroups()) {
265 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
266
267 String actionName = itemDefinition.getName();
268 menuItem = addActionPopupItem(subAppDescriptor, actionPopup, itemDefinition, items);
269 menuItem.setEnabled(actionExecutor.isAvailable(actionName, items.toArray(new Item[items.size()])));
270 }
271
272
273 if (menuItem != null) {
274 menuItem.setSeparatorVisible(true);
275 }
276 }
277 if (menuItem != null) {
278 menuItem.setSeparatorVisible(false);
279 }
280 } catch (RepositoryException e) {
281 log.error("Failed to updated actionbar", e);
282 }
283 }
284
285
286
287
288 private ContextMenu.ContextMenuItem addActionPopupItem(BrowserSubAppDescriptor subAppDescriptor, ActionPopup actionPopup, ActionbarItemDefinition itemDefinition, List<javax.jcr.Item> items) {
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 WorkbenchDefinition workbench = subAppDescriptor.getWorkbench();
314 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
315 if (actionbarDefinition == null) {
316 return;
317 }
318 List<ActionbarSectionDefinition> sections = actionbarDefinition.getSections();
319
320 try {
321 String workbenchRootItemId = JcrItemUtil.getItemId(workbench.getWorkspace(), workbench.getPath());
322 List<String> selectedItemIds = getBrowser().getSelectedItemIds();
323 List<Item> items = getJcrItemsExceptOne(workbench.getWorkspace(), selectedItemIds, workbenchRootItemId);
324
325
326 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections, items);
327
328
329 if (sectionDefinition == null) {
330 for (ActionbarSectionDefinition section : sections) {
331 actionbar.hideSection(section.getName());
332 }
333 return;
334 }
335
336
337 for (ActionbarSectionDefinition section : sections) {
338 if (section != sectionDefinition) {
339 actionbar.hideSection(section.getName());
340 }
341 }
342
343
344 actionbar.showSection(sectionDefinition.getName());
345
346
347 for (ActionbarGroupDefinition groupDefinition : sectionDefinition.getGroups()) {
348 for (ActionbarItemDefinition itemDefinition : groupDefinition.getItems()) {
349
350 String actionName = itemDefinition.getName();
351 if (actionExecutor.isAvailable(actionName, items.toArray(new Item[items.size()]))) {
352 actionbar.enable(actionName);
353 } else {
354 actionbar.disable(actionName);
355 }
356 }
357 }
358 } catch (RepositoryException e) {
359 log.error("Failed to updated actionbar", e);
360 for (ActionbarSectionDefinition section : sections) {
361 actionbar.hideSection(section.getName());
362 }
363 }
364 }
365
366 private ActionbarSectionDefinition getVisibleSection(List<ActionbarSectionDefinition> sections, List<Item> items) throws RepositoryException {
367 for (ActionbarSectionDefinition section : sections) {
368 if (isSectionVisible(section, items))
369 return section;
370 }
371 return null;
372 }
373
374 private boolean isSectionVisible(ActionbarSectionDefinition section, List<Item> items) throws RepositoryException {
375 AvailabilityDefinition availability = section.getAvailability();
376
377
378 if (!availability.getAccess().hasAccess(MgnlContext.getUser())) {
379 return false;
380 }
381
382
383 for (Item item : items) {
384 if (!isSectionVisible(section, item)) {
385 return false;
386 }
387 }
388 return true;
389 }
390
391 private boolean isSectionVisible(ActionbarSectionDefinition section, Item item) throws RepositoryException {
392 AvailabilityDefinition availability = section.getAvailability();
393
394
395 if ((availability.getRuleClass() != null)) {
396
397 AvailabilityRule rule = componentProvider.newInstance(availability.getRuleClass());
398 if (rule == null || !rule.isAvailable(item)) {
399 return false;
400 }
401 }
402
403
404 if (item == null) {
405 return availability.isRoot();
406 }
407
408
409 if (!item.isNode()) {
410 return availability.isProperties();
411 }
412
413
414 if (availability.isNodes()) {
415
416 if (availability.getNodeTypes().isEmpty()) {
417 return true;
418 }
419
420 for (String nodeType : availability.getNodeTypes()) {
421 if (NodeUtil.isNodeType((Node) item, nodeType)) {
422 return true;
423 }
424 }
425
426 }
427 return false;
428 }
429
430 protected final BrowserPresenter getBrowser() {
431 return browser;
432 }
433
434 @Override
435 public final ContentSubAppView getView() {
436 return (ContentSubAppView) super.getView();
437 }
438
439
440
441
442 @Override
443 public void locationChanged(final Location location) {
444 super.locationChanged(location);
445 restoreBrowser(getCurrentLocation());
446 }
447
448
449
450
451 @Override
452 public BrowserLocation getCurrentLocation() {
453 return BrowserLocation.wrap(super.getCurrentLocation());
454 }
455
456
457
458
459
460
461
462
463
464 private void registerSubAppEventsHandlers(final EventBus subAppEventBus, final BrowserSubApp subApp) {
465 final ActionbarPresenter actionbar = subApp.getBrowser().getActionbarPresenter();
466 subAppEventBus.addHandler(SelectionChangedEvent.class, new SelectionChangedEvent.Handler() {
467
468 @Override
469 public void onSelectionChanged(SelectionChangedEvent event) {
470 BrowserLocation location = getCurrentLocation();
471 try {
472 Item selected = JcrItemUtil.getJcrItem(event.getWorkspace(), JcrItemUtil.parseNodeIdentifier(event.getFirstItemId()));
473 location.updateNodePath(StringUtils.removeStart(selected.getPath(), "/".equals(workbenchRoot) ? "" : workbenchRoot));
474 } catch (RepositoryException e) {
475 log.warn("Could not get jcrItem with itemId " + event.getFirstItemId() + " from workspace " + event.getWorkspace(), e);
476 }
477 getAppContext().updateSubAppLocation(getSubAppContext(), location);
478 updateActionbar(actionbar);
479 }
480 });
481
482 subAppEventBus.addHandler(ItemRightClickedEvent.class, new ItemRightClickedEvent.Handler() {
483
484 @Override
485 public void onItemRightClicked(ItemRightClickedEvent event) {
486 String absItemPath;
487 try {
488 absItemPath = event.getItem().getJcrItem().getPath();
489
490 showActionPopup(absItemPath, event.getClickX(), event.getClickY());
491 } catch (RepositoryException e) {
492 log.warn("Could not get jcrItem with itemId " + event.getItemId() + " from workspace " + event.getWorkspace(), e);
493 }
494
495 }
496 });
497
498 subAppEventBus.addHandler(ViewTypeChangedEvent.class, new ViewTypeChangedEvent.Handler() {
499
500 @Override
501 public void onViewChanged(ViewTypeChangedEvent event) {
502 BrowserLocation location = getCurrentLocation();
503
504 if (location.getViewType().equals(SearchPresenterDefinition.VIEW_TYPE)
505 && !event.getViewType().equals(SearchPresenterDefinition.VIEW_TYPE)) {
506 location.updateQuery("");
507 }
508 location.updateViewType(event.getViewType());
509 getAppContext().updateSubAppLocation(getSubAppContext(), location);
510 updateActionbar(actionbar);
511 }
512 });
513
514 subAppEventBus.addHandler(SearchEvent.class, new SearchEvent.Handler() {
515
516 @Override
517 public void onSearch(SearchEvent event) {
518 BrowserLocation location = getCurrentLocation();
519 if (StringUtils.isNotBlank(event.getSearchExpression())) {
520 location.updateViewType(SearchPresenterDefinition.VIEW_TYPE);
521 }
522 location.updateQuery(event.getSearchExpression());
523 getAppContext().updateSubAppLocation(getSubAppContext(), location);
524 updateActionbar(actionbar);
525 }
526 });
527 }
528
529 public static List<Item> getJcrItemsExceptOne(final String workspaceName, List<String> ids, String itemIdToExclude) {
530 List<Item> items = JcrItemUtil.getJcrItems(workspaceName, ids);
531 if (itemIdToExclude == null) {
532 return items;
533 }
534 for (int i = 0; i < items.size(); i++) {
535 try {
536 if (itemIdToExclude.equals(JcrItemUtil.getItemId(items.get(i)))) {
537 items.set(i, null);
538 }
539 } catch (RepositoryException e) {
540 log.debug("Cannot get item ID for item [{}].", items.get(i));
541 }
542 }
543 return items;
544 }
545 }