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