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.dialog.connector.OverlayConnector;
37 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.ShellState;
38 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ActivateAppEvent;
39 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.AppRequestedEvent;
40 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.CurrentAppCloseEvent;
41 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.FullScreenEvent;
42 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.HideShellAppsEvent;
43 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.HideShellAppsRequestedEvent;
44 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ShellAppRequestedEvent;
45 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ShellAppStartedEvent;
46 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ShellAppStartingEvent;
47 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ShellAppsHiddenEvent;
48 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shell.rpc.ShellClientRpc;
49 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shell.rpc.ShellServerRpc;
50 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.ShellMessageWidget.MessageType;
51 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.connector.ViewportConnector;
52 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.widget.AppsViewportWidget;
53 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.widget.ViewportWidget;
54 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.Fragment;
55 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.ShellAppType;
56 import info.magnolia.ui.vaadin.gwt.client.shared.magnoliashell.ViewportType;
57 import info.magnolia.ui.vaadin.magnoliashell.MagnoliaShell;
58
59 import java.util.Iterator;
60 import java.util.List;
61 import java.util.Map.Entry;
62 import java.util.logging.Level;
63 import java.util.logging.Logger;
64
65 import com.google.gwt.core.client.Scheduler;
66 import com.google.gwt.event.logical.shared.ValueChangeEvent;
67 import com.google.gwt.event.logical.shared.ValueChangeHandler;
68 import com.google.gwt.user.client.History;
69 import com.google.gwt.user.client.ui.Widget;
70 import com.google.web.bindery.event.shared.EventBus;
71 import com.google.web.bindery.event.shared.SimpleEventBus;
72 import com.vaadin.client.ComponentConnector;
73 import com.vaadin.client.ConnectorHierarchyChangeEvent;
74 import com.vaadin.client.Util;
75 import com.vaadin.client.communication.RpcProxy;
76 import com.vaadin.client.communication.StateChangeEvent;
77 import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
78 import com.vaadin.client.ui.AbstractLayoutConnector;
79 import com.vaadin.client.ui.layout.ElementResizeEvent;
80 import com.vaadin.client.ui.layout.ElementResizeListener;
81 import com.vaadin.client.ui.nativebutton.NativeButtonConnector;
82 import com.vaadin.shared.ui.Connect;
83
84
85
86
87 @Connect(MagnoliaShell.class)
88 public class MagnoliaShellConnector extends AbstractLayoutConnector implements MagnoliaShellView.Presenter {
89
90 private static final Logger log = Logger.getLogger(MagnoliaShellConnector.class.getName());
91
92 private ShellServerRpc rpc = RpcProxy.create(ShellServerRpc.class, this);
93 private MagnoliaShellView view;
94 private EventBus eventBus = new SimpleEventBus();
95 private Fragment lastHandledFragment;
96 private boolean isHistoryInitialized = false;
97
98 @Override
99 protected void init() {
100 super.init();
101 addStateChangeHandler(new StateChangeHandler() {
102 @Override
103 public void onStateChanged(StateChangeEvent event) {
104 MagnoliaShellState state = getState();
105 Iterator<Entry<ShellAppType, Integer>> it = state.indications.entrySet().iterator();
106 while (it.hasNext()) {
107 final Entry<ShellAppType, Integer> entry = it.next();
108 view.setShellAppIndication(entry.getKey(), entry.getValue());
109 }
110 }
111 });
112
113 registerRpc(ShellClientRpc.class, new ShellClientRpc() {
114 @Override
115 public void showMessage(String type, String topic, String msg, String id) {
116 view.showMessage(MessageType.valueOf(type), topic, msg, id);
117 }
118
119 @Override
120 public void hideAllMessages() {
121 view.hideAllMessages();
122 }
123
124 @Override
125 public void setFullScreen(boolean isFullScreen) {
126 MagnoliaShellConnector.this.doFullScreen(isFullScreen);
127 }
128 });
129
130 getLayoutManager().addElementResizeListener(getWidget().getElement(), new ElementResizeListener() {
131 @Override
132 public void onElementResize(ElementResizeEvent e) {
133 view.updateShellDivet();
134 }
135 });
136
137 eventBus.addHandler(CurrentAppCloseEvent.TYPE, new CurrentAppCloseEvent.Handler() {
138 @Override
139 public void onViewportClose(CurrentAppCloseEvent event) {
140 closeCurrentApp();
141 }
142 });
143
144
145
146
147 eventBus.addHandler(ShellAppStartingEvent.TYPE, new ShellAppStartingEvent.Handler() {
148 @Override
149 public void onShellAppStarting(ShellAppStartingEvent event) {
150 ShellState.get().setShellAppStarting();
151 view.onShellAppStarting(event.getType());
152 }
153 });
154
155
156
157
158 eventBus.addHandler(ShellAppStartedEvent.TYPE, new ShellAppStartedEvent.Handler() {
159 @Override
160 public void onShellAppStarted(ShellAppStartedEvent event) {
161 final String currentHistoryToken = History.getToken();
162 final Fragment fragment = Fragment.fromString(currentHistoryToken);
163 String newShellAppName = event.getType().name();
164 ShellState.get().setShellAppStarted();
165 if (currentHistoryToken.isEmpty() || !fragment.isShellApp() || !fragment.getAppName().equalsIgnoreCase(newShellAppName)) {
166 final Fragment newFragment = Fragment.fromString("shell:" + newShellAppName.toLowerCase() + ":");
167 History.newItem(newFragment.toFragment(), false);
168 lastHandledFragment = newFragment;
169 activateShellApp(newFragment);
170 }
171 }
172 });
173
174
175
176
177
178 eventBus.addHandler(HideShellAppsRequestedEvent.TYPE, new HideShellAppsRequestedEvent.Handler() {
179 @Override
180 public void onHideShellAppsRequest(HideShellAppsRequestedEvent event) {
181 if (ShellState.get().isShellAppStarted() || ShellState.get().isShellAppStarting()) {
182 onHideShellAppsRequested();
183 }
184 }
185 });
186
187
188
189
190 eventBus.addHandler(ShellAppsHiddenEvent.TYPE, new ShellAppsHiddenEvent.Handler() {
191 @Override
192 public void onShellAppsHidden(ShellAppsHiddenEvent event) {
193 rpc.stopCurrentShellApp();
194 }
195 });
196
197
198
199
200 eventBus.addHandler(ActivateAppEvent.TYPE, new ActivateAppEvent.Handler() {
201 @Override
202 public void onActivateApp(ActivateAppEvent event) {
203 if (!ShellState.get().isShellAppStarting()) {
204 log.log(Level.WARNING, "Starting from swipe/keyboard: " + event.getName());
205 ShellState.get().setAppStarting();
206 rpc.activateApp(Fragment.fromString("app:" + event.getName()));
207 }
208 }
209 });
210
211
212
213
214 History.addValueChangeHandler(new ValueChangeHandler<String>() {
215 @Override
216 public void onValueChange(ValueChangeEvent<String> event) {
217 final Fragment newFragment = Fragment.fromString(event.getValue());
218
219 if (newFragment.equals(lastHandledFragment)) {
220 return;
221 }
222
223 if (newFragment.isShellApp()) {
224 if (!getConnection().hasActiveRequest() || !ShellState.get().isAppStarting()) {
225 doShowShellApp(newFragment.resolveShellAppType());
226 }
227 } else {
228
229 if (lastHandledFragment != null) {
230 log.warning("App navigation from " +lastHandledFragment.toFragment()+ " to " + newFragment.toFragment() + (!newFragment.sameSubApp(lastHandledFragment) ? "" : "not") +", request will %s be sent");
231 }
232
233
234 final Fragment latestLoadedAppLocation = getState().currentAppUriFragment;
235
236
237
238
239
240 if (newFragment.isSameApp(latestLoadedAppLocation)) {
241 log.warning("Switching to 'APP STARTED' state since the updated app is already active");
242 ShellState.get().setAppStarted();
243 }
244
245
246
247
248
249
250 if (!getConnection().hasActiveRequest() || !newFragment.isSameApp(lastHandledFragment)) {
251 loadApp(newFragment.getAppName());
252 }
253
254 if (ShellState.get().isAppStarting() || !getConnection().hasActiveRequest()) {
255 rpc.activateApp(newFragment);
256 Scheduler.get().scheduleFinally(new Scheduler.RepeatingCommand() {
257 @Override
258 public boolean execute() {
259 boolean doneProcessingRequest = !getConnection().hasActiveRequest();
260 if (doneProcessingRequest) {
261
262 }
263 return !doneProcessingRequest;
264 }
265 });
266
267 }
268 }
269 lastHandledFragment = newFragment;
270 }
271 });
272 }
273
274 @Override
275 public void activateShellApp(Fragment f) {
276 rpc.activateShellApp(f);
277 }
278
279 @Override
280 public void closeCurrentApp() {
281 ShellState.get().setAppClosing();
282 rpc.stopCurrentApp();
283 }
284
285 @Override
286 public void removeMessage(String id) {
287 rpc.removeMessage(id);
288 }
289
290 @Override
291 public void loadApp(String appName) {
292 view.onAppStarting();
293 eventBus.fireEvent(new AppRequestedEvent(appName));
294 }
295
296 private void doShowShellApp(ShellAppType shellAppType) {
297 eventBus.fireEvent(new ShellAppRequestedEvent(shellAppType));
298 }
299
300 private void doFullScreen(boolean isFullScreen) {
301 eventBus.fireEvent(new FullScreenEvent(isFullScreen));
302 }
303
304 @Override
305 public void onHideShellAppsRequested() {
306 final AppsViewportWidget appViewportWidget = (AppsViewportWidget) ((ComponentConnector)getState().viewports.get(ViewportType.APP)).getWidget();
307
308
309 Widget currentApp = appViewportWidget.getCurrentApp();
310 if (currentApp != null) {
311 view.onAppStarting();
312 ShellState.get().setShellAppClosing();
313 eventBus.fireEvent(new HideShellAppsEvent());
314 } else {
315 doShowShellApp(ShellAppType.APPLAUNCHER);
316 }
317 }
318
319 @Override
320 public void showShellApp(ShellAppType type) {
321
322
323
324 if (!getConnection().hasActiveRequest()) {
325 doShowShellApp(type);
326 }
327 }
328
329 @Override
330 public void updateCaption(ComponentConnector connector) {}
331
332 @Override
333 public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
334 List<ComponentConnector> children = getChildComponents();
335 for (ComponentConnector connector : children) {
336 if (connector instanceof ViewportConnector) {
337 final ViewportConnector vc = (ViewportConnector) connector;
338 view.updateViewport(vc.getWidget(), vc.getType());
339 vc.setEventBus(eventBus);
340 } else if (connector instanceof OverlayConnector) {
341 if (!view.hasOverlay(connector.getWidget())) {
342 final OverlayConnector oc = (OverlayConnector) connector;
343 ComponentConnector overlayParent = (ComponentConnector) oc.getState().overlayParent;
344 Widget parentWidget = overlayParent.getWidget();
345 view.openOverlayOnWidget(oc.getWidget(), parentWidget);
346 }
347 } else if (connector instanceof NativeButtonConnector) {
348 view.setUserMenu(connector.getWidget());
349 }
350 }
351
352 List<ComponentConnector> oldChildren = event.getOldChildren();
353 oldChildren.removeAll(children);
354 for (ComponentConnector cc : oldChildren) {
355 cc.getWidget().removeFromParent();
356 }
357 }
358
359 @Override
360 protected Widget createWidget() {
361 this.view = new MagnoliaShellViewImpl();
362 this.view.setPresenter(this);
363 return view.asWidget();
364 }
365
366 @Override
367 public MagnoliaShellState getState() {
368 return (MagnoliaShellState) super.getState();
369 }
370
371 @Override
372 public void updateViewportLayout(ViewportWidget activeViewport) {
373 getLayoutManager().setNeedsMeasure(Util.findConnectorFor(activeViewport));
374 getLayoutManager().layoutNow();
375 }
376
377
378 @Override
379 public void initHistory() {
380 Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
381 @Override
382 public void execute() {
383 if (!isHistoryInitialized) {
384 isHistoryInitialized = true;
385 History.fireCurrentHistoryState();
386 }
387 }
388 });
389 }
390
391 }