| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.sample.mobilewebapp.client.desktop; |
| |
| import com.google.gwt.core.client.GWT; |
| import com.google.gwt.dom.client.Style.Unit; |
| import com.google.gwt.dom.client.VideoElement; |
| import com.google.gwt.event.dom.client.ClickEvent; |
| import com.google.gwt.event.dom.client.ClickHandler; |
| import com.google.gwt.media.client.Video; |
| import com.google.gwt.place.shared.Place; |
| import com.google.gwt.place.shared.PlaceChangeEvent; |
| import com.google.gwt.place.shared.PlaceController; |
| import com.google.gwt.sample.mobilewebapp.client.MobileWebAppShell; |
| import com.google.gwt.sample.mobilewebapp.presenter.task.TaskEditView; |
| import com.google.gwt.sample.mobilewebapp.presenter.task.TaskPlace; |
| import com.google.gwt.sample.mobilewebapp.presenter.task.TaskReadView; |
| import com.google.gwt.sample.mobilewebapp.presenter.taskchart.TaskChartPresenter; |
| import com.google.gwt.sample.mobilewebapp.presenter.tasklist.TaskListPlace; |
| import com.google.gwt.sample.mobilewebapp.presenter.tasklist.TaskListView; |
| import com.google.gwt.uibinder.client.UiBinder; |
| import com.google.gwt.uibinder.client.UiField; |
| import com.google.gwt.user.cellview.client.CellList; |
| import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy; |
| import com.google.gwt.user.client.Window; |
| import com.google.gwt.user.client.ui.Anchor; |
| import com.google.gwt.user.client.ui.Button; |
| import com.google.gwt.user.client.ui.DeckLayoutPanel; |
| import com.google.gwt.user.client.ui.DialogBox; |
| import com.google.gwt.user.client.ui.DockLayoutPanel; |
| import com.google.gwt.user.client.ui.FlowPanel; |
| import com.google.gwt.user.client.ui.HasOneWidget; |
| import com.google.gwt.user.client.ui.IsWidget; |
| import com.google.gwt.user.client.ui.Label; |
| import com.google.gwt.user.client.ui.PopupPanel; |
| import com.google.gwt.user.client.ui.ResizeComposite; |
| import com.google.gwt.user.client.ui.VerticalPanel; |
| import com.google.gwt.user.client.ui.Widget; |
| import com.google.gwt.view.client.SelectionChangeEvent; |
| import com.google.gwt.view.client.SingleSelectionModel; |
| import com.google.web.bindery.event.shared.EventBus; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * Desktop version of the UI shell. |
| */ |
| public class MobileWebAppShellDesktop extends ResizeComposite implements MobileWebAppShell { |
| |
| /** |
| * CSS override used for the main menu. |
| */ |
| interface MainMenuStyle extends CellList.Style { |
| } |
| |
| interface MobileWebAppShellDesktopUiBinder extends UiBinder<Widget, MobileWebAppShellDesktop> { |
| } |
| |
| /** |
| * A ClientBundle that provides images for this widget. |
| */ |
| interface Resources extends CellList.Resources { |
| /** |
| * The styles used in the main menu. We extend |
| * {@link CellList.Style#DEFAULT_CSS} with the styles defined in |
| * MainMenuCellList.css. |
| */ |
| @Source({"MainMenuCellList.css", CellList.Style.DEFAULT_CSS}) |
| MainMenuStyle cellListStyle(); |
| } |
| |
| /** |
| * The URL attribute that determines whether or not to include the pie chart. |
| */ |
| private static final String CHART_URL_ATTRIBUTE = "chart"; |
| |
| /** |
| * The external URL of the video tutorial for browsers that do not support |
| * video. |
| */ |
| private static final String EXTERNAL_TUTORIAL_URL = "http://www.youtube.com/watch?v=oHg5SJYRHA0"; |
| |
| private static MobileWebAppShellDesktopUiBinder uiBinder = GWT |
| .create(MobileWebAppShellDesktopUiBinder.class); |
| |
| @UiField |
| Anchor helpLink; |
| |
| /** |
| * The main menu list. |
| */ |
| @UiField(provided = true) |
| CellList<MainMenuItem> mainMenu; |
| |
| /** |
| * The container that holds content. |
| */ |
| @UiField |
| DeckLayoutPanel contentContainer; |
| |
| @UiField |
| DockLayoutPanel leftNav; |
| |
| /** |
| * The container that holds the pie chart. |
| */ |
| @UiField |
| HasOneWidget pieChartContainer; |
| |
| /** |
| * A boolean indicating that we have not yet seen the first content widget. |
| */ |
| private boolean firstContentWidget = true; |
| |
| /** |
| * The {@link DialogBox} used to display the tutorial. |
| */ |
| private PopupPanel tutoralPopup; |
| |
| /** |
| * The video tutorial. |
| */ |
| private Video tutorialVideo; |
| |
| /** |
| * Construct a new {@link MobileWebAppShellDesktop}. |
| */ |
| public MobileWebAppShellDesktop(EventBus bus, TaskChartPresenter pieChart, |
| final PlaceController placeController, TaskListView taskListView, TaskEditView taskEditView, |
| TaskReadView taskReadView) { |
| |
| // Initialize the main menu. |
| Resources resources = GWT.create(Resources.class); |
| mainMenu = new CellList<MainMenuItem>(new MainMenuItem.Cell(), resources); |
| mainMenu.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.DISABLED); |
| |
| // We don't expect to have more than 30 menu items. |
| mainMenu.setVisibleRange(0, 30); |
| |
| // Add items to the main menu. |
| final List<MainMenuItem> menuItems = new ArrayList<MainMenuItem>(); |
| menuItems.add(new MainMenuItem("Task List", new TaskListPlace(false)) { |
| @Override |
| public boolean mapsToPlace(Place p) { |
| // Map to all TaskListPlace instances. |
| return p instanceof TaskListPlace; |
| } |
| }); |
| menuItems.add(new MainMenuItem("Add Task", TaskPlace.getTaskCreatePlace())); |
| mainMenu.setRowData(menuItems); |
| |
| // Choose a place when a menu item is selected. |
| final SingleSelectionModel<MainMenuItem> selectionModel = |
| new SingleSelectionModel<MainMenuItem>(); |
| selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() { |
| public void onSelectionChange(SelectionChangeEvent event) { |
| MainMenuItem selected = selectionModel.getSelectedObject(); |
| if (selected != null && !selected.mapsToPlace(placeController.getWhere())) { |
| placeController.goTo(selected.getPlace()); |
| } |
| } |
| }); |
| mainMenu.setSelectionModel(selectionModel); |
| |
| // Update selection based on the current place. |
| bus.addHandler(PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() { |
| public void onPlaceChange(PlaceChangeEvent event) { |
| Place place = event.getNewPlace(); |
| for (MainMenuItem menuItem : menuItems) { |
| if (menuItem.mapsToPlace(place)) { |
| // We found a match in the main menu. |
| selectionModel.setSelected(menuItem, true); |
| return; |
| } |
| } |
| |
| // We didn't find a match in the main menu. |
| selectionModel.setSelected(null, true); |
| } |
| }); |
| |
| // Initialize this widget. |
| initWidget(uiBinder.createAndBindUi(this)); |
| |
| // Initialize the pie chart. |
| String chartUrlValue = Window.Location.getParameter(CHART_URL_ATTRIBUTE); |
| if (chartUrlValue != null && chartUrlValue.startsWith("f")) { |
| // Chart manually disabled. |
| leftNav.remove(1); // Pie Chart. |
| leftNav.remove(0); // Pie chart legend. |
| } else if (pieChart == null) { |
| // Chart not supported. |
| pieChartContainer.setWidget(new Label("Try upgrading to a modern browser to enable charts.")); |
| } else { |
| // Chart supported. |
| Widget pieWidget = pieChart.asWidget(); |
| pieWidget.setWidth("90%"); |
| pieWidget.setHeight("90%"); |
| pieWidget.getElement().getStyle().setMarginLeft(5.0, Unit.PCT); |
| pieWidget.getElement().getStyle().setMarginTop(5.0, Unit.PCT); |
| |
| pieChartContainer.setWidget(pieChart); |
| } |
| |
| /* |
| * Add all views to the DeckLayoutPanel so we can animate between them. |
| * Using a DeckLayoutPanel here works because we only have a few views, and |
| * we always know that the task views should animate in from the right side |
| * of the screen. A more complex app will require more complex logic to |
| * figure out which direction to animate. |
| */ |
| contentContainer.add(taskListView); |
| contentContainer.add(taskReadView); |
| contentContainer.add(taskEditView); |
| contentContainer.setAnimationDuration(800); |
| |
| // Show a tutorial when the help link is clicked. |
| helpLink.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| showTutorial(); |
| } |
| }); |
| } |
| |
| @Override |
| public void setAddButtonVisible(boolean isVisible) { |
| // No-op: Adding a task is handled in the main menu. |
| } |
| |
| /** |
| * Set the widget to display in content area. |
| * |
| * @param content the {@link Widget} to display |
| */ |
| public void setWidget(IsWidget content) { |
| contentContainer.setWidget(content); |
| |
| // Do not animate the first time we show a widget. |
| if (firstContentWidget) { |
| firstContentWidget = false; |
| contentContainer.animate(0); |
| } |
| } |
| |
| /** |
| * Show a tutorial video. |
| */ |
| private void showTutorial() { |
| // Reuse the tutorial dialog if it is already created. |
| if (tutoralPopup != null) { |
| // Reset the video. |
| // TODO(jlabanca): Is cache-control=private making the video non-seekable? |
| if (tutorialVideo != null) { |
| tutorialVideo.setSrc(tutorialVideo.getCurrentSrc()); |
| } |
| |
| tutoralPopup.center(); |
| return; |
| } |
| |
| /* |
| * Forward the use to YouTube if video is not supported or if none of the |
| * source formats are supported. |
| */ |
| tutorialVideo = Video.createIfSupported(); |
| if (tutorialVideo == null) { |
| Label label = new Label("Click the link below to view the tutoral:"); |
| Anchor anchor = new Anchor(EXTERNAL_TUTORIAL_URL, EXTERNAL_TUTORIAL_URL); |
| anchor.setTarget("_blank"); |
| FlowPanel panel = new FlowPanel(); |
| panel.add(label); |
| panel.add(anchor); |
| |
| tutoralPopup = new PopupPanel(true, false); |
| tutoralPopup.setWidget(panel); |
| tutoralPopup.setGlassEnabled(true); |
| |
| // Hide the popup when the user clicks the link. |
| anchor.addClickHandler(new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| tutoralPopup.hide(); |
| } |
| }); |
| |
| tutoralPopup.center(); |
| return; |
| } |
| |
| // Add the video sources. |
| tutorialVideo.addSource("video/tutorial.ogv", VideoElement.TYPE_OGG); |
| tutorialVideo.addSource("video/tutorial.mp4", VideoElement.TYPE_MP4); |
| |
| // Setup the video player. |
| tutorialVideo.setControls(true); |
| tutorialVideo.setAutoplay(true); |
| |
| // Put the video in a dialog. |
| final DialogBox popup = new DialogBox(false, false); |
| popup.setText("Tutorial"); |
| VerticalPanel vPanel = new VerticalPanel(); |
| vPanel.add(tutorialVideo); |
| vPanel.add(new Button("Close", new ClickHandler() { |
| public void onClick(ClickEvent event) { |
| tutorialVideo.pause(); |
| popup.hide(); |
| } |
| })); |
| popup.setWidget(vPanel); |
| tutoralPopup = popup; |
| popup.center(); |
| } |
| } |