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 char c = event.getCharCode();
136
137 switch (c) {
138
139
140 case '1':
141 mainAppLauncher.toggleShellApp(ShellAppType.APPLAUNCHER);
142 break;
143 case '2':
144 mainAppLauncher.toggleShellApp(ShellAppType.PULSE);
145 break;
146 case '3':
147 mainAppLauncher.toggleShellApp(ShellAppType.FAVORITE);
148 break;
149
150
151 case '9':
152
153 if (appViewport().readyForAppSwipeOrShortcutNavigation()) {
154 ShellState.get().setAppStarting();
155 appViewport().goToPreviousApp();
156 }
157 break;
158 case '0':
159
160 if (appViewport().readyForAppSwipeOrShortcutNavigation()) {
161 ShellState.get().setAppStarting();
162 appViewport().goToNextApp();
163 }
164 break;
165
166 default:
167
168 }
169 }
170 };
171 RootPanel.get().addDomHandler(keyboardShortcutHandler, KeyPressEvent.getType());
172
173
174
175
176
177
178 KeyPressHandler escapeKeyPressHandler = new KeyPressHandler() {
179 @Override
180 public void onKeyPress(KeyPressEvent event) {
181 int code = event.getNativeEvent().getKeyCode();
182 if (code == KeyCodes.KEY_ESCAPE) {
183 blurHelper.getElement().focus();
184 }
185 }
186 };
187 RootPanel.get().addDomHandler(escapeKeyPressHandler, KeyPressEvent.getType());
188 }
189
190
191
192
193
194
195 protected boolean isFocusedElementAnInputField() {
196 Element focused = elementInFocus(RootPanel.get().getElement());
197 String tagName = focused.getTagName();
198 if ("input".equalsIgnoreCase(tagName) || "select".equalsIgnoreCase(tagName) || "textarea".equalsIgnoreCase(tagName)) {
199 return true;
200 }
201 return false;
202 }
203
204 protected native Element elementInFocus(Element element)
205
206 ;
207
208
209 protected AppsViewportWidget appViewport() {
210 return (AppsViewportWidget) viewports.get(ViewportType.APP);
211 }
212
213 protected void replaceWidget(final Widget oldWidget, final Widget newWidget) {
214 if (oldWidget != newWidget) {
215 if (oldWidget != null) {
216 remove(oldWidget);
217 }
218 }
219 if (getWidgetIndex(newWidget) < 0) {
220 add(newWidget, viewportSlot);
221 }
222 }
223
224 @Override
225 public void setPresenter(Presenter presenter) {
226 this.presenter = presenter;
227 mainAppLauncher.setListener(presenter);
228 }
229
230 @Override
231 public void showMessage(MessageType type, String topic, String message, String id) {
232 final ShellMessageWidget msg;
233 switch (type) {
234 case WARNING:
235 msg = new VWarningMessage(this, topic, message, id);
236 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
237 lowPriorityMessage.hide();
238 }
239 lowPriorityMessage = msg;
240 break;
241 case INFO:
242 msg = new VInfoMessage(this, topic, message, id);
243 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
244 lowPriorityMessage.hide();
245 }
246 lowPriorityMessage = msg;
247 break;
248 case ERROR:
249 msg = new VShellErrorMessage(this, topic, message, id);
250 if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
251 hiPriorityMessage.hide();
252 }
253 hiPriorityMessage = msg;
254 break;
255 default:
256 msg = null;
257 }
258 Scheduler.get().scheduleDeferred(new ScheduledCommand() {
259
260 @Override
261 public void execute() {
262 if (msg != null) {
263 add(msg, getElement());
264 }
265 }
266 });
267 }
268
269 @Override
270 public void hideAllMessages() {
271 if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
272 hiPriorityMessage.hideWithoutTransition();
273 }
274 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
275 lowPriorityMessage.hideWithoutTransition();
276 }
277
278 hiPriorityMessage = null;
279 lowPriorityMessage = null;
280 }
281
282 @Override
283 public void updateViewport(ViewportWidget viewport, ViewportType type) {
284 ViewportWidget oldViewport = viewports.get(type);
285 if (oldViewport != viewport) {
286 replaceWidget(oldViewport, viewport);
287 viewports.put(type, viewport);
288 }
289 }
290
291 @Override
292 public void shiftViewportsVertically(int shiftPx, boolean animated) {
293 viewportShifter.setProperty("top", mainAppLauncher.getOffsetHeight() + shiftPx);
294 if (shiftPx == 0 || shiftPx == 60) {
295 viewportShifter.clearTopAfterThisAnimation();
296 }
297 viewportShifter.run(animated ? 300 : 0, viewportSlot);
298 }
299
300 @Override
301 public void setShellAppIndication(ShellAppType type, int indication) {
302 mainAppLauncher.setIndication(type, indication);
303 }
304
305 @Override
306 public void closeMessageEager(final String id) {
307 presenter.removeMessage(id);
308 }
309
310 @Override
311 public void navigateToMessageDetails(String id) {
312 presenter.activateShellApp(Fragment.fromString("shell:pulse:messages/" + id));
313 }
314
315 @Override
316 public void updateShellDivet() {
317 mainAppLauncher.updateDivet();
318 }
319
320 @Override
321 public void openOverlayOnWidget(Widget overlayWidget, Widget overlayParent) {
322 add(overlayWidget, overlayParent.getElement());
323 }
324
325 @Override
326 public void onShellAppStarting(ShellAppType type) {
327 mainAppLauncher.activateControl(type);
328 }
329
330 @Override
331 public void onAppStarting() {
332 mainAppLauncher.deactivateControls();
333 }
334
335 @Override
336 public void setUserMenu(Widget widget) {
337 mainAppLauncher.setUserMenu(widget);
338 }
339
340 @Override
341 public void onLoad() {
342 super.onLoad();
343 presenter.initHistory();
344 }
345
346 @Override
347 public boolean hasOverlay(Widget widget) {
348 return getWidgetIndex(widget) != -1;
349 }
350
351
352 }