/* class JMenu
*
* Copyright (C) 2001-2003 R M Pitman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package charvax.swing;
import java.lang.ref.WeakReference;
import java.util.Enumeration;
import java.util.Vector;
import charva.awt.Color;
import charva.awt.Component;
import charva.awt.Dimension;
import charva.awt.Point;
import charva.awt.Toolkit;
import charva.awt.event.ActionEvent;
import charva.awt.event.KeyEvent;
/**
* Implements a menu containing JMenuItems and JSeparators.
*/
public class JMenu
extends JMenuItem
{
/** Constructs a new JMenu with no text
* (the text can be set later with the setText() method of the
* superclass).
*/
public JMenu()
{
super();
}
/** Constructs a new JMenu with the specified string as its text
*/
public JMenu(String text_)
{
this(text_, -1);
}
/** Constructs a new JMenu with the specified text and the
* specified mnemonic character (which must appear in the
* text).
*/
public JMenu(String text_, int mnemonic_)
{
super(text_, mnemonic_);
}
/**
* Add a JMenuItem (or JMenu) to the end of this JMenu.
* @return the JMenuItem that was added.
*/
public JMenuItem add(JMenuItem item_)
{
_menuItems.add(item_);
if (item_ instanceof JMenu) {
((JMenu) item_).setParentMenu(this);
}
return item_;
}
/** Add a horizontal separator to the end of the menu.
*/
public void addSeparator()
{
_menuItems.add(new JSeparator());
}
/**
* Create a JMenuItem with the specified label and add it to the
* menu.
* @return a reference to the newly created JMenuItem.
*/
public JMenuItem add(String text_)
{
JMenuItem item = new JMenuItem(text_);
add(item);
return item;
}
/**
* Sets the foreground color of this JMenu and all its
* contained JMenuItems that do not yet have their foreground
* color set. Overrides the same method in the Component class.
*/
public void setForeground(Color color_)
{
super.setForeground(color_);
Enumeration<Component> e = _menuItems.elements();
while (e.hasMoreElements()) {
Component c = e.nextElement();
if (c.getForeground() == null)
c.setForeground(color_);
}
}
/**
* Sets the background color of this JMenu and all its
* contained JMenuItems that do not yet have their background
* color set. Overrides the same method in the Component class.
*/
public void setBackground(Color color_)
{
super.setBackground(color_);
Enumeration<Component> e = _menuItems.elements();
while (e.hasMoreElements()) {
Component c = e.nextElement();
if (c.getBackground() == null)
c.setBackground(color_);
}
}
public void draw(Toolkit toolkit) {
/* Get the absolute origin of this component.
*/
Point origin = getLocationOnScreen();
int colorpair = getCursesColor();
toolkit.setCursor(origin);
int attribute = 0;
if ( ! (getParent() instanceof JMenuBar)) {
// This menu is in a JPopupMenu.
super.draw(toolkit);
}
else {
attribute = (super.hasFocus()) ? Toolkit.A_BOLD : Toolkit.A_REVERSE;
toolkit.addString(" ", attribute, colorpair);
toolkit.addString(super.getText(), attribute, colorpair);
toolkit.addString(" ", attribute, colorpair);
if (super.getMnemonic() > 0) {
int mnemonicPos = super.getText().indexOf((char) super.getMnemonic());
if (mnemonicPos != -1) {
toolkit.setCursor(origin.addOffset(mnemonicPos + 1, 0));
toolkit.addChar(super.getMnemonic(), attribute | Toolkit.A_UNDERLINE, colorpair);
}
}
}
}
/** Returns the menu item at the specified index.
* If the object at the specified index is a JSeparator, it returns null.
*/
public JMenuItem getMenuItem(int index_)
{
Object o = _menuItems.elementAt(index_);
if (o instanceof JMenuItem)
return (JMenuItem) o;
else
return null;
}
public void fireActionPerformed(ActionEvent ae_) {
// Notify all the registered ActionListeners.
super.fireActionPerformed(ae_);
setPopupMenuVisible(true);
// We get here when the popup menu has hidden itself.
if (_popup.leftWasPressed()) {
Toolkit.getDefaultToolkit().fireKeystroke(KeyEvent.VK_LEFT);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Toolkit.getDefaultToolkit().fireKeystroke(KeyEvent.VK_ENTER);
}
});
}
else if (_popup.rightWasPressed()) {
Toolkit.getDefaultToolkit().fireKeystroke(KeyEvent.VK_RIGHT);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Toolkit.getDefaultToolkit().fireKeystroke(KeyEvent.VK_ENTER);
}
});
}
else if ( ! isTopLevelMenu()) {
getAncestorWindow().hide();
}
}
public Dimension minimumSize()
{
return new Dimension(this.getWidth(), getHeight());
}
public Dimension getSize()
{
return minimumSize();
}
public int getWidth() {
return getText().length() + 2;
}
public int getHeight() {
return 1;
}
/** Returns true if the popup window of this menu is displayed.
*/
public boolean isPopupMenuVisible()
{
return _popupMenuVisible;
}
/** Displays this menu's popup menu if the specified value is true;
* hides the menu if it is false.
*/
public void setPopupMenuVisible(boolean visible_)
{
_popupMenuVisible = visible_;
if ( ! visible_) {
_popup.hide();
return;
}
if (_popup == null)
_popup = new JPopupMenu(_menuItems);
Point p;
if ( ! this.isTopLevelMenu()) {
/* If this menu is a submenu (i.e. it is not a direct
* child of the menubar), check if there is enough
* space on the right hand side of the parent menu.
* If there is not enough space, position it on the
* left of the parent menu.
*/
JMenu parentmenu = (JMenu) getParentMenu();
JPopupMenu parentpopup = parentmenu.getPopupMenu();
p = parentpopup.getLocation();
int verticalOffset = parentpopup.getComponentIndex(this);
_popup.setInvoker(parentpopup);
int parentwidth = parentpopup.getSize().width;
Toolkit term = Toolkit.getDefaultToolkit();
if (p.x + parentwidth + _popup.getWidth() <
term.getScreenColumns()) {
_popup.setLocation(
p.addOffset(parentwidth - 1, verticalOffset));
}
else {
_popup.setLocation(
p.addOffset(-_popup.getWidth() + 1, verticalOffset));
}
}
else {
JMenuBar parentMenuBar = (JMenuBar) getParent();
p = parentMenuBar.getPopupMenuLocation(this);
_popup.setInvoker(parentMenuBar);
_popup.setLocation(p);
}
_popup.show();
}
/** Returns true if this menu is the direct child of a menubar.
*/
public boolean isTopLevelMenu()
{
return (getParent() instanceof JMenuBar);
}
/** Returns a reference to this JMenu's popup menu.
*/
public JPopupMenu getPopupMenu()
{
return _popup;
}
/** Output a text description of the menu.
*/
public void debug(int level_)
{
for (int i=0; i<level_; i++)
System.err.print(" ");
System.err.println("JMenu origin=" + _origin + " text=" + getText());
}
public String toString() {
return "JMenu: text=" + getText();
}
//====================================================================
// PACKAGE-PRIVATE METHODS
/** This package-private method is called by JMenuwhen this JMenu
* is added to it as a submenu. It is not intended to be called
* by application programmers.
*/
void setParentMenu(Component parent_)
{
_parentMenu = new WeakReference<Component>(parent_);
// If the colors of this menu have not been set yet, inherit the
// colors of the parent.
if (super.getForeground() == null)
super.setForeground(parent_.getForeground());
if (super.getBackground() == null)
super.setBackground(parent_.getBackground());
}
Component getParentMenu() {
return (Component) _parentMenu.get();
}
//====================================================================
// INSTANCE VARIABLES
private Vector<Component> _menuItems = new Vector<Component>();
// Note that the reference to the parent is stored as a WeakReference
// so that the parent can be garbage-collected when it no longer has
// any strong references to it.
private WeakReference<Component> _parentMenu;
private boolean _popupMenuVisible = false;
//private final Point _popupMenuOrigin;
private JPopupMenu _popup;
}