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.vaadin.gwt.client.magnoliashell.shell;
35
36 import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryCallback;
37 import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryWrapper;
38 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.ShellState;
39 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.ShellMessageWidget;
40 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.ShellMessageWidget.MessageType;
41 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VInfoMessage;
42 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VShellErrorMessage;
43 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VWarningMessage;
44 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.animation.JQueryAnimation;
45 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.widget.AppsViewportWidget;
46 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.widget.ViewportWidget;
47 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.Fragment;
48 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.ShellAppType;
49 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.ViewportType;
50
51 import java.util.EnumMap;
52 import java.util.Map;
53
54 import com.google.gwt.core.client.Scheduler;
55 import com.google.gwt.core.client.Scheduler.ScheduledCommand;
56 import com.google.gwt.event.dom.client.KeyCodes;
57 import com.google.gwt.event.dom.client.KeyPressEvent;
58 import com.google.gwt.event.dom.client.KeyPressHandler;
59 import com.google.gwt.user.client.DOM;
60 import com.google.gwt.user.client.Element;
61 import com.google.gwt.user.client.ui.FocusPanel;
62 import com.google.gwt.user.client.ui.RootPanel;
63 import com.google.gwt.user.client.ui.Widget;
64 import com.googlecode.mgwt.ui.client.widget.touch.TouchPanel;
65
66
67
68
69 public class MagnoliaShellViewImpl extends TouchPanel implements MagnoliaShellView {
70
71 public static final String CLASS_NAME = "v-magnolia-shell";
72
73 public static final String VIEWPORT_SLOT_CLASS_NAME = "v-shell-viewport-slot";
74
75 private final Map<ViewportType, ViewportWidget> viewports = new EnumMap<ViewportType, ViewportWidget>(ViewportType.class);
76
77 private final ShellAppLauncher mainAppLauncher;
78
79 private ShellMessageWidget lowPriorityMessage;
80
81 private ShellMessageWidget hiPriorityMessage;
82
83 private Presenter presenter;
84
85 private JQueryAnimation viewportShifter = new JQueryAnimation();
86
87 private final Element viewportSlot = DOM.createDiv();
88
89
90 private final FocusPanel blurHelper = new FocusPanel();
91
92 public MagnoliaShellViewImpl() {
93 super();
94 this.mainAppLauncher = new ShellAppLauncher();
95 getElement().setClassName(CLASS_NAME);
96 viewportSlot.setClassName(VIEWPORT_SLOT_CLASS_NAME);
97 add(mainAppLauncher, getElement());
98
99
100 getElement().appendChild(viewportSlot);
101 viewportShifter.addCallback(new JQueryCallback() {
102 @Override
103 public void execute(JQueryWrapper query) {
104 presenter.updateViewportLayout(appViewport());
105 }
106 });
107
108 initKeyboardShortcutSupport();
109 }
110
111
112
113
114
115
116 protected void initKeyboardShortcutSupport() {
117
118 add(blurHelper, getElement());
119
120 KeyPressHandler keyboardShortcutHandler = new KeyPressHandler() {
121
122 @Override
123 public void onKeyPress(KeyPressEvent event) {
124
125
126 if (isFocusedElementAnInputField()) {
127 return;
128 }
129
130
131 if (event.isAnyModifierKeyDown()) {
132 return;
133 }
134
135 if (isFocusedElementGroovyConsole()) {
136 return;
137 }
138
139 char c = event.getCharCode();
140
141 switch (c) {
142
143
144 case '1':
145 mainAppLauncher.toggleShellApp(ShellAppType.APPLAUNCHER);
146 break;
147 case '2':
148 mainAppLauncher.toggleShellApp(ShellAppType.PULSE);
149 break;
150 case '3':
151 mainAppLauncher.toggleShellApp(ShellAppType.FAVORITE);
152 break;
153
154
155 case '9':
156
157 if (appViewport().readyForAppSwipeOrShortcutNavigation()) {
158 ShellState.get().setAppStarting();
159 appViewport().goToPreviousApp();
160 }
161 break;
162 case '0':
163
164 if (appViewport().readyForAppSwipeOrShortcutNavigation()) {
165 ShellState.get().setAppStarting();
166 appViewport().goToNextApp();
167 }
168 break;
169
170 default:
171
172 }
173 }
174 };
175 RootPanel.get().addDomHandler(keyboardShortcutHandler, KeyPressEvent.getType());
176
177
178
179
180
181
182 KeyPressHandler escapeKeyPressHandler = new KeyPressHandler() {
183 @Override
184 public void onKeyPress(KeyPressEvent event) {
185 int code = event.getNativeEvent().getKeyCode();
186 if (code == KeyCodes.KEY_ESCAPE) {
187 blurHelper.getElement().focus();
188 }
189 }
190 };
191 RootPanel.get().addDomHandler(escapeKeyPressHandler, KeyPressEvent.getType());
192 }
193
194
195
196
197 protected boolean isFocusedElementAnInputField() {
198 Element focused = elementInFocus(RootPanel.get().getElement());
199 String tagName = focused.getTagName();
200
201 if ("input".equalsIgnoreCase(tagName) || "select".equalsIgnoreCase(tagName) || "textarea".equalsIgnoreCase(tagName)) {
202 return true;
203 }
204 return false;
205 }
206
207 protected native Element elementInFocus(Element element)
208
209 ;
210
211
212 protected AppsViewportWidget appViewport() {
213 return (AppsViewportWidget) viewports.get(ViewportType.APP);
214 }
215
216 protected void replaceWidget(final Widget oldWidget, final Widget newWidget) {
217 if (oldWidget != newWidget) {
218 if (oldWidget != null) {
219 remove(oldWidget);
220 }
221 }
222 if (getWidgetIndex(newWidget) < 0) {
223 add(newWidget, viewportSlot);
224 }
225 }
226
227 @Override
228 public void setPresenter(Presenter presenter) {
229 this.presenter = presenter;
230 mainAppLauncher.setListener(presenter);
231 }
232
233 @Override
234 public void showMessage(MessageType type, String topic, String message, String id) {
235 final ShellMessageWidget msg;
236 switch (type) {
237 case WARNING:
238 msg = new VWarningMessage(this, topic, message, id);
239 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
240 lowPriorityMessage.hide();
241 }
242 lowPriorityMessage = msg;
243 break;
244 case INFO:
245 msg = new VInfoMessage(this, topic, message, id);
246 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
247 lowPriorityMessage.hide();
248 }
249 lowPriorityMessage = msg;
250 break;
251 case ERROR:
252 msg = new VShellErrorMessage(this, topic, message, id);
253 if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
254 hiPriorityMessage.hide();
255 }
256 hiPriorityMessage = msg;
257 break;
258 default:
259 msg = null;
260 }
261 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
262
263 @Override
264 public void execute() {
265 if (msg != null) {
266 add(msg, getElement());
267 }
268 }
269 });
270 }
271
272 @Override
273 public void hideAllMessages() {
274 if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
275 hiPriorityMessage.hideWithoutTransition();
276 }
277 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
278 lowPriorityMessage.hideWithoutTransition();
279 }
280
281 hiPriorityMessage = null;
282 lowPriorityMessage = null;
283 }
284
285 @Override
286 public void updateViewport(ViewportWidget viewport, ViewportType type) {
287 ViewportWidget oldViewport = viewports.get(type);
288 if (oldViewport != viewport) {
289 replaceWidget(oldViewport, viewport);
290 viewports.put(type, viewport);
291 }
292 }
293
294 @Override
295 public void shiftViewportsVertically(int shiftPx, boolean animated) {
296 viewportShifter.setProperty("top", mainAppLauncher.getOffsetHeight() + shiftPx);
297 if (shiftPx == 0 || shiftPx == 60) {
298 viewportShifter.clearTopAfterThisAnimation();
299 }
300 viewportShifter.run(animated ? 300 : 0, viewportSlot);
301 }
302
303 @Override
304 public void setShellAppIndication(ShellAppType type, int indication) {
305 mainAppLauncher.setIndication(type, indication);
306 }
307
308 @Override
309 public void closeMessageEager(final String id) {
310 presenter.removeMessage(id);
311 }
312
313 @Override
314 public void navigateToMessageDetails(String id) {
315 presenter.activateShellApp(Fragment.fromString("shell:pulse:messages/" + id));
316 }
317
318 @Override
319 public void updateShellDivet() {
320 mainAppLauncher.updateDivet();
321 }
322
323 @Override
324 public void openOverlayOnWidget(Widget overlayWidget, Widget overlayParent) {
325 add(overlayWidget, overlayParent.getElement());
326 }
327
328 @Override
329 public void onShellAppStarting(ShellAppType type) {
330 mainAppLauncher.activateControl(type);
331 }
332
333 @Override
334 public void onAppStarting() {
335 mainAppLauncher.deactivateControls();
336 }
337
338 @Override
339 public void setUserMenu(Widget widget) {
340 mainAppLauncher.setUserMenu(widget);
341 }
342
343 @Override
344 public void onLoad() {
345 super.onLoad();
346 presenter.initHistory();
347 }
348
349 @Override
350 public boolean hasOverlay(Widget widget) {
351 return getWidgetIndex(widget) != -1;
352 }
353
354
355
356
357
358 private boolean isFocusedElementGroovyConsole() {
359 Element focused = elementInFocus(RootPanel.get().getElement());
360
361 String className = focused.getClassName();
362
363 if (className.contains("terminal")) {
364 return true;
365 }
366 return false;
367 }
368
369 }