package com.gwt.ui.client;
import java.util.ArrayList;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.HasMouseOutHandlers;
import com.google.gwt.event.dom.client.HasMouseOverHandlers;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.gwt.ui.client.supertable.HTMLHelper;
public class PopupMenu extends PopupPanel {
private PopupMenu parent = null;
private VerticalPanel panel = new VerticalPanel();
private PopupMenu openChildMenu = null;
private ArrayList<Widget> widgets = new ArrayList<Widget>();
/**
* A constructor for this class.
*/
public PopupMenu() {
super(true);
setStyleName("gwtcomp-PopupMenu");
panel = new VerticalPanel();
panel.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
panel.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
setWidget(panel);
}
/**
* Adds a child menu item that is a cascaded menu.
*
* @param widget normally a HTML or Label object is used to print the menu item name.
* @param cascadedMenu the popup menu that is popped up when the user mouses over the widget.
*/
public void addMenuItem(Widget widget, final PopupMenu cascadedMenu) {
class ItemSelectionListener implements HasMouseOutHandlers, HasMouseOverHandlers {
private PopupMenu parent0;
private FocusPanel panel0;
private PopupMenu cascadedMenu0;
public ItemSelectionListener(final PopupMenu parent, final FocusPanel panel, final PopupMenu cascadedMenu) {
this.parent0 = parent;
this.panel0 = panel;
this.cascadedMenu0 = cascadedMenu;
panel0.addMouseOverHandler(new MouseOverHandler() {
@Override
public void onMouseOver(MouseOverEvent event) {
panel0.addStyleName("gwtcomp-PopupMenu-MenuItem-MouseIn");
// hide the previous cascaded menu
if (parent0.openChildMenu != null) {
parent0.openChildMenu.hide();
parent0.openChildMenu = null;
}
// open the cascaded menu if one is available
if (cascadedMenu0 != null) {
int top = event.getRelativeY(event.getRelativeElement());
int left = event.getRelativeX(event.getRelativeElement());
cascadedMenu0.setPopupPosition(left, top);
cascadedMenu0.show();
parent0.openChildMenu = cascadedMenu0;
}
}
});
panel0.addMouseOutHandler(new MouseOutHandler() {
@Override
public void onMouseOut(MouseOutEvent event) {
panel0.removeStyleName("gwtcomp-PopupMenu-MenuItem-MouseIn");
}
});
}
@Override
public void fireEvent(GwtEvent<?> arg0) {
// TODO Auto-generated method stub
}
@Override
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
return addDomHandler(handler, MouseOutEvent.getType());
}
@Override
public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
return addDomHandler(handler, MouseOverEvent.getType());
}
}
HorizontalPanel w = new HorizontalPanel();
w.addStyleName("gwtcomp-PopupMenu-MenuItem");
w.setWidth("100%");
w.add(widget);
w.setCellHorizontalAlignment(widget, HasHorizontalAlignment.ALIGN_LEFT);
w.setCellVerticalAlignment(widget, HasVerticalAlignment.ALIGN_TOP);
// add spacing
w.add(new HTML(" "));
if (cascadedMenu != null) {
Image im = new Image(GWT.getModuleBaseURL() + "gwtcomp-icons/right-arrow.png");
w.add(im);
w.setCellHorizontalAlignment(im, HasHorizontalAlignment.ALIGN_RIGHT);
w.setCellVerticalAlignment(im, HasVerticalAlignment.ALIGN_MIDDLE);
cascadedMenu.parent = this;
}
FocusPanel fp = new FocusPanel(w);
panel.add(fp);
widgets.add(fp);
fp.setWidth("100%");
fp.addStyleName("gwtcomp-PopupMenu-MenuItem");
fp.setHeight("22px");
new ItemSelectionListener(this, fp, cascadedMenu);
}
/**
* Add a child menu item.
*
* @param widget normally a HTML segment or a text lable is passed but other input widgets can be passed as well.
*/
public void addMenuItem(Widget widget) {
addMenuItem(widget, null);
}
/**
* Removes a child menu at the given index.
*
* @param index index
*/
public void removeMenuItem(int index) {
widgets.remove(index);
panel.remove(index);
}
public void removeMenuItem(Widget widget) {
panel.remove(widget);
widgets.remove(widget);
}
/**
* Add a separator item.
*/
public void addSeparator() {
HTML html = new HTML(HTMLHelper.hr("#AAAAAA"));
html.setHeight("22px");
panel.add(html);
widgets.add(html);
}
public void clearMenuItems() {
for (Widget widget : widgets) {
panel.remove(widget);
}
widgets.clear();
}
/**
* Hides the popup menu. In case the menu is a cascaded menu and has parents, the parents are hidden as well.
*/
public void hideAll() {
this.hide();
PopupMenu parent = this.parent;
while (parent != null) {
parent.hide();
parent = parent.parent;
}
// Don't leave any menu items selected
int numItems = panel.getWidgetCount();
for (int i = 0; i < numItems; i++) {
panel.getWidget(i).removeStyleName("gwtcomp-PopupMenu-MenuItem-MouseIn");
}
}
/**
* Gets the root menu for a given popup menu. Cascaded menus have parents and possibly grand-parents. This method iterates through the
* chain and returns the root popup menu.
*
* @param menu a given popup menu object
* @return the root popup menu
*/
public static PopupMenu getRootMenu(PopupMenu menu) {
PopupMenu element = menu;
PopupMenu parent = element.parent;
while (parent != null) {
element = parent;
parent = element.parent;
}
return element;
}
}