Java tutorial
/** * Copyright 2006 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 liber.browse.client; import java.util.Vector; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.DeferredCommand; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.PopupListener; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; /** * A standard menu bar widget. A menu bar can contain any number of menu items, * each of which can either fire a {@see com.google.gwt.user.client.Command} or * open a cascaded menu bar. * * <p> * <img class='gallery' src='WysiwymMenuBar.png'/> * </p> * * <h3>CSS Style Rules</h3> * <ul class='css'> * <li>.gwt-WysiwymMenuBar { the menu bar itself }</li> * <li>.gwt-WysiwymMenuBar .gwt-WysiwymMenuItem { menu items }</li> * <li>.gwt-WysiwymMenuBar .gwt-WysiwymMenuItem-selected { selected menu items }</li> * </ul> * * <p> * <h3>Example</h3> * {@example com.google.gwt.examples.WysiwymMenuBarExample} * </p> * * Tried to adapt this so when shown, the first menu item would be selected and the user * could use the cursor keys to select items. Never could get that to work though. */ public class WysiwymMenuBar extends Widget implements PopupListener { private Element body; private Vector items = new Vector(); private WysiwymMenuBar parentMenu; private PopupPanel popup; private WysiwymMenuItem selectedItem; private WysiwymMenuBar shownChildMenu; private boolean vertical, autoOpen; /** * Creates an empty horizontal menu bar. */ public WysiwymMenuBar() { this(false); } /** * Creates an empty menu bar. * * @param vertical <code>true</code> to orient the menu bar vertically */ public WysiwymMenuBar(boolean vertical) { super(); Element table = DOM.createTable(); body = DOM.createTBody(); DOM.appendChild(table, body); if (!vertical) { Element tr = DOM.createTR(); DOM.appendChild(body, tr); } this.vertical = vertical; Element outer = DOM.createDiv(); DOM.appendChild(outer, table); setElement(outer); sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT); setStyleName("gwt-MenuBar"); } /** * Adds a menu item to the bar. * * @param item the item to be added */ public void addItem(WysiwymMenuItem item) { Element tr; if (vertical) { tr = DOM.createTR(); DOM.appendChild(body, tr); } else { tr = DOM.getChild(body, 0); } DOM.appendChild(tr, item.getElement()); item.setParentMenu(this); item.setSelectionStyle(false); items.add(item); } /** * Adds a menu item to the bar, that will fire the given command when it is * selected. * * @param text the item's text * @param asHTML <code>true</code> to treat the specified text as html * @param cmd the command to be fired * @return the {@see WysiwymMenuItem} object created */ public WysiwymMenuItem addItem(String text, boolean asHTML, Command cmd) { WysiwymMenuItem item = new WysiwymMenuItem(text, asHTML, cmd); addItem(item); return item; } /** * Adds a menu item to the bar, that will open the specified menu when it is * selected. * * @param text the item's text * @param asHTML <code>true</code> to treat the specified text as html * @param popup the menu to be cascaded from it * @return the {@see WysiwymMenuItem} object created */ public WysiwymMenuItem addItem(String text, boolean asHTML, WysiwymMenuBar popup) { WysiwymMenuItem item = new WysiwymMenuItem(text, asHTML, popup); addItem(item); return item; } /** * Adds a menu item to the bar, that will fire the given command when it is * selected. * * @param text the item's text * @param cmd the command to be fired * @return the {@see WysiwymMenuItem} object created */ public WysiwymMenuItem addItem(String text, Command cmd) { WysiwymMenuItem item = new WysiwymMenuItem(text, cmd); addItem(item); return item; } /** * Adds a menu item to the bar, that will open the specified menu when it is * selected. * * @param text the item's text * @param popup the menu to be cascaded from it * @return the {@see WysiwymMenuItem} object created */ public WysiwymMenuItem addItem(String text, WysiwymMenuBar popup) { WysiwymMenuItem item = new WysiwymMenuItem(text, popup); addItem(item); return item; } /** * Removes all menu items from this menu bar. */ public void clearItems() { Element container = getItemContainerElement(); while (DOM.getChildCount(container) > 0) { DOM.removeChild(container, DOM.getChild(container, 0)); } items.clear(); } /** * Gets whether this menu bar's child menus will open when the mouse is moved * over it. * * @return <code>true</code> if child menus will auto-open */ public boolean getAutoOpen() { return autoOpen; } public void onBrowserEvent(Event event) { super.onBrowserEvent(event); WysiwymMenuItem item = findItem(DOM.eventGetTarget(event)); switch (DOM.eventGetType(event)) { case Event.ONCLICK: { // Fire an item's command when the user clicks on it. if (item != null) { doItemAction(item, true); } break; } case Event.ONMOUSEOVER: { if (item != null) { itemOver(item); } break; } case Event.ONMOUSEOUT: { if (item != null) { itemOver(null); } break; } } } public void onPopupClosed(PopupPanel sender, boolean autoClosed) { // If the menu popup was auto-closed, close all of its parents as well. if (autoClosed) { closeAllParents(); } // When the menu popup closes, remember that no item is // currently showing a popup menu. onHide(); shownChildMenu = null; popup = null; } /** * Removes the specified menu item from the bar. * * @param item the item to be removed */ public void removeItem(WysiwymMenuItem item) { int idx = items.indexOf(item); if (idx == -1) { return; } Element container = getItemContainerElement(); DOM.removeChild(container, DOM.getChild(container, idx)); items.remove(idx); } /** * Sets whether this menu bar's child menus will open when the mouse is moved * over it. * * @param autoOpen <code>true</code> to cause child menus to auto-open */ public void setAutoOpen(boolean autoOpen) { this.autoOpen = autoOpen; } protected void onDetach() { // When the menu is detached, make sure to close all of its children. if (popup != null) { popup.hide(); } super.onDetach(); } /** * Closes all parent menu popups. */ void closeAllParents() { WysiwymMenuBar curMenu = this; while (curMenu != null) { curMenu.close(); if ((curMenu.parentMenu == null) && (curMenu.selectedItem != null)) { curMenu.selectedItem.setSelectionStyle(false); curMenu.selectedItem = null; } curMenu = curMenu.parentMenu; } } /** * Performs the action associated with the given menu item. If the item has a * popup associated with it, the popup will be shown. If it has a command * associated with it, and 'fireCommand' is true, then the command will be * fired. Popups associated with other items will be hidden. * * @param item the item whose popup is to be shown. @param fireCommand <code>true</code> * if the item's command should be fired, <code>false</code> otherwise. */ void doItemAction(final WysiwymMenuItem item, boolean fireCommand) { // If the given item is already showing its menu, we're done. if ((shownChildMenu != null) && (item.getSubMenu() == shownChildMenu)) { return; } // If another item is showing its menu, then hide it. if (shownChildMenu != null) { shownChildMenu.onHide(); popup.hide(); } // If the item has no popup, optionally fire its command. if (item.getSubMenu() == null) { if (fireCommand) { // Close this menu and all of its parents. closeAllParents(); // Fire the item's command. Command cmd = item.getCommand(); if (cmd != null) { DeferredCommand.add(cmd); } } return; } // Ensure that the item is selected. selectItem(item); // Create a new popup for this item, and position it next to // the item (below if this is a horizontal menu bar, to the // right if it's a vertical bar). popup = new PopupPanel(true) { { setWidget(item.getSubMenu()); item.getSubMenu().onShow(); } public boolean onEventPreview(Event event) { // Hook the popup panel's event preview. We use this to keep it from // auto-hiding when the parent menu is clicked. switch (DOM.eventGetType(event)) { case Event.ONCLICK: // If the event target is part of the parent menu, suppress the // event altogether. Element target = DOM.eventGetTarget(event); Element parentMenuElement = item.getParentMenu().getElement(); if (DOM.isOrHasChild(parentMenuElement, target)) { return false; } break; } return super.onEventPreview(event); } }; popup.addPopupListener(this); /** ADDED TO ENSURE THAT POPUP-MENUS DO NOT RUN OFF SCREEN */ if ((item.getAbsoluteLeft() + item.getOffsetWidth() + 150) > Window.getClientWidth()) //don't let the menu run off the page popup.setPopupPosition(item.getAbsoluteLeft() - 120, item.getAbsoluteTop()); else popup.setPopupPosition(item.getAbsoluteLeft() + item.getOffsetWidth(), item.getAbsoluteTop()); shownChildMenu = item.getSubMenu(); item.getSubMenu().parentMenu = this; // Show the popup, ensuring that the WysiwymMenuBar's event preview remains on top // of the popup's. popup.show(); } void itemOver(WysiwymMenuItem item) { if (item == null) { // Don't clear selection if the currently selected item's menu is showing. if ((selectedItem != null) && (shownChildMenu == selectedItem.getSubMenu())) { return; } } // Style the item selected when the mouse enters. selectItem(item); // If child menus are being shown, or this menu is itself // a child menu, automatically show an item's child menu // when the mouse enters. if (item != null) { if ((shownChildMenu != null) || (parentMenu != null) || autoOpen) { doItemAction(item, false); } } } /** * Closes this menu (if it is a popup). */ private void close() { if (parentMenu != null) { parentMenu.popup.hide(); } } private WysiwymMenuItem findItem(Element hItem) { for (int i = 0; i < items.size(); ++i) { WysiwymMenuItem item = (WysiwymMenuItem) items.get(i); if (DOM.isOrHasChild(item.getElement(), hItem)) { return item; } } return null; } private Element getItemContainerElement() { if (vertical) { return body; } else { return DOM.getChild(body, 0); } } /** * This method is called when a menu bar is hidden, so that it can hide any * child popups that are currently being shown. */ private void onHide() { if (shownChildMenu != null) { shownChildMenu.onHide(); popup.hide(); } } /** * This method is called when a menu bar is shown. It should select * the first item, so user can scroll through with the cursor keys. * Never could get it to work though. */ private void onShow() { // Select the first item when a menu is shown. if (items.size() > 0) { selectItem((WysiwymMenuItem) items.get(0)); } } private void selectItem(WysiwymMenuItem item) { if (item == selectedItem) { return; } if (selectedItem != null) { selectedItem.setSelectionStyle(false); } if (item != null) { item.setSelectionStyle(true); } selectedItem = item; } }