View Javadoc

1   /**
2    * This file Copyright (c) 2011 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.vaadin.gwt.client.magnoliashell;
35  
36  import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.AnimationSettings;
37  import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryCallback;
38  import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryWrapper;
39  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.VMagnoliaShell.ViewportType;
40  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.VMainLauncher.ShellAppType;
41  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.AppActivatedEvent;
42  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ShellAppNavigationEvent;
43  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.ViewportCloseEvent;
44  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.handler.ShellNavigationHandler;
45  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.event.handler.ViewportCloseHandler;
46  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VInfoMessage;
47  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VShellErrorMessage;
48  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VShellMessage;
49  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VShellMessage.MessageType;
50  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.shellmessage.VWarningMessage;
51  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.VAppsViewport;
52  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.VAppsViewport.PreloaderCallback;
53  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.VDialogViewport;
54  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.VShellAppsViewport;
55  import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.VShellViewport;
56  
57  import java.util.Collection;
58  import java.util.Collections;
59  import java.util.EnumMap;
60  import java.util.Map;
61  
62  import org.vaadin.artur.icepush.client.ui.VICEPush;
63  
64  import com.google.gwt.core.client.Scheduler;
65  import com.google.gwt.core.client.Scheduler.ScheduledCommand;
66  import com.google.gwt.dom.client.Document;
67  import com.google.gwt.dom.client.IFrameElement;
68  import com.google.gwt.dom.client.Style.Position;
69  import com.google.gwt.dom.client.Style.Unit;
70  import com.google.gwt.event.logical.shared.ValueChangeEvent;
71  import com.google.gwt.event.logical.shared.ValueChangeHandler;
72  import com.google.gwt.user.client.History;
73  import com.google.gwt.user.client.Window;
74  import com.google.gwt.user.client.ui.RootPanel;
75  import com.google.gwt.user.client.ui.Widget;
76  import com.google.web.bindery.event.shared.EventBus;
77  import com.googlecode.mgwt.ui.client.widget.touch.TouchPanel;
78  
79  
80  /**
81   * GWT implementation of MagnoliaShell client side (the view part basically).
82   */
83  public class VMagnoliaShellViewImpl extends TouchPanel implements VMagnoliaShellView, ViewportCloseHandler {
84  
85      public static final String CLASSNAME = "v-magnolia-shell";
86  
87      private final Map<ViewportType, VShellViewport> viewports = new EnumMap<ViewportType, VShellViewport>(ViewportType.class);
88  
89      private ViewportType activeViewportType = null;
90  
91      private final VMainLauncher mainAppLauncher;
92  
93      private Presenter presenter;
94  
95      private final EventBus eventBus;
96  
97      private VShellMessage lowPriorityMessage;
98  
99      private VShellMessage hiPriorityMessage;
100 
101     public VMagnoliaShellViewImpl(final EventBus eventBus) {
102         super();
103         this.eventBus = eventBus;
104         this.mainAppLauncher = new VMainLauncher(eventBus);
105         setStyleName(CLASSNAME);
106         add(mainAppLauncher, getElement());
107         bindEventHandlers();
108 
109         // TODO:Very useful for debugging/development - but perhaps should be removed - Christopher
110         // Zimmermann
111         if (Window.Location.getQueryString().indexOf("tablet=true") >= 0) {
112             RootPanel.get().addStyleName("tablet");
113         }
114 
115         final IFrameElement iframe = Document.get().createIFrameElement();
116         getElement().appendChild(iframe);
117         iframe.setPropertyString("width", "100%");
118         iframe.setPropertyString("height", "100%");
119         iframe.getStyle().setProperty("border", "none");
120         // iframe.setSrc("http://www.sport-express.ru");
121         iframe.getStyle().setPosition(Position.ABSOLUTE);
122         iframe.getStyle().setLeft(0, Unit.PX);
123         iframe.getStyle().setTop(0, Unit.PX);
124         iframe.getStyle().setWidth(100, Unit.PCT);
125         iframe.getStyle().setHeight(100, Unit.PCT);
126         // iframe.getStyle().setZIndex(1000);
127     }
128 
129     private void bindEventHandlers() {
130         eventBus.addHandler(ViewportCloseEvent.TYPE, this);
131         eventBus.addHandler(ShellAppNavigationEvent.TYPE, navigationHandler);
132         eventBus.addHandler(AppActivatedEvent.TYPE, navigationHandler);
133 
134         History.addValueChangeHandler(new ValueChangeHandler<String>() {
135 
136             @Override
137             public void onValueChange(ValueChangeEvent<String> event) {
138                 presenter.handleHistoryChange(event.getValue());
139             }
140         });
141     }
142 
143     protected VAppsViewport getAppViewport() {
144         return (VAppsViewport) viewports.get(ViewportType.APP_VIEWPORT);
145     }
146 
147     protected VShellAppsViewport getShellAppViewport() {
148         return (VShellAppsViewport) viewports.get(ViewportType.SHELL_APP_VIEWPORT);
149     }
150 
151     protected VDialogViewport getDialogViewport() {
152         return (VDialogViewport) viewports.get(ViewportType.DIALOG_VIEWPORT);
153     }
154 
155     @Override
156     public void setActiveViewport(final ViewportType type) {
157         if (activeViewportType != type) {
158             final VShellViewport shellAppViewport = getShellAppViewport();
159             final VShellViewport appViewport = getAppViewport();
160 
161             boolean appViewportActive = type.equals(ViewportType.APP_VIEWPORT);
162             if (appViewportActive) {
163                 mainAppLauncher.deactivateControls();
164             }
165             shellAppViewport.setActive(!appViewportActive);
166             appViewport.setActive(appViewportActive);
167 
168             activeViewportType = type;
169         }
170     }
171 
172     @Override
173     public int getViewportHeight() {
174         int errorMessageHeight = hiPriorityMessage == null &&
175             (getWidgetIndex(hiPriorityMessage) > -1) ? hiPriorityMessage.getOffsetHeight() : 0;
176         return getOffsetHeight() - mainAppLauncher.getExpandedHeight() - errorMessageHeight;
177     }
178 
179     @Override
180     public int getViewportWidth() {
181         return getOffsetWidth();
182     }
183 
184     @Override
185     public boolean remove(Widget w) {
186         presenter.destroyChild(w);
187         return super.remove(w);
188     }
189 
190     protected void replaceWidget(final Widget oldWidget, final Widget newWidget) {
191         if (oldWidget != newWidget) {
192             if (oldWidget != null) {
193                 remove(oldWidget);
194             }
195         }
196         if (getWidgetIndex(newWidget) < 0) {
197             add(newWidget, getElement());
198         }
199     }
200 
201     @Override
202     public void setPresenter(Presenter presenter) {
203         this.presenter = presenter;
204     }
205 
206     @Override
207     public void setWidth(String width) {
208         Integer pxWidth = JQueryWrapper.parseInt(width);
209         boolean widthChanged = pxWidth != null && pxWidth != getOffsetWidth();
210         super.setWidth(width);
211         if (widthChanged) {
212             mainAppLauncher.updateDivet();
213         }
214     }
215 
216     @Override
217     public void showMessage(MessageType type, String topic, String message, String id) {
218         final VShellMessage msg;
219         switch (type) {
220             case WARNING :
221                 msg = new VWarningMessage(this, topic, message, id);
222                 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
223                     lowPriorityMessage.hide();
224                 }
225                 lowPriorityMessage = msg;
226                 break;
227             case INFO :
228                 msg = new VInfoMessage(this, topic, message, id);
229                 if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
230                     lowPriorityMessage.hide();
231                 }
232                 lowPriorityMessage = msg;
233                 break;
234             case ERROR :
235                 msg = new VShellErrorMessage(this, topic, message, id);
236                 if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
237                     hiPriorityMessage.hide();
238                 }
239                 hiPriorityMessage = msg;
240                 break;
241             default :
242                 msg = null;
243         }
244         Scheduler.get().scheduleDeferred(new ScheduledCommand() {
245 
246             @Override
247             public void execute() {
248                 if (msg != null) {
249                     add(msg, getElement());
250                 }
251             }
252         });
253     }
254 
255     @Override
256     public void hideAllMessages() {
257         if (hiPriorityMessage != null && getWidgetIndex(hiPriorityMessage) != -1) {
258             hiPriorityMessage.hideWithoutTransition();
259         }
260         hiPriorityMessage = null;
261 
262         if (lowPriorityMessage != null && getWidgetIndex(lowPriorityMessage) != -1) {
263             lowPriorityMessage.hideWithoutTransition();
264         }
265         lowPriorityMessage = null;
266     }
267 
268     @Override
269     public void updateViewport(VShellViewport viewport, ViewportType type) {
270         doUpdateViewport(viewport, type);
271     }
272 
273     private final ShellNavigationHandler navigationHandler = new ShellNavigationHandler() {
274 
275         @Override
276         public void onAppActivated(AppActivatedEvent event) {
277             final String fragment = activeViewportType.getFragmentPrefix()
278                 + event.getAppId()
279                 + ":"
280                 + event.getSubAppId()
281                 + ";"
282                 + event.getParameter();
283             History.newItem(fragment, false);
284         }
285 
286         @Override
287         public void onShellAppNavigation(final ShellAppNavigationEvent event) {
288 
289             VShellAppsViewport viewport = getShellAppViewport();
290             Widget shellApp = viewport.getShellAppByType(event.getType());
291             ShellAppNavigationEvent refreshEvent = viewport.getRefreshEvent();
292 
293             // if interrupting to another shell app before refresh event comes
294             if (!event.equals(refreshEvent)) {
295                 refreshEvent = null;
296             }
297             if (shellApp != null && refreshEvent == null) {
298                 viewport.setRefreshEvent(event);
299 
300                 // Need to update state of button and divet in the main launcher
301                 mainAppLauncher.activateControl(event.getType());
302 
303                 viewport.setVisibleApp(shellApp);
304                 // trigger viewport active transition if it was not.
305                 if (!viewport.isActive()) {
306                     setActiveViewport(ViewportType.SHELL_APP_VIEWPORT);
307                 }
308             } else {
309                 viewport.setRefreshEvent(null);
310                 getShellAppViewport().showLoadingPane();
311                 presenter.loadShellApp(event.getType(), event.getToken());
312             }
313         }
314 
315     };
316 
317     @Override
318     public void onViewportClose(ViewportCloseEvent event) {
319         final VMagnoliaShell.ViewportType viewportType = event.getViewportType();
320         if (viewportType == ViewportType.SHELL_APP_VIEWPORT) {
321             getShellAppViewport().setClosing(true);
322             presenter.closeCurrentShellApp();
323         } else if (viewportType == ViewportType.APP_VIEWPORT) {
324             presenter.closeCurrentApp();
325         }
326     }
327 
328     @Override
329     public void navigate(String appId, String subAppId, String parameter) {
330         eventBus.fireEvent(new AppActivatedEvent(activeViewportType == ViewportType.SHELL_APP_VIEWPORT, appId, subAppId, parameter));
331     }
332 
333     @Override
334     public Collection<VShellViewport> getViewports() {
335         return Collections.unmodifiableCollection(viewports.values());
336     }
337 
338     @Override
339     public Presenter getPresenter() {
340         return presenter;
341     }
342 
343     @Override
344     public void shiftViewportsVertically(int shiftPx, boolean animated) {
345         for (final VShellViewport viewport : viewports.values()) {
346             final AnimationSettings settings = new AnimationSettings();
347             settings.setProperty("top", "+=" + shiftPx);
348             settings.setProperty("height", "+=" + -shiftPx);
349             settings.addCallback(new JQueryCallback() {
350 
351                 @Override
352                 public void execute(JQueryWrapper query) {
353                     getPresenter().updateViewportLayout(viewport);
354                 }
355             });
356             JQueryWrapper.select(viewport).animate(animated ? 300 : 0, settings);
357         }
358     }
359 
360     @Override
361     public void setPusher(final VICEPush pusher) {
362         if (getWidgetIndex(pusher) != -1) {
363             insert(pusher, 0);
364         }
365     }
366 
367     @Override
368     public void setShellAppIndication(ShellAppType type, int indication) {
369         mainAppLauncher.setIndication(type, indication);
370     }
371 
372     @Override
373     public void closeMessageEager(final String id) {
374         presenter.removeMessage(id);
375     }
376 
377     @Override
378     public void navigateToMessageDetails(String id) {
379         presenter.loadShellApp(ShellAppType.PULSE, "messages/" + id);
380     }
381 
382     private void doUpdateViewport(VShellViewport viewport, ViewportType shellAppViewport) {
383         final VShellViewport oldViewport = viewports.get(shellAppViewport);
384         if (oldViewport != viewport) {
385             replaceWidget(oldViewport, viewport);
386             viewport.setEventBus(eventBus);
387             viewports.put(shellAppViewport, viewport);
388         }
389     }
390 
391     @Override
392     public void showAppPreloader(String prefix, PreloaderCallback preloaderCallback) {
393         setActiveViewport(ViewportType.APP_VIEWPORT);
394         getAppViewport().showAppPreloader(prefix, preloaderCallback);
395     }
396 }