// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client;
import com.google.appinventor.client.boxes.MotdBox;
import com.google.appinventor.client.explorer.commands.ChainableCommand;
import com.google.appinventor.client.explorer.commands.SaveAllEditorsCommand;
import com.google.appinventor.client.tracking.Tracking;
import com.google.appinventor.client.widgets.DropDownButton.DropDownItem;
import com.google.appinventor.client.widgets.DropDownButton;
import com.google.appinventor.client.widgets.TextButton;
import com.google.appinventor.shared.rpc.project.GalleryApp;
import com.google.appinventor.shared.rpc.project.GalleryAppListResult;
import com.google.appinventor.shared.rpc.project.ProjectRootNode;
import com.google.appinventor.shared.rpc.user.Config;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import static com.google.appinventor.client.Ode.MESSAGES;
/**
* The top panel, which contains the main menu, various links plus ads.
*
*/
public class TopPanel extends Composite {
// Strings for links and dropdown menus:
private final DropDownButton accountButton;
public DropDownButton languageDropDown;
private final String WIDGET_NAME_MESSAGES = "Messages";
private final String WIDGET_NAME_PRIVATE_USER_PROFILE = "Profile";
private final TextButton gallery;
private final TextButton moderation;
private final String WIDGET_NAME_SIGN_OUT = "Signout";
private final String WIDGET_NAME_USER = "User";
private static final String WIDGET_NAME_LANGUAGE = "Language";
private static final String SIGNOUT_URL = "/ode/_logout";
private static final String LOGO_IMAGE_URL = "/images/logo.png";
private static final String LANGUAGES_IMAGE_URL = "/images/languages.svg";
private static final String WINDOW_OPEN_FEATURES = "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes";
private static final String WINDOW_OPEN_LOCATION = "_ai2";
private final VerticalPanel rightPanel; // remember this so we can add MOTD later if needed
final Ode ode = Ode.getInstance();
/**
* Initializes and assembles all UI elements shown in the top panel.
*/
public TopPanel() {
/*
* The layout of the top panel is as follows:
*
* +-- topPanel ------------------------------------+
* |+-- logo --++-----tools-----++--links/account--+|
* || || || ||
* |+----------++---------------++-----------------+|
* +------------------------------------------------+
*/
HorizontalPanel topPanel = new HorizontalPanel();
topPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE);
// Create the Tools
TopToolbar tools = new TopToolbar();
ode.setTopToolbar(tools);
// Create the Links
HorizontalPanel links = new HorizontalPanel();
links.setStyleName("ode-TopPanelLinks");
links.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE);
if (Ode.getInstance().isReadOnly()) {
Label readOnly = new Label(MESSAGES.readOnlyMode());
readOnly.setStyleName("ode-TopPanelWarningLabel");
links.add(readOnly);
}
// My Projects Link
TextButton myProjects = new TextButton(MESSAGES.myProjectsTabName());
myProjects.setStyleName("ode-TopPanelButton");
myProjects.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
ode.switchToProjectsView();
}
});
myProjects.setStyleName("ode-TopPanelButton");
links.add(myProjects);
// Code on gallerydev branch
// Gallery Link
gallery = new TextButton(MESSAGES.tabNameGallery());
gallery.setStyleName("ode-TopPanelButton");
gallery.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
ode.switchToGalleryView();
}
});
links.add(gallery);
Config config = ode.getSystemConfig();
String guideUrl = config.getGuideUrl();
if (!Strings.isNullOrEmpty(guideUrl)) {
TextButton guideLink = new TextButton(MESSAGES.guideTabName());
guideLink.addClickHandler(new WindowOpenClickHandler(guideUrl));
guideLink.setStyleName("ode-TopPanelButton");
links.add(guideLink);
}
// Feedback Link
String feedbackUrl = config.getFeedbackUrl();
if (!Strings.isNullOrEmpty(feedbackUrl)) {
TextButton feedbackLink = new TextButton(MESSAGES.feedbackTabName());
feedbackLink.addClickHandler(
new WindowOpenClickHandler(feedbackUrl));
feedbackLink.setStyleName("ode-TopPanelButton");
links.add(feedbackLink);
}
/*
// Code on master branch
// Gallery Link
if (Ode.getInstance().getUser().getIsAdmin()) {
TextButton gallery = new TextButton(MESSAGES.galleryTabName());
gallery.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
Window.open("http://gallery.appinventor.mit.edu", "_blank", "scrollbars=1");
}
});
gallery.setStyleName("ode-TopPanelButton");
links.add(gallery);
}
*/
moderation = new TextButton(MESSAGES.tabNameModeration());
moderation.setStyleName("ode-TopPanelButton");
moderation.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent clickEvent) {
ode.switchToModerationPageView();
}
});
moderation.setVisible(false);
links.add(moderation);
// Create the Account Information
rightPanel = new VerticalPanel();
rightPanel.setHeight("100%");
rightPanel.setVerticalAlignment(VerticalPanel.ALIGN_MIDDLE);
HorizontalPanel account = new HorizontalPanel();
account.setStyleName("ode-TopPanelAccount");
// Account Drop Down Button
List<DropDownItem> userItems = Lists.newArrayList();
// Sign Out
userItems.add(new DropDownItem(WIDGET_NAME_SIGN_OUT, MESSAGES.signOutLink(), new SignOutAction()));
accountButton = new DropDownButton(WIDGET_NAME_USER, " " , userItems, true);
accountButton.setItemEnabled(WIDGET_NAME_MESSAGES, false);
accountButton.setStyleName("ode-TopPanelButton");
// Language
List<DropDownItem> languageItems = Lists.newArrayList();
String[] localeNames = LocaleInfo.getAvailableLocaleNames();
String nativeName;
for (String localeName : localeNames) {
if (!localeName.equals("default")) {
SelectLanguage lang = new SelectLanguage();
lang.setLocale(localeName);
nativeName = getDisplayName(localeName);
languageItems.add(new DropDownItem(WIDGET_NAME_LANGUAGE, nativeName, lang));
}
}
String currentLang = LocaleInfo.getCurrentLocale().getLocaleName();
String nativeDisplayName = getDisplayName(currentLang);
languageDropDown = new DropDownButton(WIDGET_NAME_LANGUAGE, nativeDisplayName, languageItems, true);
languageDropDown.setStyleName("ode-TopPanelButton");
account.setVerticalAlignment(VerticalPanel.ALIGN_MIDDLE);
account.add(links);
account.add(languageDropDown);
account.add(accountButton);
rightPanel.add(account);
// Add the Logo, Tools, Links to the TopPanel
addLogo(topPanel);
topPanel.add(tools);
topPanel.add(rightPanel);
topPanel.setCellVerticalAlignment(rightPanel, HorizontalPanel.ALIGN_MIDDLE);
rightPanel.setCellHorizontalAlignment(account, HorizontalPanel.ALIGN_RIGHT);
topPanel.setCellHorizontalAlignment(rightPanel, HorizontalPanel.ALIGN_RIGHT);
initWidget(topPanel);
setStyleName("ode-TopPanel");
setWidth("100%");
}
private String getDisplayName(String localeName){
String nativeName=LocaleInfo.getLocaleNativeDisplayName(localeName);
if (localeName == "zh_CN") {
nativeName = MESSAGES.SwitchToSimplifiedChinese();
} else if (localeName == "zh_TW") {
nativeName = MESSAGES.SwitchToTraditionalChinese();
} else if (localeName == "es_ES") {
nativeName = MESSAGES.SwitchToSpanish();
} else if (localeName == "fr_FR") {
nativeName = MESSAGES.SwitchToFrench();
} else if (localeName == "it_IT") {
nativeName = MESSAGES.SwitchToItalian();
} else if (localeName == "ru") {
nativeName = MESSAGES.SwitchToRussian();
} else if (localeName == "ko_KR") {
nativeName = MESSAGES.SwitchToKorean();
} else if (localeName == "sv") {
nativeName = MESSAGES.SwitchToSwedish();
} else if (localeName == "pt_BR") {
nativeName = MESSAGES.switchToPortugueseBR();
}
return nativeName;
}
public void updateAccountMessageButton(){
// Since we want to insert "Messages" before "Sign Out", we need to clear first.
accountButton.clearAllItems();
// Gallery Items
// (1)Private User Profile
accountButton.addItem(new DropDownItem(WIDGET_NAME_PRIVATE_USER_PROFILE, MESSAGES.privateProfileLink(), new PrivateProfileAction()));
// (2)Sign Out
accountButton.addItem(new DropDownItem(WIDGET_NAME_SIGN_OUT, MESSAGES.signOutLink(), new SignOutAction()));
}
private void addLogo(HorizontalPanel panel) {
// Logo should be a link to App Inv homepage. Currently, after the user
// has logged in, the top level *is* ODE; so for now don't make it a link.
// Add timestamp to logo url to get around browsers that agressively cache
// the image! This same trick is used in StorageUtil.getFilePath().
Image logo = new Image(LOGO_IMAGE_URL + "?t=" + System.currentTimeMillis());
logo.setSize("40px", "40px");
logo.setStyleName("ode-Logo");
String logoUrl = ode.getSystemConfig().getLogoUrl();
if (!Strings.isNullOrEmpty(logoUrl)) {
logo.addClickHandler(new WindowOpenClickHandler(logoUrl));
}
panel.add(logo);
panel.setCellWidth(logo, "50px");
Label title = new Label("MIT App Inventor 2");
Label version = new Label("Beta");
title.setStyleName("ode-LogoText");
version.setStyleName("ode-LogoVersion");
VerticalPanel titleContainer = new VerticalPanel();
titleContainer.add(title);
titleContainer.add(version);
titleContainer.setCellHorizontalAlignment(version, HorizontalPanel.ALIGN_RIGHT);
panel.add(titleContainer);
panel.setCellWidth(titleContainer, "180px");
panel.setCellHorizontalAlignment(logo, HorizontalPanel.ALIGN_LEFT);
panel.setCellVerticalAlignment(logo, HorizontalPanel.ALIGN_MIDDLE);
}
private void addMotd(VerticalPanel panel) {
MotdBox motdBox = MotdBox.getMotdBox();
panel.add(motdBox);
panel.setCellHorizontalAlignment(motdBox, HorizontalPanel.ALIGN_RIGHT);
panel.setCellVerticalAlignment(motdBox, HorizontalPanel.ALIGN_BOTTOM);
}
/**
* Updates the UI to show the user's email address.
*
* @param email the email address
*/
public void showUserEmail(String email) {
accountButton.setCaption(email);
}
/**
* Updates the UI to show the moderation's link.
*/
public void showModerationLink(boolean b) {
moderation.setVisible(b);
}
/**
* Updates the UI to show the moderation's link.
*/
public void showGalleryLink(boolean b) {
gallery.setVisible(b);
}
/**
* Adds the MOTD box to the right panel. This should only be called once.
*/
public void showMotd() {
addMotd(rightPanel);
}
private static class WindowOpenClickHandler implements ClickHandler {
private final String url;
WindowOpenClickHandler(String url) {
this.url = url;
}
@Override
public void onClick(ClickEvent clickEvent) {
Window.open(url, WINDOW_OPEN_LOCATION, WINDOW_OPEN_FEATURES);
}
}
private static class SignOutAction implements Command {
@Override
public void execute() {
// Maybe take a screenshot
Ode.getInstance().screenShotMaybe(new Runnable() {
@Override
public void run() {
Window.Location.replace(SIGNOUT_URL);
}
}, true); // Wait for i/o
}
}
private class SelectLanguage implements Command {
private String localeName;
@Override
public void execute() {
final String queryParam = LocaleInfo.getLocaleQueryParam();
Command savecmd = new SaveAction();
savecmd.execute();
if (queryParam != null) {
UrlBuilder builder = Window.Location.createUrlBuilder().setParameter(
queryParam, localeName);
Window.Location.replace(builder.buildString());
} else {
// If we are using only cookies, just reload
Window.Location.reload();
}
}
public void setLocale(String nativeName) {
localeName = nativeName;
}
}
private class SaveAction implements Command {
@Override
public void execute() {
ProjectRootNode projectRootNode = Ode.getInstance().getCurrentYoungAndroidProjectRootNode();
if (projectRootNode != null) {
ChainableCommand cmd = new SaveAllEditorsCommand(null);
cmd.startExecuteChain(Tracking.PROJECT_ACTION_SAVE_YA, projectRootNode);
}
}
}
private static class PrivateProfileAction implements Command {
@Override
public void execute() {
Ode.getInstance().switchToPrivateUserProfileView();
}
}
}