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.ContentView.ViewType;
59 import info.magnolia.ui.workbench.definition.WorkbenchDefinition;
60 import info.magnolia.ui.workbench.event.ItemRightClickedEvent;
61 import info.magnolia.ui.workbench.event.SearchEvent;
62 import info.magnolia.ui.workbench.event.SelectionChangedEvent;
63 import info.magnolia.ui.workbench.event.ViewTypeChangedEvent;
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, 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 ViewType viewType = location.getViewType();
180 if (viewType == null) {
181 log.warn("ViewType did not match, returning default viewType.");
182
183 viewType = getBrowser().getDefaultViewType();
184 location.updateViewType(viewType);
185 getAppContext().updateSubAppLocation(getSubAppContext(), location);
186 }
187 String query = location.getQuery();
188
189 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
190 final String workspaceName = subAppDescriptor.getWorkbench().getWorkspace();
191
192 String itemId = null;
193 try {
194 itemId = JcrItemUtil.getItemId(SessionUtil.getNode(workspaceName, path));
195
196
197 if (itemId == null) {
198 itemId = JcrItemUtil.getItemId(SessionUtil.getNode(workspaceName, workbenchRoot));
199 BrowserLocation newLocation = getCurrentLocation();
200 newLocation.updateNodePath("/");
201
202 getAppContext().updateSubAppLocation(getSubAppContext(), newLocation);
203 }
204 } catch (RepositoryException e) {
205 log.warn("Could not retrieve item at path {} in workspace {}", path, workspaceName);
206 }
207 List<String> ids = new ArrayList<String>();
208 ids.add(itemId);
209 getBrowser().resync(ids, viewType, query);
210 updateActionbar(getBrowser().getActionbarPresenter());
211 }
212
213
214
215
216
217 public void showActionPopup(String absItemPath, int x, int y) {
218
219
220 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
221 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
222 if (actionbarDefinition == null) {
223 return;
224 }
225
226 ActionPopup actionPopup = browser.getView().getActionPopup();
227
228 updateActionPopup(actionPopup);
229 actionPopup.open(x, y);
230 }
231
232
233
234
235
236 private void updateActionPopup(ActionPopup actionPopup) {
237
238 actionPopup.removeAllItems();
239
240 BrowserSubAppDescriptor subAppDescriptor = (BrowserSubAppDescriptor) getSubAppContext().getSubAppDescriptor();
241 WorkbenchDefinition workbench = subAppDescriptor.getWorkbench();
242 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
243 if (actionbarDefinition == null) {
244 return;
245 }
246 List<ActionbarSectionDefinition> sections = actionbarDefinition.getSections();
247
248 try {
249 String workbenchRootItemId = JcrItemUtil.getItemId(workbench.getWorkspace(), workbench.getPath());
250 List<String> selectedItemIds = getBrowser().getSelectedItemIds();
251 List<Item> items = getJcrItemsExceptOne(workbench.getWorkspace(), selectedItemIds, workbenchRootItemId);
252
253
254 ActionbarSectionDefinition sectionDefinition = getVisibleSection(sections, items);
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, items);
268 menuItem.setEnabled(actionExecutor.isAvailable(actionName, items.toArray(new Item[items.size()])));
269 }
270
271
272 if (menuItem != null) {
273 menuItem.setSeparatorVisible(true);
274 }
275 }
276 if (menuItem != null) {
277 menuItem.setSeparatorVisible(false);
278 }
279 } catch (RepositoryException e) {
280 log.error("Failed to updated actionbar", e);
281 }
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() == ViewType.SEARCH && event.getViewType() != ViewType.SEARCH) {
505 location.updateQuery("");
506 }
507 location.updateViewType(event.getViewType());
508 getAppContext().updateSubAppLocation(getSubAppContext(), location);
509 updateActionbar(actionbar);
510 }
511 });
512
513 subAppEventBus.addHandler(SearchEvent.class, new SearchEvent.Handler() {
514
515 @Override
516 public void onSearch(SearchEvent event) {
517 BrowserLocation location = getCurrentLocation();
518 if (StringUtils.isNotBlank(event.getSearchExpression())) {
519 location.updateViewType(ViewType.SEARCH);
520 }
521 location.updateQuery(event.getSearchExpression());
522 getAppContext().updateSubAppLocation(getSubAppContext(), location);
523 updateActionbar(actionbar);
524 }
525 });
526 }
527
528 public static List<Item> getJcrItemsExceptOne(final String workspaceName, List<String> ids, String itemIdToExclude) {
529 List<Item> items = JcrItemUtil.getJcrItems(workspaceName, ids);
530 if (itemIdToExclude == null) {
531 return items;
532 }
533 for (int i = 0; i < items.size(); i++) {
534 try {
535 if (itemIdToExclude.equals(JcrItemUtil.getItemId(items.get(i)))) {
536 items.set(i, null);
537 }
538 } catch (RepositoryException e) {
539 log.debug("Cannot get item ID for item [{}].", items.get(i));
540 }
541 }
542 return items;
543 }
544 }