1553 lines · 50.6 KB · Java
RawDownload
/* * 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.*;import java.awt.event.*;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;import java.beans.*; import java.util.Locale;import java.util.Vector;import java.util.Hashtable;import javax.accessibility.*;import javax.swing.plaf.PopupMenuUI;import javax.swing.plaf.ComponentUI;import javax.swing.plaf.basic.BasicComboPopup;import javax.swing.event.*;import sun.security.util.SecurityConstants; import java.applet.Applet; /** * An implementation of a popup menu -- a small window that pops up * and displays a series of choices. A <code>JPopupMenu</code> is used for the * menu that appears when the user selects an item on the menu bar. * It is also used for "pull-right" menu that appears when the * selects a menu item that activates it. Finally, a <code>JPopupMenu</code> * can also be used anywhere else you want a menu to appear.  For * example, when the user right-clicks in a specified area. * <p> * For information and examples of using popup menus, see * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/menu.html">How to Use Menus</a> * 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 false * description: A small window that pops up and displays a series of choices. * * @author Georges Saab * @author David Karlton * @author Arnaud Weber */public class JPopupMenu extends JComponent implements Accessible,MenuElement {     /**     * @see #getUIClassID     * @see #readObject     */    private static final String uiClassID = "PopupMenuUI";     /**     * Key used in AppContext to determine if light way popups are the default.     */    private static final Object defaultLWPopupEnabledKey =        new StringBuffer("JPopupMenu.defaultLWPopupEnabledKey");     /** Bug#4425878-Property javax.swing.adjustPopupLocationToFit introduced */    static boolean popupPostionFixDisabled = false;     static {        popupPostionFixDisabled = java.security.AccessController.doPrivileged(                new sun.security.action.GetPropertyAction(                "javax.swing.adjustPopupLocationToFit","")).equals("false");     }     transient  Component invoker;    transient  Popup popup;    transient  Frame frame;    private    int desiredLocationX,desiredLocationY;     private    String     label                   = null;    private    boolean   paintBorder              = true;    private    Insets    margin                   = null;     /**     * Used to indicate if lightweight popups should be used.     */    private    boolean   lightWeightPopup         = true;     /*     * Model for the selected subcontrol.     */    private SingleSelectionModel selectionModel;     /* Lock object used in place of class object for synchronization.     * (4187686)     */    private static final Object classLock = new Object();     /* 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.     /**     *  Sets the default value of the <code>lightWeightPopupEnabled</code>     *  property.     *     *  @param aFlag <code>true</code> if popups can be lightweight,     *               otherwise <code>false</code>     *  @see #getDefaultLightWeightPopupEnabled     *  @see #setLightWeightPopupEnabled     */    public static void setDefaultLightWeightPopupEnabled(boolean aFlag) {        SwingUtilities.appContextPut(defaultLWPopupEnabledKey,                                     Boolean.valueOf(aFlag));    }     /**     *  Gets the <code>defaultLightWeightPopupEnabled</code> property,     *  which by default is <code>true</code>.     *     *  @return the value of the <code>defaultLightWeightPopupEnabled</code>     *          property     *     *  @see #setDefaultLightWeightPopupEnabled     */    public static boolean getDefaultLightWeightPopupEnabled() {        Boolean b = (Boolean)            SwingUtilities.appContextGet(defaultLWPopupEnabledKey);        if (b == null) {            SwingUtilities.appContextPut(defaultLWPopupEnabledKey,                                         Boolean.TRUE);            return true;        }        return b.booleanValue();    }     /**     * Constructs a <code>JPopupMenu</code> without an "invoker".     */    public JPopupMenu() {        this(null);    }     /**     * Constructs a <code>JPopupMenu</code> with the specified title.     *     * @param label  the string that a UI may use to display as a title     * for the popup menu.     */    public JPopupMenu(String label) {        this.label = label;        lightWeightPopup = getDefaultLightWeightPopupEnabled();        setSelectionModel(new DefaultSingleSelectionModel());        enableEvents(AWTEvent.MOUSE_EVENT_MASK);        setFocusTraversalKeysEnabled(false);        updateUI();    }       /**     * Returns the look and feel (L&F) object that renders this component.     *     * @return the <code>PopupMenuUI</code> object that renders this component     */    public PopupMenuUI getUI() {        return (PopupMenuUI)ui;    }     /**     * Sets the L&F object that renders this component.     *     * @param ui the new <code>PopupMenuUI</code> L&F object     * @see UIDefaults#getUI     * @beaninfo     *        bound: true     *       hidden: true     *    attribute: visualUpdate true     *  description: The UI object that implements the Component's LookAndFeel.     */    public void setUI(PopupMenuUI ui) {        super.setUI(ui);    }     /**     * Resets the UI property to a value from the current look and feel.     *     * @see JComponent#updateUI     */    public void updateUI() {        setUI((PopupMenuUI)UIManager.getUI(this));    }      /**     * Returns the name of the L&F class that renders this component.     *     * @return the string "PopupMenuUI"     * @see JComponent#getUIClassID     * @see UIDefaults#getUI     */    public String getUIClassID() {        return uiClassID;    }     protected void processFocusEvent(FocusEvent evt) {        super.processFocusEvent(evt);    }     /**     * Processes key stroke events such as mnemonics and accelerators.     *     * @param evt  the key event to be processed     */    protected void processKeyEvent(KeyEvent evt) {        MenuSelectionManager.defaultManager().processKeyEvent(evt);        if (evt.isConsumed()) {            return;        }        super.processKeyEvent(evt);    }      /**     * Returns the model object that handles single selections.     *     * @return the <code>selectionModel</code> property     * @see SingleSelectionModel     */    public SingleSelectionModel getSelectionModel() {        return selectionModel;    }     /**     * Sets the model object to handle single selections.     *     * @param model the new <code>SingleSelectionModel</code>     * @see SingleSelectionModel     * @beaninfo     * description: The selection model for the popup menu     *      expert: true     */    public void setSelectionModel(SingleSelectionModel model) {        selectionModel = model;    }     /**     * Appends the specified menu item to the end of this menu.     *     * @param menuItem the <code>JMenuItem</code> to add     * @return the <code>JMenuItem</code> added     */    public JMenuItem add(JMenuItem menuItem) {        super.add(menuItem);        return menuItem;    }     /**     * Creates a new menu item with the specified text and appends     * it to the end of this menu.     *     * @param s the string for the menu item to be added     */    public JMenuItem add(String s) {        return add(new JMenuItem(s));    }     /**     * Appends a new menu item to the end of the menu which     * dispatches the specified <code>Action</code> object.     *     * @param a the <code>Action</code> to add to the menu     * @return the new menu item     * @see Action     */    public JMenuItem add(Action a) {        JMenuItem mi = createActionComponent(a);        mi.setAction(a);        add(mi);        return mi;    }     /**     * Returns an point which has been adjusted to take into account of the     * desktop bounds, taskbar and multi-monitor configuration.     * <p>     * This adustment may be cancelled by invoking the application with     * -Djavax.swing.adjustPopupLocationToFit=false     */    Point adjustPopupLocationToFitScreen(int xPosition, int yPosition) {        Point popupLocation = new Point(xPosition, yPosition);         if(popupPostionFixDisabled == true || GraphicsEnvironment.isHeadless()) {            return popupLocation;        }         // Get screen bounds        Rectangle scrBounds;        GraphicsConfiguration gc = getCurrentGraphicsConfiguration(popupLocation);        Toolkit toolkit = Toolkit.getDefaultToolkit();        if(gc != null) {            // If we have GraphicsConfiguration use it to get screen bounds            scrBounds = gc.getBounds();        } else {            // If we don't have GraphicsConfiguration use primary screen            scrBounds = new Rectangle(toolkit.getScreenSize());        }         // Calculate the screen size that popup should fit        Dimension popupSize = JPopupMenu.this.getPreferredSize();        long popupRightX = (long)popupLocation.x + (long)popupSize.width;        long popupBottomY = (long)popupLocation.y + (long)popupSize.height;        int scrWidth = scrBounds.width;        int scrHeight = scrBounds.height;        if (!canPopupOverlapTaskBar()) {            // Insets include the task bar. Take them into account.            Insets scrInsets = toolkit.getScreenInsets(gc);            scrBounds.x += scrInsets.left;            scrBounds.y += scrInsets.top;            scrWidth -= scrInsets.left + scrInsets.right;            scrHeight -= scrInsets.top + scrInsets.bottom;        }        int scrRightX = scrBounds.x + scrWidth;        int scrBottomY = scrBounds.y + scrHeight;         // Ensure that popup menu fits the screen        if (popupRightX > (long)scrRightX) {            popupLocation.x = scrRightX - popupSize.width;            if( popupLocation.x < scrBounds.x ) {                popupLocation.x = scrBounds.x ;            }        }        if (popupBottomY > (long)scrBottomY) {            popupLocation.y = scrBottomY - popupSize.height;            if( popupLocation.y < scrBounds.y ) {                popupLocation.y = scrBounds.y;            }        }         return popupLocation;    }     /**     * Tries to find GraphicsConfiguration     * that contains the mouse cursor position.     * Can return null.     */    private GraphicsConfiguration getCurrentGraphicsConfiguration(            Point popupLocation) {        GraphicsConfiguration gc = null;        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(popupLocation)) {                    gc = dgc;                    break;                }            }        }        // If not found and we have invoker, ask invoker about his gc        if(gc == null && getInvoker() != null) {            gc = getInvoker().getGraphicsConfiguration();        }        return gc;    }     /**     * Checks that there are enough security permissions     * to make popup "always on top", which allows to show it above the task bar.     */    static boolean canPopupOverlapTaskBar() {        boolean result = true;        try {            SecurityManager sm = System.getSecurityManager();            if (sm != null) {                sm.checkPermission(                    SecurityConstants.AWT.SET_WINDOW_ALWAYS_ON_TOP_PERMISSION);            }        } catch (SecurityException se) {            // There is no permission to show popups over the task bar            result = false;        }        return result;    }      /**     * Factory method which creates the <code>JMenuItem</code> for     * <code>Actions</code> added to the <code>JPopupMenu</code>.     *     * @param a the <code>Action</code> for the menu item to be added     * @return the new menu item     * @see Action     *     * @since 1.3     */    protected JMenuItem createActionComponent(Action a) {        JMenuItem mi = new JMenuItem() {            protected PropertyChangeListener createActionPropertyChangeListener(Action a) {                PropertyChangeListener pcl = createActionChangeListener(this);                if (pcl == null) {                    pcl = super.createActionPropertyChangeListener(a);                }                return pcl;            }        };        mi.setHorizontalTextPosition(JButton.TRAILING);        mi.setVerticalTextPosition(JButton.CENTER);        return mi;    }     /**     * Returns a properly configured <code>PropertyChangeListener</code>     * which updates the control as changes to the <code>Action</code> occur.     */    protected PropertyChangeListener createActionChangeListener(JMenuItem b) {        return b.createActionPropertyChangeListener0(b.getAction());    }     /**     * Removes the component at the specified index from this popup menu.     *     * @param       pos the position of the item to be removed     * @exception   IllegalArgumentException if the value of     *                          <code>pos</code> < 0, or if the value of     *                          <code>pos</code> is greater than the     *                          number of items     */    public void remove(int pos) {        if (pos < 0) {            throw new IllegalArgumentException("index less than zero.");        }        if (pos > getComponentCount() -1) {            throw new IllegalArgumentException("index greater than the number of items.");        }        super.remove(pos);    }     /**     * Sets the value of the <code>lightWeightPopupEnabled</code> property,     * which by default is <code>true</code>.     * By default, when a look and feel displays a popup,     * it can choose to     * use a lightweight (all-Java) popup.     * Lightweight popup windows are more efficient than heavyweight     * (native peer) windows,     * but lightweight and heavyweight components do not mix well in a GUI.     * If your application mixes lightweight and heavyweight components,     * you should disable lightweight popups.     * Some look and feels might always use heavyweight popups,     * no matter what the value of this property.     *     * @param aFlag  <code>false</code> to disable lightweight popups     * @beaninfo     * description: Determines whether lightweight popups are used when possible     *      expert: true     *     * @see #isLightWeightPopupEnabled     */    public void setLightWeightPopupEnabled(boolean aFlag) {        // NOTE: this use to set the flag on a shared JPopupMenu, which meant        // this effected ALL JPopupMenus.

Lines 1–500 of 1553.