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.ActionbarView;
39 import info.magnolia.ui.actionbar.definition.ActionbarDefinition;
40 import info.magnolia.ui.api.action.ActionExecutionException;
41 import info.magnolia.ui.api.action.ActionExecutor;
42 import info.magnolia.ui.api.app.AppContext;
43 import info.magnolia.ui.api.app.SubAppContext;
44 import info.magnolia.ui.api.app.SubAppEventBus;
45 import info.magnolia.ui.api.availability.AvailabilityChecker;
46 import info.magnolia.ui.api.availability.AvailabilityDefinition;
47 import info.magnolia.ui.api.event.AdmincentralEventBus;
48 import info.magnolia.ui.api.event.ContentChangedEvent;
49 import info.magnolia.ui.api.message.Message;
50 import info.magnolia.ui.api.message.MessageType;
51 import info.magnolia.ui.imageprovider.ImageProvider;
52 import info.magnolia.ui.vaadin.integration.NullItem;
53 import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
54 import info.magnolia.ui.workbench.WorkbenchPresenter;
55 import info.magnolia.ui.workbench.WorkbenchView;
56 import info.magnolia.ui.workbench.event.ActionEvent;
57 import info.magnolia.ui.workbench.event.ItemDoubleClickedEvent;
58 import info.magnolia.ui.workbench.event.ItemShortcutKeyEvent;
59 import info.magnolia.ui.workbench.event.SearchEvent;
60 import info.magnolia.ui.workbench.event.SelectionChangedEvent;
61
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Collection;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Set;
68
69 import javax.inject.Inject;
70 import javax.inject.Named;
71
72 import org.apache.commons.collections4.ListUtils;
73 import org.apache.commons.collections4.Predicate;
74 import org.apache.commons.lang3.StringUtils;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 import com.vaadin.data.Item;
79 import com.vaadin.event.ShortcutAction;
80 import com.vaadin.server.Resource;
81
82
83
84
85
86
87
88
89
90
91
92
93
94 public class BrowserPresenter implements ActionbarPresenter.Listener, BrowserView.Listener {
95
96 private static final Logger log = LoggerFactory.getLogger(BrowserPresenter.class);
97
98 private final Predicate<Object> itemExistsPredicate = new Predicate<Object>() {
99 @Override
100 public boolean evaluate(final Object object) {
101 return verifyItemExists(object);
102 }
103 };
104
105 private final WorkbenchPresenter workbenchPresenter;
106
107 private final ActionExecutor actionExecutor;
108
109 private final BrowserSubAppDescriptor subAppDescriptor;
110
111 private final BrowserView view;
112
113 private final EventBus admincentralEventBus;
114
115 private final EventBus subAppEventBus;
116
117 private final ActionbarPresenter actionbarPresenter;
118
119 private final AvailabilityChecker availabilityChecker;
120
121 private final AppContext appContext;
122
123 private final ContentConnector contentConnector;
124
125 private final ImageProvider imageProvider;
126
127 @Inject
128 public BrowserPresenter(
129 BrowserView view,
130 SubAppContext subAppContext,
131 ActionExecutor actionExecutor,
132 @Named(AdmincentralEventBus.NAME) EventBus admincentralEventBus,
133 @Named(SubAppEventBus.NAME) EventBus subAppEventBus,
134 ContentConnector contentConnector,
135 ImageProvider imageProvider,
136 WorkbenchPresenter workbenchPresenter,
137 ActionbarPresenter actionbarPresenter,
138 AvailabilityChecker availabilityChecker) {
139 this.view = view;
140 this.appContext = subAppContext.getAppContext();
141 this.subAppDescriptor = (BrowserSubAppDescriptor) subAppContext.getSubAppDescriptor();
142 this.actionExecutor = actionExecutor;
143 this.admincentralEventBus = admincentralEventBus;
144 this.subAppEventBus = subAppEventBus;
145 this.contentConnector = contentConnector;
146 this.imageProvider = imageProvider;
147 this.workbenchPresenter = workbenchPresenter;
148 this.actionbarPresenter = actionbarPresenter;
149 this.availabilityChecker = availabilityChecker;
150 }
151
152 public BrowserView start() {
153 actionbarPresenter.setListener(this);
154
155 WorkbenchView workbenchView = workbenchPresenter.start(subAppDescriptor.getWorkbench(), subAppDescriptor.getImageProvider(), subAppEventBus);
156 ActionbarView actionbar = actionbarPresenter.start(subAppDescriptor.getActionbar(), subAppDescriptor.getActions());
157
158 view.setWorkbenchView(workbenchView);
159 view.setActionbarView(actionbar);
160 view.setListener(this);
161
162 bindHandlers();
163 return view;
164 }
165
166 private void bindHandlers() {
167 admincentralEventBus.addHandler(ContentChangedEvent.class, new ContentChangedEvent.Handler() {
168
169 @Override
170 public void onContentChanged(ContentChangedEvent event) {
171 List<Object> itemIds = new ArrayList<>();
172 if (event.getItemId() instanceof Collection) {
173 for (Object itemId : (Collection<?>) event.getItemId()) {
174 itemIds.add(itemId);
175 }
176 } else {
177 itemIds.add(event.getItemId());
178 }
179 workbenchPresenter.refresh();
180
181
182
183 List<Object> existingSelectedItemIds = ListUtils.select(itemIds, itemExistsPredicate);
184 if (existingSelectedItemIds.isEmpty()) {
185 existingSelectedItemIds = ListUtils.select(getSelectedItemIds(), itemExistsPredicate);
186 }
187
188 workbenchPresenter.select(existingSelectedItemIds);
189
190 if (event.isItemContentChanged() && !existingSelectedItemIds.isEmpty()) {
191 workbenchPresenter.expand(existingSelectedItemIds.get(0));
192 }
193
194
195 if (!existingSelectedItemIds.isEmpty()) {
196 refreshActionbarPreviewImage(existingSelectedItemIds.get(0));
197 }
198 }
199 });
200
201 subAppEventBus.addHandler(SelectionChangedEvent.class, new SelectionChangedEvent.Handler() {
202
203 @Override
204 public void onSelectionChanged(SelectionChangedEvent event) {
205
206 refreshActionbarPreviewImage(event.getFirstItemId());
207 }
208 });
209
210 subAppEventBus.addHandler(ItemDoubleClickedEvent.class, new ItemDoubleClickedEvent.Handler() {
211
212 @Override
213 public void onItemDoubleClicked(ItemDoubleClickedEvent event) {
214 executeDefaultAction();
215 }
216 });
217
218 subAppEventBus.addHandler(SearchEvent.class, new SearchEvent.Handler() {
219
220 @Override
221 public void onSearch(SearchEvent event) {
222 workbenchPresenter.doSearch(event.getSearchExpression());
223 }
224 });
225
226 subAppEventBus.addHandler(ActionEvent.class, new ActionEvent.Handler() {
227
228 @Override
229 public void onAction(ActionEvent event) {
230 executeAction(event.getActionName(), event.getItemIds(), event.getParameters());
231 }
232 });
233
234 subAppEventBus.addHandler(ItemShortcutKeyEvent.class, new ItemShortcutKeyEvent.Handler() {
235
236 @Override
237 public void onItemShortcutKeyEvent(ItemShortcutKeyEvent event) {
238 int keyCode = event.getKeyCode();
239 switch (keyCode) {
240 case ShortcutAction.KeyCode.ENTER:
241 executeDefaultAction();
242 break;
243 case ShortcutAction.KeyCode.DELETE:
244 executeDeleteAction();
245 break;
246 }
247
248 }
249 });
250 }
251
252 private void refreshActionbarPreviewImage(Object itemId) {
253 Object previewResource = getPreviewImageForId(itemId);
254 if (previewResource instanceof Resource) {
255 getActionbarPresenter().setPreview((Resource) previewResource);
256 } else {
257 getActionbarPresenter().setPreview(null);
258 }
259 }
260
261 protected boolean verifyItemExists(Object itemId) {
262 return contentConnector.canHandleItem(itemId) && contentConnector.getItem(itemId) != null;
263 }
264
265 public List<Object> getSelectedItemIds() {
266 return workbenchPresenter.getSelectedIds();
267 }
268
269
270
271
272
273 public String getDefaultViewType() {
274 return workbenchPresenter.getDefaultViewType();
275 }
276
277 public boolean hasViewType(String viewType) {
278 return workbenchPresenter.hasViewType(viewType);
279 }
280
281 public BrowserView getView() {
282 return view;
283 }
284
285 public ActionbarPresenter getActionbarPresenter() {
286 return actionbarPresenter;
287 }
288
289
290
291
292
293 public void resync(final List<Object> itemIds, final String viewType, final String query) {
294 workbenchPresenter.resynch(itemIds, viewType, query);
295 }
296
297 protected Object getPreviewImageForId(Object itemId) {
298 if (imageProvider != null) {
299 return imageProvider.getThumbnailResource(itemId, ImageProvider.PORTRAIT_GENERATOR);
300 }
301 return null;
302 }
303
304 @Override
305 public void onActionbarItemClicked(String actionName) {
306 executeAction(actionName);
307 }
308
309 @Override
310 public void onActionBarSelection(String actionName) {
311 executeAction(actionName);
312 }
313
314
315
316
317 private void executeDefaultAction() {
318 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
319 if (actionbarDefinition == null) {
320 return;
321 }
322 String defaultAction = actionbarDefinition.getDefaultAction();
323 if (StringUtils.isNotEmpty(defaultAction)) {
324 executeAction(defaultAction);
325 }
326 }
327
328
329
330
331 private void executeDeleteAction() {
332 ActionbarDefinition actionbarDefinition = subAppDescriptor.getActionbar();
333 if (actionbarDefinition == null) {
334 return;
335 }
336 String deleteAction = actionbarDefinition.getDeleteAction();
337 if (StringUtils.isNotEmpty(deleteAction)) {
338 executeAction(deleteAction);
339 }
340 }
341
342 private void executeAction(String actionName) {
343 try {
344 AvailabilityDefinition availability = actionExecutor.getActionDefinition(actionName).getAvailability();
345 if (availabilityChecker.isAvailable(availability, getSelectedItemIds())) {
346 Object[] args = prepareActionArgs();
347 actionExecutor.execute(actionName, args);
348 }
349 } catch (ActionExecutionException e) {
350 Message error = new Message(MessageType.ERROR, "An error occurred while executing an action.", e.getMessage());
351 log.error("An error occurred while executing action [{}]", actionName, e);
352 appContext.sendLocalMessage(error);
353 }
354 }
355
356 private void executeAction(String actionName, Set<Object> itemIds, Object... parameters) {
357 try {
358 AvailabilityDefinition availability = actionExecutor.getActionDefinition(actionName).getAvailability();
359 if (availabilityChecker.isAvailable(availability, getSelectedItemIds())) {
360 List<Object> args = new ArrayList<Object>();
361 args.add(itemIds);
362 args.addAll(Arrays.asList(parameters));
363 actionExecutor.execute(actionName, new Object[] { args.toArray(new Object[args.size()]) });
364 }
365 } catch (ActionExecutionException e) {
366 Message error = new Message(MessageType.ERROR, "An error occurred while executing an action.", e.getMessage());
367 log.error("An error occurred while executing action [{}]", actionName, e);
368 appContext.sendLocalMessage(error);
369 }
370 }
371
372 protected Object[] prepareActionArgs() {
373 List<Object> argList = new ArrayList<Object>();
374 List<Item> selectedItems = new ArrayList<Item>();
375
376 List<Object> selectedIds = getSelectedItemIds();
377 if (selectedIds.isEmpty()) {
378 selectedIds.add(contentConnector.getDefaultItemId());
379 }
380 Iterator<Object> idIt = selectedIds.iterator();
381 while (idIt.hasNext()) {
382 selectedItems.add(contentConnector.getItem(idIt.next()));
383 }
384
385 if (selectedItems.size() <= 1) {
386
387 argList.add(selectedItems.isEmpty() ? new NullItem() : selectedItems.get(0));
388 argList.add(selectedItems);
389 } else {
390
391 argList.add(selectedItems);
392 }
393 return argList.toArray(new Object[argList.size()]);
394 }
395 }