package org.geogebra.web.web.gui.menubar;
import org.geogebra.common.move.events.BaseEvent;
import org.geogebra.common.move.ggtapi.events.LogOutEvent;
import org.geogebra.common.move.ggtapi.events.LoginEvent;
import org.geogebra.common.move.views.BooleanRenderable;
import org.geogebra.common.move.views.EventRenderable;
import org.geogebra.common.plugin.EventType;
import org.geogebra.web.html5.gui.laf.MainMenuI;
import org.geogebra.web.html5.gui.util.NoDragImage;
import org.geogebra.web.html5.main.AppW;
import org.geogebra.web.web.css.GuiResources;
import org.geogebra.web.web.gui.GuiManagerW;
import org.geogebra.web.web.gui.browser.SignInButton;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItem;
import com.google.gwt.user.client.ui.StackPanel;
/**
* Sidebar menu for SMART
*
*
*/
public class MainMenu extends FlowPanel implements MainMenuI, EventRenderable, BooleanRenderable {
/**
* Appw app
*/
/*private MenuItem signIn;
private SignedInMenuW signedIn;
private MenuItem signedInMenu;*/
AppW app;
/**
* Panel with menus
*/
StackPanel menuPanel;
private ViewMenuW viewMenu;
private FileMenuW fileMenu;
private HelpMenuW helpMenu;
private OptionsMenuW optionsMenu;
private ToolsMenuW toolsMenu;
private EditMenuW editMenu;
private PerspectivesMenuW perspectivesMenu;
private boolean leftSide = false;
/**
* Menus
*/
GMenuBar[] menus;
private GMenuBar userMenu;
/** sign in menu */
GMenuBar signInMenu = new GMenuBar(true, "signin");
/**
* Constructs the menubar
*
* @param app
* application
*/
public MainMenu(AppW app) {
this.addStyleName("menubarSMART");
leftSide = app.isWhiteboardActive();
if (leftSide) {
addStyleName("mowMenubar");
}
this.app = app;
init();
}
private void init() {
this.app.getLoginOperation().getView().add(this);
final boolean exam = app.isExam();
if(app.enableFileFeatures()){
this.createFileMenu();
}
boolean enableGraph = !exam || app.enableGraphing();
if (enableGraph){
this.createPerspectivesMenu();
this.createEditMenu();
this.createViewMenu();
}
this.createOptionsMenu();
if (enableGraph) {
this.createToolsMenu();
}
if (!exam) {
this.createHelpMenu();
this.createUserMenu();
if(!app.enableFileFeatures()){
this.menus = new GMenuBar[]{editMenu,perspectivesMenu,viewMenu, optionsMenu, toolsMenu, helpMenu};
}else{
this.menus = new GMenuBar[]{fileMenu,editMenu,perspectivesMenu,viewMenu, optionsMenu, toolsMenu, helpMenu};
}
} else {
this.menus = new GMenuBar[] { fileMenu, optionsMenu };
}
for(int i=0; i<menus.length; i++){
final int next = (i+1)%menus.length;
final int previous = (i-1+menus.length)%menus.length;
final int index = i;
this.menus[i].addDomHandler(new KeyDownHandler(){
@Override
public void onKeyDown(KeyDownEvent event) {
int keyCode = event.getNativeKeyCode();
//First / last below are not intuitive -- note that default handler of
//down skipped already from last to first
if(keyCode == KeyCodes.KEY_DOWN){
if(menus[index].isFirstItemSelected()){
menuPanel.showStack(next);
menus[next].focus();
}
}
if(keyCode == KeyCodes.KEY_UP){
if(menus[index].isLastItemSelected()){
menuPanel.showStack(previous);
menus[previous].focus();
}
}
if(keyCode == KeyCodes.KEY_ESCAPE){
app.toggleMenu();
((GuiManagerW)app.getGuiManager()).getToolbarPanel().selectMenuButton(-1);
}
}}, KeyDownEvent.getType());
}
this.menuPanel = new StackPanel() {
@Override
public void showStack(int index) {
super.showStack(index);
dispatchOpenEvent();
app.getGuiManager().setDraggingViews(
isViewDraggingMenu(menus[index]), false);
}
@Override
public void onBrowserEvent(Event event) {
if (!exam && DOM.eventGetType(event) == Event.ONCLICK) {
Element target = DOM.eventGetTarget(event);
int index = findDividerIndex(target);
//check if SignIn was clicked
//if we are offline, the last item is actually Help
if (app.getNetworkOperation().isOnline() &&
!app.getLoginOperation().isLoggedIn()
&& index >= 0
&& this.getWidget(index) == signInMenu) {
((SignInButton)app.getLAF().getSignInButton(app)).login();
app.toggleMenu();
return;
}
if (index != -1) {
if (index == this.getSelectedIndex()) {
closeAll(this);
return;
}
showStack(index);
}
}
super.onBrowserEvent(event);
}
// violator pattern from
// https://code.google.com/archive/p/google-web-toolkit/issues/1188
private native void closeAll(StackPanel stackPanel) /*-{
stackPanel.@com.google.gwt.user.client.ui.StackPanel::setStackVisible(IZ)(stackPanel. @com.google.gwt.user.client.ui.StackPanel::visibleStack, false);
stackPanel.@com.google.gwt.user.client.ui.StackPanel::visibleStack = -1;
}-*/;
private int findDividerIndex(Element elemSource) {
Element elem = elemSource;
while (elem != null && elem != getElement()) {
String expando = elem.getPropertyString("__index");
if (expando != null) {
// Make sure it belongs to me!
int ownerHash = elem.getPropertyInt("__owner");
if (ownerHash == hashCode()) {
// Yes, it's mine.
return Integer.parseInt(expando);
}
// It must belong to some nested StackPanel.
return -1;
}
elem = DOM.getParent(elem);
}
return -1;
}
};
this.menuPanel.addStyleName("menuPanel");
if(app.enableFileFeatures()){
this.menuPanel.add(fileMenu, getHTML(GuiResources.INSTANCE.menu_icon_file(), "File"), true);
}
if (enableGraph) {
this.menuPanel.add(editMenu,
getHTML(GuiResources.INSTANCE.menu_icon_edit(), "Edit"),
true);
this.menuPanel
.add(perspectivesMenu,
getHTML(GuiResources.INSTANCE
.menu_icon_perspectives(), "math_apps"),
true);
this.menuPanel.add(viewMenu,
getHTML(GuiResources.INSTANCE.menu_icon_view(), "View"),
true);
}
this.menuPanel.add(optionsMenu, getHTML(GuiResources.INSTANCE.menu_icon_options(), "Options"), true);
if (!app.getLAF().isSmart() && enableGraph) {
this.menuPanel.add(toolsMenu, getHTML(GuiResources.INSTANCE.menu_icon_tools(), "Tools"), true);
}
if (!exam) {
this.menuPanel.add(helpMenu,
getHTML(GuiResources.INSTANCE.menu_icon_help(), "Help"),
true);
if(app.getNetworkOperation().isOnline()){
render(true);
}
app.getNetworkOperation().getView().add(this);
}
this.add(menuPanel);
}
/**
* @param menu
* menu
* @return whether dragging views should be enabled for this menu
*/
protected boolean isViewDraggingMenu(GMenuBar menu) {
return menu == perspectivesMenu || menu == viewMenu;
}
@Override
public void render(boolean online) {
if(!app.enableFileFeatures()){
return;
}
if (online && app.getLoginOperation().isLoggedIn()) {
loggedIn = true;
addUserMenu();
} else if(online){
addSignInMenu();
} else {
loggedIn = false;
if(this.signInMenu != null){
this.menuPanel.remove(this.signInMenu);
}
if(this.userMenu != null){
this.menuPanel.remove(this.userMenu);
}
}
}
private void createUserMenu() {
this.userMenu = new GMenuBar(true, "user");
this.userMenu.addStyleName("GeoGebraMenuBar");
this.userMenu.addItem(
getMenuBarHtml(
GuiResources.INSTANCE.menu_icon_sign_out().getSafeUri()
.asString(),
app.getLocalization().getMenu("SignOut"), true),
true, new MenuCommand(app) {
@Override
public void doExecute() {
app.getLoginOperation().performLogOut();
}
});
}
private String getHTML(ImageResource img, String s){
//return "<img src=\""+img.getSafeUri().asString()+"\" /><span style= \"font-size:80% \" >" + s + "</span>";
return "<img src=\"" + img.getSafeUri().asString()
+ "\" draggable=\"false\"><span>"
+ app.getLocalization().getMenu(s) + "</span>";
}
private void createFileMenu() {
fileMenu = new FileMenuW(app);
}
private void createPerspectivesMenu() {
perspectivesMenu = new PerspectivesMenuW(app);
}
private void createEditMenu() {
editMenu = new EditMenuW(app);
}
private void createViewMenu() {
viewMenu = new ViewMenuW(app);
}
private void createHelpMenu() {
helpMenu = new HelpMenuW(app);
}
private void createOptionsMenu() {
optionsMenu = new OptionsMenuW(app);
}
private void createToolsMenu() {
toolsMenu = new ToolsMenuW(app);
}
private EditMenuW getEditMenu() {
return editMenu;
}
/**
* Update all submenus that depend on file content
*/
public void updateMenubar() {
if(app.hasOptionsMenu()){
app.getOptionsMenu(null).update();
}
if(viewMenu != null){
viewMenu.update();
}
if (this.getEditMenu() != null) {
getEditMenu().update();
}
}
/**
* Update on selection change
*/
public void updateSelection() {
if(this.getEditMenu()!=null){
getEditMenu().invalidate();
}
}
public void focus(){
int index= Math.max(menuPanel.getSelectedIndex(),0);
if(this.menus[index]!=null){
this.menus[index].focus();
}
}
public static void addSubmenuArrow(MenuBar w) {
addSubmenuArrow(w, false);
}
public static void addSubmenuArrow(MenuBar w, boolean left) {
w.addStyleName(left ? "subMenuRightSide" : "subMenuLeftSide");
FlowPanel arrowSubmenu = new FlowPanel();
arrowSubmenu.addStyleName("arrowSubmenu");
NoDragImage arrow = left
? new NoDragImage(GuiResources.INSTANCE.arrow_submenu_left()
.getSafeUri().asString())
: new NoDragImage(GuiResources.INSTANCE.arrow_submenu_right()
.getSafeUri().asString());
arrowSubmenu.add(arrow);
w.getElement().appendChild(arrowSubmenu.getElement());
}
public static String getMenuBarHtml(String url, String str, boolean enabled) {
String text2 = str.replace("\"", "'");
String text3 = (enabled) ? text2 : "<span style=\"color:gray;\">"+text2+"</span>";
return "<img class=\"GeoGebraMenuImage menuImg\" alt=\"" + text2
+ "\" src=\""
+ url + "\" draggable=\"false\">" + text3;
}
public static String getMenuBarHtml(String url, String str) {
String text = str.replace("\"", "'");
return "<img class=\"menuImg\" width=\"16\" height=\"16\" alt=\"" + text
+ "\" src=\""
+ url + "\" draggable=\"false\">"
+ text;
}
public static void setMenuSelected(MenuItem m, boolean visible) {
if (visible) {
m.addStyleName("checked");
} else {
m.removeStyleName("checked");
}
}
/**
* sets the height of the menu
* @param height int
*/
public void updateHeight(int height) {
this.setHeight(height + "px");
}
private boolean loggedIn = false;
@Override
public void renderEvent(final BaseEvent event) {
if(!app.enableFileFeatures()){
return;
}
if (event instanceof LoginEvent && ((LoginEvent) event).isSuccessful()) {
if (loggedIn) {
this.menuPanel.remove(this.userMenu);
}
loggedIn = true;
this.menuPanel.remove(this.signInMenu);
addUserMenu();
this.userMenu.setVisible(false);
} else if (event instanceof LogOutEvent) {
this.menuPanel.remove(this.userMenu);
loggedIn = false;
addSignInMenu();
this.signInMenu.setVisible(false);
}
}
private void addSignInMenu() {
this.menuPanel.add(this.signInMenu,
getHTML(GuiResources.INSTANCE.menu_icon_sign_in(),
app.getLocalization().getMenu("SignIn")),
true);
}
private void addUserMenu() {
this.menuPanel.add(this.userMenu, getHTML(GuiResources.INSTANCE.menu_icon_signed_in_f(), app.getLoginOperation().getUserName()), true);
}
/**
* Inform client listener about opening the menu
*/
public void dispatchOpenEvent() {
if (menuPanel != null) {
int index = menuPanel.getSelectedIndex();
app.dispatchEvent(new org.geogebra.common.plugin.Event(
EventType.OPEN_MENU, null, menus[index].getMenuTitle()));
}
}
}