/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.AWTEvent;import java.awt.Component;import java.awt.ComponentOrientation;import java.awt.Container;import java.awt.Dimension;import java.awt.Frame;import java.awt.Graphics;import java.awt.GraphicsConfiguration;import java.awt.GraphicsDevice;import java.awt.GraphicsEnvironment;import java.awt.Insets;import java.awt.Point;import java.awt.Polygon;import java.awt.Rectangle;import java.awt.Toolkit;import java.awt.event.*;import java.beans.*; import java.util.*; import java.io.Serializable;import java.io.ObjectOutputStream;import java.io.ObjectInputStream;import java.io.IOException; import javax.swing.event.*;import javax.swing.plaf.*;import javax.swing.plaf.basic.*;import javax.accessibility.*; import java.lang.ref.WeakReference; /** * An implementation of a menu -- a popup window containing * <code>JMenuItem</code>s that * is displayed when the user selects an item on the <code>JMenuBar</code>. * In addition to <code>JMenuItem</code>s, a <code>JMenu</code> can * also contain <code>JSeparator</code>s. * <p> * In essence, a menu is a button with an associated <code>JPopupMenu</code>. * When the "button" is pressed, the <code>JPopupMenu</code> appears. If the * "button" is on the <code>JMenuBar</code>, the menu is a top-level window. * If the "button" is another menu item, then the <code>JPopupMenu</code> is * "pull-right" menu. * <p> * Menus can be configured, and to some degree controlled, by * <code><a href="Action.html">Action</a></code>s. Using an * <code>Action</code> with a menu has many benefits beyond directly * configuring a menu. Refer to <a href="Action.html#buttonActions"> * Swing Components Supporting <code>Action</code></a> for more * details, and you can find more information in <a * href="http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html">How * to Use Actions</a>, a section in <em>The Java Tutorial</em>. * <p> * For information and examples of using menus see * <a href="http://java.sun.com/doc/books/tutorial/uiswing/components/menu.html">How to Use Menus</a>, * a section in <em>The Java Tutorial.</em> * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo * attribute: isContainer true * description: A popup window containing menu items displayed in a menu bar. * * @author Georges Saab * @author David Karlton * @author Arnaud Weber * @see JMenuItem * @see JSeparator * @see JMenuBar * @see JPopupMenu */public class JMenu extends JMenuItem implements Accessible,MenuElement{ /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "MenuUI"; /* * The popup menu portion of the menu. */ private JPopupMenu popupMenu; /* * The button's model listeners. Default is <code>null</code>. */ private ChangeListener menuChangeListener = null; /* * Only one <code>MenuEvent</code> is needed for each menu since the * event's only state is the source property. The source of events * generated is always "this". Default is <code>null</code>. */ private MenuEvent menuEvent = null; /* Registry of listeners created for <code>Action-JMenuItem</code> * linkage. This is needed so that references can * be cleaned up at remove time to allow garbage collection * Default is <code>null</code>. */ private static Hashtable listenerRegistry = null; /* * Used by the look and feel (L&F) code to handle * implementation specific menu behaviors. */ private int delay; /* * Location of the popup component. Location is <code>null</code> * if it was not customized by <code>setMenuLocation</code> */ private Point customMenuLocation = null; /* Diagnostic aids -- should be false for production builds. */ private static final boolean TRACE = false; // trace creates and disposes private static final boolean VERBOSE = false; // show reuse hits/misses private static final boolean DEBUG = false; // show bad params, misc. /** * Constructs a new <code>JMenu</code> with no text. */ public JMenu() { this(""); } /** * Constructs a new <code>JMenu</code> with the supplied string * as its text. * * @param s the text for the menu label */ public JMenu(String s) { super(s); } /** * Constructs a menu whose properties are taken from the * <code>Action</code> supplied. * @param a an <code>Action</code> * * @since 1.3 */ public JMenu(Action a) { this(); setAction(a); } /** * Constructs a new <code>JMenu</code> with the supplied string as * its text and specified as a tear-off menu or not. * * @param s the text for the menu label * @param b can the menu be torn off (not yet implemented) */ public JMenu(String s, boolean b) { this(s); } /** * Overriden to do nothing. We want JMenu to be focusable, but * <code>JMenuItem</code> doesn't want to be, thus we override this * do nothing. We don't invoke <code>setFocusable(true)</code> after * super's constructor has completed as this has the side effect that * <code>JMenu</code> will be considered traversable via the * keyboard, which we don't want. Making a Component traversable by * the keyboard after invoking <code>setFocusable(true)</code> is OK, * as <code>setFocusable</code> is new API * and is speced as such, but internally we don't want to use it like * this else we change the keyboard traversability. */ void initFocusability() { } /** * Resets the UI property with a value from the current look and feel. * * @see JComponent#updateUI */ public void updateUI() { setUI((MenuItemUI)UIManager.getUI(this)); if ( popupMenu != null ) { popupMenu.setUI((PopupMenuUI)UIManager.getUI(popupMenu)); } } /** * Returns the name of the L&F class that renders this component. * * @return the string "MenuUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return uiClassID; } // public void repaint(long tm, int x, int y, int width, int height) { // Thread.currentThread().dumpStack(); // super.repaint(tm,x,y,width,height); // } /** * Sets the data model for the "menu button" -- the label * that the user clicks to open or close the menu. * * @param newModel the <code>ButtonModel</code> * @see #getModel * @beaninfo * description: The menu's model * bound: true * expert: true * hidden: true */ public void setModel(ButtonModel newModel) { ButtonModel oldModel = getModel(); super.setModel(newModel); if (oldModel != null && menuChangeListener != null) { oldModel.removeChangeListener(menuChangeListener); menuChangeListener = null; } model = newModel; if (newModel != null) { menuChangeListener = createMenuChangeListener(); newModel.addChangeListener(menuChangeListener); } } /** * Returns true if the menu is currently selected (highlighted). * * @return true if the menu is selected, else false */ public boolean isSelected() { return getModel().isSelected(); } /** * Sets the selection status of the menu. * * @param b true to select (highlight) the menu; false to de-select * the menu * @beaninfo * description: When the menu is selected, its popup child is shown. * expert: true * hidden: true */ public void setSelected(boolean b) { ButtonModel model = getModel(); boolean oldValue = model.isSelected(); // TIGER - 4840653 // Removed code which fired an AccessibleState.SELECTED // PropertyChangeEvent since this resulted in two // identical events being fired since // AbstractButton.fireItemStateChanged also fires the // same event. This caused screen readers to speak the // name of the item twice. if (b != model.isSelected()) { getModel().setSelected(b); } } /** * Returns true if the menu's popup window is visible. * * @return true if the menu is visible, else false */ public boolean isPopupMenuVisible() { ensurePopupMenuCreated(); return popupMenu.isVisible(); } /** * Sets the visibility of the menu's popup. If the menu is * not enabled, this method will have no effect. * * @param b a boolean value -- true to make the menu visible, * false to hide it * @beaninfo * description: The popup menu's visibility * expert: true * hidden: true */ public void setPopupMenuVisible(boolean b) { if (DEBUG) { System.out.println("in JMenu.setPopupMenuVisible " + b); // Thread.dumpStack(); } boolean isVisible = isPopupMenuVisible(); if (b != isVisible && (isEnabled() || !b)) { ensurePopupMenuCreated(); if ((b==true) && isShowing()) { // Set location of popupMenu (pulldown or pullright) Point p = getCustomMenuLocation(); if (p == null) { p = getPopupMenuOrigin(); } getPopupMenu().show(this, p.x, p.y); } else { getPopupMenu().setVisible(false); } } } /** * Computes the origin for the <code>JMenu</code>'s popup menu. * This method uses Look and Feel properties named * <code>Menu.menuPopupOffsetX</code>, * <code>Menu.menuPopupOffsetY</code>, * <code>Menu.submenuPopupOffsetX</code>, and * <code>Menu.submenuPopupOffsetY</code> * to adjust the exact location of popup. * * @return a <code>Point</code> in the coordinate space of the * menu which should be used as the origin * of the <code>JMenu</code>'s popup menu * * @since 1.3 */ protected Point getPopupMenuOrigin() { int x; int y; JPopupMenu pm = getPopupMenu(); // Figure out the sizes needed to caclulate the menu position Dimension s = getSize(); Dimension pmSize = pm.getSize(); // For the first time the menu is popped up, // the size has not yet been initiated if (pmSize.width==0) { pmSize = pm.getPreferredSize(); } Point position = getLocationOnScreen(); Toolkit toolkit = Toolkit.getDefaultToolkit(); GraphicsConfiguration gc = getGraphicsConfiguration(); Rectangle screenBounds = new Rectangle(toolkit.getScreenSize()); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gd = ge.getScreenDevices(); for(int i = 0; i < gd.length; i++) { if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) { GraphicsConfiguration dgc = gd[i].getDefaultConfiguration(); if(dgc.getBounds().contains(position)) { gc = dgc; break; } } } if (gc != null) { screenBounds = gc.getBounds(); // take screen insets (e.g. taskbar) into account Insets screenInsets = toolkit.getScreenInsets(gc); screenBounds.width -= Math.abs(screenInsets.left + screenInsets.right); screenBounds.height -= Math.abs(screenInsets.top + screenInsets.bottom); position.x -= Math.abs(screenInsets.left); position.y -= Math.abs(screenInsets.top); } Container parent = getParent(); if (parent instanceof JPopupMenu) { // We are a submenu (pull-right) int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX"); int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY"); if( SwingUtilities.isLeftToRight(this) ) { // First determine x: x = s.width + xOffset; // Prefer placement to the right if (position.x + x + pmSize.width >= screenBounds.width + screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width < 2*(position.x - screenBounds.x)) { x = 0 - xOffset - pmSize.width; } } else { // First determine x: x = 0 - xOffset - pmSize.width; // Prefer placement to the left if (position.x + x < screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width > 2*(position.x - screenBounds.x)) { x = s.width + xOffset; } } // Then the y: y = yOffset; // Prefer dropping down if (position.y + y + pmSize.height >= screenBounds.height + screenBounds.y && // popup doesn't fit - place it wherever there's more room screenBounds.height - s.height < 2*(position.y - screenBounds.y)) { y = s.height - yOffset - pmSize.height; } } else { // We are a toplevel menu (pull-down) int xOffset = UIManager.getInt("Menu.menuPopupOffsetX"); int yOffset = UIManager.getInt("Menu.menuPopupOffsetY"); if( SwingUtilities.isLeftToRight(this) ) { // First determine the x: x = xOffset; // Extend to the right if (position.x + x + pmSize.width >= screenBounds.width + screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width < 2*(position.x - screenBounds.x)) { x = s.width - xOffset - pmSize.width; } } else { // First determine the x: x = s.width - xOffset - pmSize.width; // Extend to the left if (position.x + x < screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width > 2*(position.x - screenBounds.x)) { x = xOffset; } } // Then the y: y = s.height + yOffset; // Prefer dropping down if (position.y + y + pmSize.height >= screenBounds.height && // popup doesn't fit - place it wherever there's more room screenBounds.height - s.height < 2*(position.y - screenBounds.y)) { y = 0 - yOffset - pmSize.height; // Otherwise drop 'up' } } return new Point(x,y); } /** * Returns the suggested delay, in milliseconds, before submenus * are popped up or down. * Each look and feel (L&F) may determine its own policy for * observing the <code>delay</code> property.Lines 1–500 of 1624. Load more
/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.AWTEvent; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Insets; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.*; import java.beans.*; import java.util.*; import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import javax.swing.event.*; import javax.swing.plaf.*; import javax.swing.plaf.basic.*; import javax.accessibility.*; import java.lang.ref.WeakReference; /** * An implementation of a menu -- a popup window containing * <code>JMenuItem</code>s that * is displayed when the user selects an item on the <code>JMenuBar</code>. * In addition to <code>JMenuItem</code>s, a <code>JMenu</code> can * also contain <code>JSeparator</code>s. * <p> * In essence, a menu is a button with an associated <code>JPopupMenu</code>. * When the "button" is pressed, the <code>JPopupMenu</code> appears. If the * "button" is on the <code>JMenuBar</code>, the menu is a top-level window. * If the "button" is another menu item, then the <code>JPopupMenu</code> is * "pull-right" menu. * <p> * Menus can be configured, and to some degree controlled, by * <code><a href="Action.html">Action</a></code>s. Using an * <code>Action</code> with a menu has many benefits beyond directly * configuring a menu. Refer to <a href="Action.html#buttonActions"> * Swing Components Supporting <code>Action</code></a> for more * details, and you can find more information in <a * href="http://java.sun.com/docs/books/tutorial/uiswing/misc/action.html">How * to Use Actions</a>, a section in <em>The Java Tutorial</em>. * <p> * For information and examples of using menus see * <a href="http://java.sun.com/doc/books/tutorial/uiswing/components/menu.html">How to Use Menus</a>, * a section in <em>The Java Tutorial.</em> * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @beaninfo * attribute: isContainer true * description: A popup window containing menu items displayed in a menu bar. * * @author Georges Saab * @author David Karlton * @author Arnaud Weber * @see JMenuItem * @see JSeparator * @see JMenuBar * @see JPopupMenu */ public class JMenu extends JMenuItem implements Accessible,MenuElement { /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "MenuUI"; /* * The popup menu portion of the menu. */ private JPopupMenu popupMenu; /* * The button's model listeners. Default is <code>null</code>. */ private ChangeListener menuChangeListener = null; /* * Only one <code>MenuEvent</code> is needed for each menu since the * event's only state is the source property. The source of events * generated is always "this". Default is <code>null</code>. */ private MenuEvent menuEvent = null; /* Registry of listeners created for <code>Action-JMenuItem</code> * linkage. This is needed so that references can * be cleaned up at remove time to allow garbage collection * Default is <code>null</code>. */ private static Hashtable listenerRegistry = null; /* * Used by the look and feel (L&F) code to handle * implementation specific menu behaviors. */ private int delay; /* * Location of the popup component. Location is <code>null</code> * if it was not customized by <code>setMenuLocation</code> */ private Point customMenuLocation = null; /* Diagnostic aids -- should be false for production builds. */ private static final boolean TRACE = false; // trace creates and disposes private static final boolean VERBOSE = false; // show reuse hits/misses private static final boolean DEBUG = false; // show bad params, misc. /** * Constructs a new <code>JMenu</code> with no text. */ public JMenu() { this(""); } /** * Constructs a new <code>JMenu</code> with the supplied string * as its text. * * @param s the text for the menu label */ public JMenu(String s) { super(s); } /** * Constructs a menu whose properties are taken from the * <code>Action</code> supplied. * @param a an <code>Action</code> * * @since 1.3 */ public JMenu(Action a) { this(); setAction(a); } /** * Constructs a new <code>JMenu</code> with the supplied string as * its text and specified as a tear-off menu or not. * * @param s the text for the menu label * @param b can the menu be torn off (not yet implemented) */ public JMenu(String s, boolean b) { this(s); } /** * Overriden to do nothing. We want JMenu to be focusable, but * <code>JMenuItem</code> doesn't want to be, thus we override this * do nothing. We don't invoke <code>setFocusable(true)</code> after * super's constructor has completed as this has the side effect that * <code>JMenu</code> will be considered traversable via the * keyboard, which we don't want. Making a Component traversable by * the keyboard after invoking <code>setFocusable(true)</code> is OK, * as <code>setFocusable</code> is new API * and is speced as such, but internally we don't want to use it like * this else we change the keyboard traversability. */ void initFocusability() { } /** * Resets the UI property with a value from the current look and feel. * * @see JComponent#updateUI */ public void updateUI() { setUI((MenuItemUI)UIManager.getUI(this)); if ( popupMenu != null ) { popupMenu.setUI((PopupMenuUI)UIManager.getUI(popupMenu)); } } /** * Returns the name of the L&F class that renders this component. * * @return the string "MenuUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return uiClassID; } // public void repaint(long tm, int x, int y, int width, int height) { // Thread.currentThread().dumpStack(); // super.repaint(tm,x,y,width,height); // } /** * Sets the data model for the "menu button" -- the label * that the user clicks to open or close the menu. * * @param newModel the <code>ButtonModel</code> * @see #getModel * @beaninfo * description: The menu's model * bound: true * expert: true * hidden: true */ public void setModel(ButtonModel newModel) { ButtonModel oldModel = getModel(); super.setModel(newModel); if (oldModel != null && menuChangeListener != null) { oldModel.removeChangeListener(menuChangeListener); menuChangeListener = null; } model = newModel; if (newModel != null) { menuChangeListener = createMenuChangeListener(); newModel.addChangeListener(menuChangeListener); } } /** * Returns true if the menu is currently selected (highlighted). * * @return true if the menu is selected, else false */ public boolean isSelected() { return getModel().isSelected(); } /** * Sets the selection status of the menu. * * @param b true to select (highlight) the menu; false to de-select * the menu * @beaninfo * description: When the menu is selected, its popup child is shown. * expert: true * hidden: true */ public void setSelected(boolean b) { ButtonModel model = getModel(); boolean oldValue = model.isSelected(); // TIGER - 4840653 // Removed code which fired an AccessibleState.SELECTED // PropertyChangeEvent since this resulted in two // identical events being fired since // AbstractButton.fireItemStateChanged also fires the // same event. This caused screen readers to speak the // name of the item twice. if (b != model.isSelected()) { getModel().setSelected(b); } } /** * Returns true if the menu's popup window is visible. * * @return true if the menu is visible, else false */ public boolean isPopupMenuVisible() { ensurePopupMenuCreated(); return popupMenu.isVisible(); } /** * Sets the visibility of the menu's popup. If the menu is * not enabled, this method will have no effect. * * @param b a boolean value -- true to make the menu visible, * false to hide it * @beaninfo * description: The popup menu's visibility * expert: true * hidden: true */ public void setPopupMenuVisible(boolean b) { if (DEBUG) { System.out.println("in JMenu.setPopupMenuVisible " + b); // Thread.dumpStack(); } boolean isVisible = isPopupMenuVisible(); if (b != isVisible && (isEnabled() || !b)) { ensurePopupMenuCreated(); if ((b==true) && isShowing()) { // Set location of popupMenu (pulldown or pullright) Point p = getCustomMenuLocation(); if (p == null) { p = getPopupMenuOrigin(); } getPopupMenu().show(this, p.x, p.y); } else { getPopupMenu().setVisible(false); } } } /** * Computes the origin for the <code>JMenu</code>'s popup menu. * This method uses Look and Feel properties named * <code>Menu.menuPopupOffsetX</code>, * <code>Menu.menuPopupOffsetY</code>, * <code>Menu.submenuPopupOffsetX</code>, and * <code>Menu.submenuPopupOffsetY</code> * to adjust the exact location of popup. * * @return a <code>Point</code> in the coordinate space of the * menu which should be used as the origin * of the <code>JMenu</code>'s popup menu * * @since 1.3 */ protected Point getPopupMenuOrigin() { int x; int y; JPopupMenu pm = getPopupMenu(); // Figure out the sizes needed to caclulate the menu position Dimension s = getSize(); Dimension pmSize = pm.getSize(); // For the first time the menu is popped up, // the size has not yet been initiated if (pmSize.width==0) { pmSize = pm.getPreferredSize(); } Point position = getLocationOnScreen(); Toolkit toolkit = Toolkit.getDefaultToolkit(); GraphicsConfiguration gc = getGraphicsConfiguration(); Rectangle screenBounds = new Rectangle(toolkit.getScreenSize()); GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice[] gd = ge.getScreenDevices(); for(int i = 0; i < gd.length; i++) { if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) { GraphicsConfiguration dgc = gd[i].getDefaultConfiguration(); if(dgc.getBounds().contains(position)) { gc = dgc; break; } } } if (gc != null) { screenBounds = gc.getBounds(); // take screen insets (e.g. taskbar) into account Insets screenInsets = toolkit.getScreenInsets(gc); screenBounds.width -= Math.abs(screenInsets.left + screenInsets.right); screenBounds.height -= Math.abs(screenInsets.top + screenInsets.bottom); position.x -= Math.abs(screenInsets.left); position.y -= Math.abs(screenInsets.top); } Container parent = getParent(); if (parent instanceof JPopupMenu) { // We are a submenu (pull-right) int xOffset = UIManager.getInt("Menu.submenuPopupOffsetX"); int yOffset = UIManager.getInt("Menu.submenuPopupOffsetY"); if( SwingUtilities.isLeftToRight(this) ) { // First determine x: x = s.width + xOffset; // Prefer placement to the right if (position.x + x + pmSize.width >= screenBounds.width + screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width < 2*(position.x - screenBounds.x)) { x = 0 - xOffset - pmSize.width; } } else { // First determine x: x = 0 - xOffset - pmSize.width; // Prefer placement to the left if (position.x + x < screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width > 2*(position.x - screenBounds.x)) { x = s.width + xOffset; } } // Then the y: y = yOffset; // Prefer dropping down if (position.y + y + pmSize.height >= screenBounds.height + screenBounds.y && // popup doesn't fit - place it wherever there's more room screenBounds.height - s.height < 2*(position.y - screenBounds.y)) { y = s.height - yOffset - pmSize.height; } } else { // We are a toplevel menu (pull-down) int xOffset = UIManager.getInt("Menu.menuPopupOffsetX"); int yOffset = UIManager.getInt("Menu.menuPopupOffsetY"); if( SwingUtilities.isLeftToRight(this) ) { // First determine the x: x = xOffset; // Extend to the right if (position.x + x + pmSize.width >= screenBounds.width + screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width < 2*(position.x - screenBounds.x)) { x = s.width - xOffset - pmSize.width; } } else { // First determine the x: x = s.width - xOffset - pmSize.width; // Extend to the left if (position.x + x < screenBounds.x && // popup doesn't fit - place it wherever there's more room screenBounds.width - s.width > 2*(position.x - screenBounds.x)) { x = xOffset; } } // Then the y: y = s.height + yOffset; // Prefer dropping down if (position.y + y + pmSize.height >= screenBounds.height && // popup doesn't fit - place it wherever there's more room screenBounds.height - s.height < 2*(position.y - screenBounds.y)) { y = 0 - yOffset - pmSize.height; // Otherwise drop 'up' } } return new Point(x,y); } /** * Returns the suggested delay, in milliseconds, before submenus * are popped up or down. * Each look and feel (L&F) may determine its own policy for * observing the <code>delay</code> property.