/* |
|
* Copyright (c) 1997, 2013, 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.awt.SunToolkit; |
|
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="https://docs.oracle.com/javase/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™ |
|
* 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 |
|
*/ |
|
@SuppressWarnings("serial") |
|
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 (popupBottomY > (long) scrBottomY) { |
|
popupLocation.y = scrBottomY - popupSize.height; |
|
} |
|
if (popupLocation.x < scrBounds.x) { |
|
popupLocation.x = scrBounds.x; |
|
} |
|
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; |
|
} |
|
/** |
|
* Returns whether popup is allowed to be shown above the task bar. |
|
*/ |
|
static boolean canPopupOverlapTaskBar() { |
|
boolean result = true; |
|
Toolkit tk = Toolkit.getDefaultToolkit(); |
|
if (tk instanceof SunToolkit) { |
|
result = ((SunToolkit)tk).canPopupOverlapTaskBar(); |
|
} |
|
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. |
|
lightWeightPopup = aFlag; |
|
} |
|
/** |
|
* Gets the <code>lightWeightPopupEnabled</code> property. |
|
* |
|
* @return the value of the <code>lightWeightPopupEnabled</code> property |
|
* @see #setLightWeightPopupEnabled |
|
*/ |
|
public boolean isLightWeightPopupEnabled() { |
|
return lightWeightPopup; |
|
} |
|
/** |
|
* Returns the popup menu's label |
|
* |
|
* @return a string containing the popup menu's label |
|
* @see #setLabel |
|
*/ |
|
public String getLabel() { |
|
return label; |
|
} |
|
/** |
|
* Sets the popup menu's label. Different look and feels may choose |
|
* to display or not display this. |
|
* |
|
* @param label a string specifying the label for the popup menu |
|
* |
|
* @see #setLabel |
|
* @beaninfo |
|
* description: The label for the popup menu. |
|
* bound: true |
|
*/ |
|
public void setLabel(String label) { |
|
String oldValue = this.label; |
|
this.label = label; |
|
firePropertyChange("label", oldValue, label); |
|
if (accessibleContext != null) { |
|
accessibleContext.firePropertyChange( |
|
AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY, |
|
oldValue, label); |
|
} |
|
invalidate(); |
|
repaint(); |
|
} |
|
/** |
|
* Appends a new separator at the end of the menu. |
|
*/ |
|
public void addSeparator() { |
|
add( new JPopupMenu.Separator() ); |
|
} |
|
/** |
|
* Inserts a menu item for the specified <code>Action</code> object at |
|
* a given position. |
|
* |
|
* @param a the <code>Action</code> object to insert |
|
* @param index specifies the position at which to insert the |
|
* <code>Action</code>, where 0 is the first |
|
* @exception IllegalArgumentException if <code>index</code> < 0 |
|
* @see Action |
|
*/ |
|
public void insert(Action a, int index) { |
|
JMenuItem mi = createActionComponent(a); |
|
mi.setAction(a); |
|
insert(mi, index); |
|
} |
|
/** |
|
* Inserts the specified component into the menu at a given |
|
* position. |
|
* |
|
* @param component the <code>Component</code> to insert |
|
* @param index specifies the position at which |
|
* to insert the component, where 0 is the first |
|
* @exception IllegalArgumentException if <code>index</code> < 0 |
|
*/ |
|
public void insert(Component component, int index) { |
|
if (index < 0) { |
|
throw new IllegalArgumentException("index less than zero."); |
|
} |
|
int nitems = getComponentCount(); |
|
// PENDING(ges): Why not use an array? |
|
Vector<Component> tempItems = new Vector<Component>(); |
|
/* Remove the item at index, nitems-index times |
|
storing them in a temporary vector in the |
|
order they appear on the menu. |
|
*/ |
|
for (int i = index ; i < nitems; i++) { |
|
tempItems.addElement(getComponent(index)); |
|
remove(index); |
|
} |
|
add(component); |
|
/* Add the removed items back to the menu, they are |
|
already in the correct order in the temp vector. |
|
*/ |
|
for (Component tempItem : tempItems) { |
|
add(tempItem); |
|
} |
|
} |
|
/** |
|
* Adds a <code>PopupMenu</code> listener. |
|
* |
|
* @param l the <code>PopupMenuListener</code> to add |
|
*/ |
|
public void addPopupMenuListener(PopupMenuListener l) { |
|
listenerList.add(PopupMenuListener.class,l); |
|
} |
|
/** |
|
* Removes a <code>PopupMenu</code> listener. |
|
* |
|
* @param l the <code>PopupMenuListener</code> to remove |
|
*/ |
|
public void removePopupMenuListener(PopupMenuListener l) { |
|
listenerList.remove(PopupMenuListener.class,l); |
|
} |
|
/** |
|
* Returns an array of all the <code>PopupMenuListener</code>s added |
|
* to this JMenuItem with addPopupMenuListener(). |
|
* |
|
* @return all of the <code>PopupMenuListener</code>s added or an empty |
|
* array if no listeners have been added |
|
* @since 1.4 |
|
*/ |
|
public PopupMenuListener[] getPopupMenuListeners() { |
|
return listenerList.getListeners(PopupMenuListener.class); |
|
} |
|
/** |
|
* Adds a <code>MenuKeyListener</code> to the popup menu. |
|
* |
|
* @param l the <code>MenuKeyListener</code> to be added |
|
* @since 1.5 |
|
*/ |
|
public void addMenuKeyListener(MenuKeyListener l) { |
|
listenerList.add(MenuKeyListener.class, l); |
|
} |
|
/** |
|
* Removes a <code>MenuKeyListener</code> from the popup menu. |
|
* |
|
* @param l the <code>MenuKeyListener</code> to be removed |
|
* @since 1.5 |
|
*/ |
|
public void removeMenuKeyListener(MenuKeyListener l) { |
|
listenerList.remove(MenuKeyListener.class, l); |
|
} |
|
/** |
|
* Returns an array of all the <code>MenuKeyListener</code>s added |
|
* to this JPopupMenu with addMenuKeyListener(). |
|
* |
|
* @return all of the <code>MenuKeyListener</code>s added or an empty |
|
* array if no listeners have been added |
|
* @since 1.5 |
|
*/ |
|
public MenuKeyListener[] getMenuKeyListeners() { |
|
return listenerList.getListeners(MenuKeyListener.class); |
|
} |
|
/** |
|
* Notifies <code>PopupMenuListener</code>s that this popup menu will |
|
* become visible. |
|
*/ |
|
protected void firePopupMenuWillBecomeVisible() { |
|
Object[] listeners = listenerList.getListenerList(); |
|
PopupMenuEvent e=null; |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==PopupMenuListener.class) { |
|
if (e == null) |
|
e = new PopupMenuEvent(this); |
|
((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e); |
|
} |
|
} |
|
} |
|
/** |
|
* Notifies <code>PopupMenuListener</code>s that this popup menu will |
|
* become invisible. |
|
*/ |
|
protected void firePopupMenuWillBecomeInvisible() { |
|
Object[] listeners = listenerList.getListenerList(); |
|
PopupMenuEvent e=null; |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==PopupMenuListener.class) { |
|
if (e == null) |
|
e = new PopupMenuEvent(this); |
|
((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e); |
|
} |
|
} |
|
} |
|
/** |
|
* Notifies <code>PopupMenuListeners</code> that this popup menu is |
|
* cancelled. |
|
*/ |
|
protected void firePopupMenuCanceled() { |
|
Object[] listeners = listenerList.getListenerList(); |
|
PopupMenuEvent e=null; |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==PopupMenuListener.class) { |
|
if (e == null) |
|
e = new PopupMenuEvent(this); |
|
((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e); |
|
} |
|
} |
|
} |
|
/** |
|
* Always returns true since popups, by definition, should always |
|
* be on top of all other windows. |
|
* @return true |
|
*/ |
|
// package private |
|
boolean alwaysOnTop() { |
|
return true; |
|
} |
|
/** |
|
* Lays out the container so that it uses the minimum space |
|
* needed to display its contents. |
|
*/ |
|
public void pack() { |
|
if(popup != null) { |
|
Dimension pref = getPreferredSize(); |
|
if (pref == null || pref.width != getWidth() || |
|
pref.height != getHeight()) { |
|
showPopup(); |
|
} else { |
|
validate(); |
|
} |
|
} |
|
} |
|
/** |
|
* Sets the visibility of the popup menu. |
|
* |
|
* @param b true to make the popup visible, or false to |
|
* hide it |
|
* @beaninfo |
|
* bound: true |
|
* description: Makes the popup visible |
|
*/ |
|
public void setVisible(boolean b) { |
|
if (DEBUG) { |
|
System.out.println("JPopupMenu.setVisible " + b); |
|
} |
|
// Is it a no-op? |
|
if (b == isVisible()) |
|
return; |
|
// if closing, first close all Submenus |
|
if (b == false) { |
|
// 4234793: This is a workaround because JPopupMenu.firePopupMenuCanceled is |
|
// a protected method and cannot be called from BasicPopupMenuUI directly |
|
// The real solution could be to make |
|
// firePopupMenuCanceled public and call it directly. |
|
Boolean doCanceled = (Boolean)getClientProperty("JPopupMenu.firePopupMenuCanceled"); |
|
if (doCanceled != null && doCanceled == Boolean.TRUE) { |
|
putClientProperty("JPopupMenu.firePopupMenuCanceled", Boolean.FALSE); |
|
firePopupMenuCanceled(); |
|
} |
|
getSelectionModel().clearSelection(); |
|
} else { |
|
// This is a popup menu with MenuElement children, |
|
// set selection path before popping up! |
|
if (isPopupMenu()) { |
|
MenuElement me[] = new MenuElement[1]; |
|
me[0] = this; |
|
MenuSelectionManager.defaultManager().setSelectedPath(me); |
|
} |
|
} |
|
if(b) { |
|
firePopupMenuWillBecomeVisible(); |
|
showPopup(); |
|
firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE); |
|
} else if(popup != null) { |
|
firePopupMenuWillBecomeInvisible(); |
|
popup.hide(); |
|
popup = null; |
|
firePropertyChange("visible", Boolean.TRUE, Boolean.FALSE); |
|
// 4694797: When popup menu is made invisible, selected path |
|
// should be cleared |
|
if (isPopupMenu()) { |
|
MenuSelectionManager.defaultManager().clearSelectedPath(); |
|
} |
|
} |
|
} |
|
/** |
|
* Retrieves <code>Popup</code> instance from the |
|
* <code>PopupMenuUI</code> that has had <code>show</code> invoked on |
|
* it. If the current <code>popup</code> is non-null, |
|
* this will invoke <code>dispose</code> of it, and then |
|
* <code>show</code> the new one. |
|
* <p> |
|
* This does NOT fire any events, it is up the caller to dispatch |
|
* the necessary events. |
|
*/ |
|
private void showPopup() { |
|
Popup oldPopup = popup; |
|
if (oldPopup != null) { |
|
oldPopup.hide(); |
|
} |
|
PopupFactory popupFactory = PopupFactory.getSharedInstance(); |
|
if (isLightWeightPopupEnabled()) { |
|
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP); |
|
} |
|
else { |
|
popupFactory.setPopupType(PopupFactory.HEAVY_WEIGHT_POPUP); |
|
} |
|
// adjust the location of the popup |
|
Point p = adjustPopupLocationToFitScreen(desiredLocationX,desiredLocationY); |
|
desiredLocationX = p.x; |
|
desiredLocationY = p.y; |
|
Popup newPopup = getUI().getPopup(this, desiredLocationX, |
|
desiredLocationY); |
|
popupFactory.setPopupType(PopupFactory.LIGHT_WEIGHT_POPUP); |
|
popup = newPopup; |
|
newPopup.show(); |
|
} |
|
/** |
|
* Returns true if the popup menu is visible (currently |
|
* being displayed). |
|
*/ |
|
public boolean isVisible() { |
|
return popup != null; |
|
} |
|
/** |
|
* Sets the location of the upper left corner of the |
|
* popup menu using x, y coordinates. |
|
* <p> |
|
* The method changes the geometry-related data. Therefore, |
|
* the native windowing system may ignore such requests, or it may modify |
|
* the requested data, so that the {@code JPopupMenu} object is placed and sized |
|
* in a way that corresponds closely to the desktop settings. |
|
* |
|
* @param x the x coordinate of the popup's new position |
|
* in the screen's coordinate space |
|
* @param y the y coordinate of the popup's new position |
|
* in the screen's coordinate space |
|
* @beaninfo |
|
* description: The location of the popup menu. |
|
*/ |
|
public void setLocation(int x, int y) { |
|
int oldX = desiredLocationX; |
|
int oldY = desiredLocationY; |
|
desiredLocationX = x; |
|
desiredLocationY = y; |
|
if(popup != null && (x != oldX || y != oldY)) { |
|
showPopup(); |
|
} |
|
} |
|
/** |
|
* Returns true if the popup menu is a standalone popup menu |
|
* rather than the submenu of a <code>JMenu</code>. |
|
* |
|
* @return true if this menu is a standalone popup menu, otherwise false |
|
*/ |
|
private boolean isPopupMenu() { |
|
return ((invoker != null) && !(invoker instanceof JMenu)); |
|
} |
|
/** |
|
* Returns the component which is the 'invoker' of this |
|
* popup menu. |
|
* |
|
* @return the <code>Component</code> in which the popup menu is displayed |
|
*/ |
|
public Component getInvoker() { |
|
return this.invoker; |
|
} |
|
/** |
|
* Sets the invoker of this popup menu -- the component in which |
|
* the popup menu menu is to be displayed. |
|
* |
|
* @param invoker the <code>Component</code> in which the popup |
|
* menu is displayed |
|
* @beaninfo |
|
* description: The invoking component for the popup menu |
|
* expert: true |
|
*/ |
|
public void setInvoker(Component invoker) { |
|
Component oldInvoker = this.invoker; |
|
this.invoker = invoker; |
|
if ((oldInvoker != this.invoker) && (ui != null)) { |
|
ui.uninstallUI(this); |
|
ui.installUI(this); |
|
} |
|
invalidate(); |
|
} |
|
/** |
|
* Displays the popup menu at the position x,y in the coordinate |
|
* space of the component invoker. |
|
* |
|
* @param invoker the component in whose space the popup menu is to appear |
|
* @param x the x coordinate in invoker's coordinate space at which |
|
* the popup menu is to be displayed |
|
* @param y the y coordinate in invoker's coordinate space at which |
|
* the popup menu is to be displayed |
|
*/ |
|
public void show(Component invoker, int x, int y) { |
|
if (DEBUG) { |
|
System.out.println("in JPopupMenu.show " ); |
|
} |
|
setInvoker(invoker); |
|
Frame newFrame = getFrame(invoker); |
|
if (newFrame != frame) { |
|
// Use the invoker's frame so that events |
|
// are propagated properly |
|
if (newFrame!=null) { |
|
this.frame = newFrame; |
|
if(popup != null) { |
|
setVisible(false); |
|
} |
|
} |
|
} |
|
Point invokerOrigin; |
|
if (invoker != null) { |
|
invokerOrigin = invoker.getLocationOnScreen(); |
|
// To avoid integer overflow |
|
long lx, ly; |
|
lx = ((long) invokerOrigin.x) + |
|
((long) x); |
|
ly = ((long) invokerOrigin.y) + |
|
((long) y); |
|
if(lx > Integer.MAX_VALUE) lx = Integer.MAX_VALUE; |
|
if(lx < Integer.MIN_VALUE) lx = Integer.MIN_VALUE; |
|
if(ly > Integer.MAX_VALUE) ly = Integer.MAX_VALUE; |
|
if(ly < Integer.MIN_VALUE) ly = Integer.MIN_VALUE; |
|
setLocation((int) lx, (int) ly); |
|
} else { |
|
setLocation(x, y); |
|
} |
|
setVisible(true); |
|
} |
|
/** |
|
* Returns the popup menu which is at the root of the menu system |
|
* for this popup menu. |
|
* |
|
* @return the topmost grandparent <code>JPopupMenu</code> |
|
*/ |
|
JPopupMenu getRootPopupMenu() { |
|
JPopupMenu mp = this; |
|
while((mp!=null) && (mp.isPopupMenu()!=true) && |
|
(mp.getInvoker() != null) && |
|
(mp.getInvoker().getParent() != null) && |
|
(mp.getInvoker().getParent() instanceof JPopupMenu) |
|
) { |
|
mp = (JPopupMenu) mp.getInvoker().getParent(); |
|
} |
|
return mp; |
|
} |
|
/** |
|
* Returns the component at the specified index. |
|
* |
|
* @param i the index of the component, where 0 is the first |
|
* @return the <code>Component</code> at that index |
|
* @deprecated replaced by {@link java.awt.Container#getComponent(int)} |
|
*/ |
|
@Deprecated |
|
public Component getComponentAtIndex(int i) { |
|
return getComponent(i); |
|
} |
|
/** |
|
* Returns the index of the specified component. |
|
* |
|
* @param c the <code>Component</code> to find |
|
* @return the index of the component, where 0 is the first; |
|
* or -1 if the component is not found |
|
*/ |
|
public int getComponentIndex(Component c) { |
|
int ncomponents = this.getComponentCount(); |
|
Component[] component = this.getComponents(); |
|
for (int i = 0 ; i < ncomponents ; i++) { |
|
Component comp = component[i]; |
|
if (comp == c) |
|
return i; |
|
} |
|
return -1; |
|
} |
|
/** |
|
* Sets the size of the Popup window using a <code>Dimension</code> object. |
|
* This is equivalent to <code>setPreferredSize(d)</code>. |
|
* |
|
* @param d the <code>Dimension</code> specifying the new size |
|
* of this component. |
|
* @beaninfo |
|
* description: The size of the popup menu |
|
*/ |
|
public void setPopupSize(Dimension d) { |
|
Dimension oldSize = getPreferredSize(); |
|
setPreferredSize(d); |
|
if (popup != null) { |
|
Dimension newSize = getPreferredSize(); |
|
if (!oldSize.equals(newSize)) { |
|
showPopup(); |
|
} |
|
} |
|
} |
|
/** |
|
* Sets the size of the Popup window to the specified width and |
|
* height. This is equivalent to |
|
* <code>setPreferredSize(new Dimension(width, height))</code>. |
|
* |
|
* @param width the new width of the Popup in pixels |
|
* @param height the new height of the Popup in pixels |
|
* @beaninfo |
|
* description: The size of the popup menu |
|
*/ |
|
public void setPopupSize(int width, int height) { |
|
setPopupSize(new Dimension(width, height)); |
|
} |
|
/** |
|
* Sets the currently selected component, This will result |
|
* in a change to the selection model. |
|
* |
|
* @param sel the <code>Component</code> to select |
|
* @beaninfo |
|
* description: The selected component on the popup menu |
|
* expert: true |
|
* hidden: true |
|
*/ |
|
public void setSelected(Component sel) { |
|
SingleSelectionModel model = getSelectionModel(); |
|
int index = getComponentIndex(sel); |
|
model.setSelectedIndex(index); |
|
} |
|
/** |
|
* Checks whether the border should be painted. |
|
* |
|
* @return true if the border is painted, false otherwise |
|
* @see #setBorderPainted |
|
*/ |
|
public boolean isBorderPainted() { |
|
return paintBorder; |
|
} |
|
/** |
|
* Sets whether the border should be painted. |
|
* |
|
* @param b if true, the border is painted. |
|
* @see #isBorderPainted |
|
* @beaninfo |
|
* description: Is the border of the popup menu painted |
|
*/ |
|
public void setBorderPainted(boolean b) { |
|
paintBorder = b; |
|
repaint(); |
|
} |
|
/** |
|
* Paints the popup menu's border if the <code>borderPainted</code> |
|
* property is <code>true</code>. |
|
* @param g the <code>Graphics</code> object |
|
* |
|
* @see JComponent#paint |
|
* @see JComponent#setBorder |
|
*/ |
|
protected void paintBorder(Graphics g) { |
|
if (isBorderPainted()) { |
|
super.paintBorder(g); |
|
} |
|
} |
|
/** |
|
* Returns the margin, in pixels, between the popup menu's border and |
|
* its containers. |
|
* |
|
* @return an <code>Insets</code> object containing the margin values. |
|
*/ |
|
public Insets getMargin() { |
|
if(margin == null) { |
|
return new Insets(0,0,0,0); |
|
} else { |
|
return margin; |
|
} |
|
} |
|
/** |
|
* Examines the list of menu items to determine whether |
|
* <code>popup</code> is a popup menu. |
|
* |
|
* @param popup a <code>JPopupMenu</code> |
|
* @return true if <code>popup</code> |
|
*/ |
|
boolean isSubPopupMenu(JPopupMenu popup) { |
|
int ncomponents = this.getComponentCount(); |
|
Component[] component = this.getComponents(); |
|
for (int i = 0 ; i < ncomponents ; i++) { |
|
Component comp = component[i]; |
|
if (comp instanceof JMenu) { |
|
JMenu menu = (JMenu)comp; |
|
JPopupMenu subPopup = menu.getPopupMenu(); |
|
if (subPopup == popup) |
|
return true; |
|
if (subPopup.isSubPopupMenu(popup)) |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
private static Frame getFrame(Component c) { |
|
Component w = c; |
|
while(!(w instanceof Frame) && (w!=null)) { |
|
w = w.getParent(); |
|
} |
|
return (Frame)w; |
|
} |
|
/** |
|
* Returns a string representation of this <code>JPopupMenu</code>. |
|
* This method |
|
* is intended to be used only for debugging purposes, and the |
|
* content and format of the returned string may vary between |
|
* implementations. The returned string may be empty but may not |
|
* be <code>null</code>. |
|
* |
|
* @return a string representation of this <code>JPopupMenu</code>. |
|
*/ |
|
protected String paramString() { |
|
String labelString = (label != null ? |
|
label : ""); |
|
String paintBorderString = (paintBorder ? |
|
"true" : "false"); |
|
String marginString = (margin != null ? |
|
margin.toString() : ""); |
|
String lightWeightPopupEnabledString = (isLightWeightPopupEnabled() ? |
|
"true" : "false"); |
|
return super.paramString() + |
|
",desiredLocationX=" + desiredLocationX + |
|
",desiredLocationY=" + desiredLocationY + |
|
",label=" + labelString + |
|
",lightWeightPopupEnabled=" + lightWeightPopupEnabledString + |
|
",margin=" + marginString + |
|
",paintBorder=" + paintBorderString; |
|
} |
|
///////////////// |
|
// Accessibility support |
|
//////////////// |
|
/** |
|
* Gets the AccessibleContext associated with this JPopupMenu. |
|
* For JPopupMenus, the AccessibleContext takes the form of an |
|
* AccessibleJPopupMenu. |
|
* A new AccessibleJPopupMenu instance is created if necessary. |
|
* |
|
* @return an AccessibleJPopupMenu that serves as the |
|
* AccessibleContext of this JPopupMenu |
|
*/ |
|
public AccessibleContext getAccessibleContext() { |
|
if (accessibleContext == null) { |
|
accessibleContext = new AccessibleJPopupMenu(); |
|
} |
|
return accessibleContext; |
|
} |
|
/** |
|
* This class implements accessibility support for the |
|
* <code>JPopupMenu</code> class. It provides an implementation of the |
|
* Java Accessibility API appropriate to popup menu user-interface |
|
* elements. |
|
*/ |
|
@SuppressWarnings("serial") |
|
protected class AccessibleJPopupMenu extends AccessibleJComponent |
|
implements PropertyChangeListener { |
|
/** |
|
* AccessibleJPopupMenu constructor |
|
* |
|
* @since 1.5 |
|
*/ |
|
protected AccessibleJPopupMenu() { |
|
JPopupMenu.this.addPropertyChangeListener(this); |
|
} |
|
/** |
|
* Get the role of this object. |
|
* |
|
* @return an instance of AccessibleRole describing the role of |
|
* the object |
|
*/ |
|
public AccessibleRole getAccessibleRole() { |
|
return AccessibleRole.POPUP_MENU; |
|
} |
|
/** |
|
* This method gets called when a bound property is changed. |
|
* @param e A <code>PropertyChangeEvent</code> object describing |
|
* the event source and the property that has changed. Must not be null. |
|
* |
|
* @throws NullPointerException if the parameter is null. |
|
* @since 1.5 |
|
*/ |
|
public void propertyChange(PropertyChangeEvent e) { |
|
String propertyName = e.getPropertyName(); |
|
if (propertyName == "visible") { |
|
if (e.getOldValue() == Boolean.FALSE && |
|
e.getNewValue() == Boolean.TRUE) { |
|
handlePopupIsVisibleEvent(true); |
|
} else if (e.getOldValue() == Boolean.TRUE && |
|
e.getNewValue() == Boolean.FALSE) { |
|
handlePopupIsVisibleEvent(false); |
|
} |
|
} |
|
} |
|
/* |
|
* Handles popup "visible" PropertyChangeEvent |
|
*/ |
|
private void handlePopupIsVisibleEvent(boolean visible) { |
|
if (visible) { |
|
// notify listeners that the popup became visible |
|
firePropertyChange(ACCESSIBLE_STATE_PROPERTY, |
|
null, AccessibleState.VISIBLE); |
|
// notify listeners that a popup list item is selected |
|
fireActiveDescendant(); |
|
} else { |
|
// notify listeners that the popup became hidden |
|
firePropertyChange(ACCESSIBLE_STATE_PROPERTY, |
|
AccessibleState.VISIBLE, null); |
|
} |
|
} |
|
/* |
|
* Fires AccessibleActiveDescendant PropertyChangeEvent to notify listeners |
|
* on the popup menu invoker that a popup list item has been selected |
|
*/ |
|
private void fireActiveDescendant() { |
|
if (JPopupMenu.this instanceof BasicComboPopup) { |
|
// get the popup list |
|
JList<?> popupList = ((BasicComboPopup)JPopupMenu.this).getList(); |
|
if (popupList == null) { |
|
return; |
|
} |
|
// get the first selected item |
|
AccessibleContext ac = popupList.getAccessibleContext(); |
|
AccessibleSelection selection = ac.getAccessibleSelection(); |
|
if (selection == null) { |
|
return; |
|
} |
|
Accessible a = selection.getAccessibleSelection(0); |
|
if (a == null) { |
|
return; |
|
} |
|
AccessibleContext selectedItem = a.getAccessibleContext(); |
|
// fire the event with the popup invoker as the source. |
|
if (selectedItem != null && invoker != null) { |
|
AccessibleContext invokerContext = invoker.getAccessibleContext(); |
|
if (invokerContext != null) { |
|
// Check invokerContext because Component.getAccessibleContext |
|
// returns null. Classes that extend Component are responsible |
|
// for returning a non-null AccessibleContext. |
|
invokerContext.firePropertyChange( |
|
ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY, |
|
null, selectedItem); |
|
} |
|
} |
|
} |
|
} |
|
} // inner class AccessibleJPopupMenu |
|
//////////// |
|
// Serialization support. |
|
//////////// |
|
private void writeObject(ObjectOutputStream s) throws IOException { |
|
Vector<Object> values = new Vector<Object>(); |
|
s.defaultWriteObject(); |
|
// Save the invoker, if its Serializable. |
|
if(invoker != null && invoker instanceof Serializable) { |
|
values.addElement("invoker"); |
|
values.addElement(invoker); |
|
} |
|
// Save the popup, if its Serializable. |
|
if(popup != null && popup instanceof Serializable) { |
|
values.addElement("popup"); |
|
values.addElement(popup); |
|
} |
|
s.writeObject(values); |
|
if (getUIClassID().equals(uiClassID)) { |
|
byte count = JComponent.getWriteObjCounter(this); |
|
JComponent.setWriteObjCounter(this, --count); |
|
if (count == 0 && ui != null) { |
|
ui.installUI(this); |
|
} |
|
} |
|
} |
|
// implements javax.swing.MenuElement |
|
private void readObject(ObjectInputStream s) |
|
throws IOException, ClassNotFoundException { |
|
s.defaultReadObject(); |
|
Vector<?> values = (Vector)s.readObject(); |
|
int indexCounter = 0; |
|
int maxCounter = values.size(); |
|
if(indexCounter < maxCounter && values.elementAt(indexCounter). |
|
equals("invoker")) { |
|
invoker = (Component)values.elementAt(++indexCounter); |
|
indexCounter++; |
|
} |
|
if(indexCounter < maxCounter && values.elementAt(indexCounter). |
|
equals("popup")) { |
|
popup = (Popup)values.elementAt(++indexCounter); |
|
indexCounter++; |
|
} |
|
} |
|
/** |
|
* This method is required to conform to the |
|
* <code>MenuElement</code> interface, but it not implemented. |
|
* @see MenuElement#processMouseEvent(MouseEvent, MenuElement[], MenuSelectionManager) |
|
*/ |
|
public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {} |
|
/** |
|
* Processes a key event forwarded from the |
|
* <code>MenuSelectionManager</code> and changes the menu selection, |
|
* if necessary, by using <code>MenuSelectionManager</code>'s API. |
|
* <p> |
|
* Note: you do not have to forward the event to sub-components. |
|
* This is done automatically by the <code>MenuSelectionManager</code>. |
|
* |
|
* @param e a <code>KeyEvent</code> |
|
* @param path the <code>MenuElement</code> path array |
|
* @param manager the <code>MenuSelectionManager</code> |
|
*/ |
|
public void processKeyEvent(KeyEvent e, MenuElement path[], |
|
MenuSelectionManager manager) { |
|
MenuKeyEvent mke = new MenuKeyEvent(e.getComponent(), e.getID(), |
|
e.getWhen(), e.getModifiers(), |
|
e.getKeyCode(), e.getKeyChar(), |
|
path, manager); |
|
processMenuKeyEvent(mke); |
|
if (mke.isConsumed()) { |
|
e.consume(); |
|
} |
|
} |
|
/** |
|
* Handles a keystroke in a menu. |
|
* |
|
* @param e a <code>MenuKeyEvent</code> object |
|
* @since 1.5 |
|
*/ |
|
private void processMenuKeyEvent(MenuKeyEvent e) { |
|
switch (e.getID()) { |
|
case KeyEvent.KEY_PRESSED: |
|
fireMenuKeyPressed(e); break; |
|
case KeyEvent.KEY_RELEASED: |
|
fireMenuKeyReleased(e); break; |
|
case KeyEvent.KEY_TYPED: |
|
fireMenuKeyTyped(e); break; |
|
default: |
|
break; |
|
} |
|
} |
|
/** |
|
* Notifies all listeners that have registered interest for |
|
* notification on this event type. |
|
* |
|
* @param event a <code>MenuKeyEvent</code> |
|
* @see EventListenerList |
|
*/ |
|
private void fireMenuKeyPressed(MenuKeyEvent event) { |
|
Object[] listeners = listenerList.getListenerList(); |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==MenuKeyListener.class) { |
|
((MenuKeyListener)listeners[i+1]).menuKeyPressed(event); |
|
} |
|
} |
|
} |
|
/** |
|
* Notifies all listeners that have registered interest for |
|
* notification on this event type. |
|
* |
|
* @param event a <code>MenuKeyEvent</code> |
|
* @see EventListenerList |
|
*/ |
|
private void fireMenuKeyReleased(MenuKeyEvent event) { |
|
Object[] listeners = listenerList.getListenerList(); |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==MenuKeyListener.class) { |
|
((MenuKeyListener)listeners[i+1]).menuKeyReleased(event); |
|
} |
|
} |
|
} |
|
/** |
|
* Notifies all listeners that have registered interest for |
|
* notification on this event type. |
|
* |
|
* @param event a <code>MenuKeyEvent</code> |
|
* @see EventListenerList |
|
*/ |
|
private void fireMenuKeyTyped(MenuKeyEvent event) { |
|
Object[] listeners = listenerList.getListenerList(); |
|
for (int i = listeners.length-2; i>=0; i-=2) { |
|
if (listeners[i]==MenuKeyListener.class) { |
|
((MenuKeyListener)listeners[i+1]).menuKeyTyped(event); |
|
} |
|
} |
|
} |
|
/** |
|
* Messaged when the menubar selection changes to activate or |
|
* deactivate this menu. This implements the |
|
* <code>javax.swing.MenuElement</code> interface. |
|
* Overrides <code>MenuElement.menuSelectionChanged</code>. |
|
* |
|
* @param isIncluded true if this menu is active, false if |
|
* it is not |
|
* @see MenuElement#menuSelectionChanged(boolean) |
|
*/ |
|
public void menuSelectionChanged(boolean isIncluded) { |
|
if (DEBUG) { |
|
System.out.println("In JPopupMenu.menuSelectionChanged " + isIncluded); |
|
} |
|
if(invoker instanceof JMenu) { |
|
JMenu m = (JMenu) invoker; |
|
if(isIncluded) |
|
m.setPopupMenuVisible(true); |
|
else |
|
m.setPopupMenuVisible(false); |
|
} |
|
if (isPopupMenu() && !isIncluded) |
|
setVisible(false); |
|
} |
|
/** |
|
* Returns an array of <code>MenuElement</code>s containing the submenu |
|
* for this menu component. It will only return items conforming to |
|
* the <code>JMenuElement</code> interface. |
|
* If popup menu is <code>null</code> returns |
|
* an empty array. This method is required to conform to the |
|
* <code>MenuElement</code> interface. |
|
* |
|
* @return an array of <code>MenuElement</code> objects |
|
* @see MenuElement#getSubElements |
|
*/ |
|
public MenuElement[] getSubElements() { |
|
MenuElement result[]; |
|
Vector<MenuElement> tmp = new Vector<MenuElement>(); |
|
int c = getComponentCount(); |
|
int i; |
|
Component m; |
|
for(i=0 ; i < c ; i++) { |
|
m = getComponent(i); |
|
if(m instanceof MenuElement) |
|
tmp.addElement((MenuElement) m); |
|
} |
|
result = new MenuElement[tmp.size()]; |
|
for(i=0,c=tmp.size() ; i < c ; i++) |
|
result[i] = tmp.elementAt(i); |
|
return result; |
|
} |
|
/** |
|
* Returns this <code>JPopupMenu</code> component. |
|
* @return this <code>JPopupMenu</code> object |
|
* @see MenuElement#getComponent |
|
*/ |
|
public Component getComponent() { |
|
return this; |
|
} |
|
/** |
|
* A popup menu-specific separator. |
|
*/ |
|
@SuppressWarnings("serial") |
|
static public class Separator extends JSeparator |
|
{ |
|
public Separator( ) |
|
{ |
|
super( JSeparator.HORIZONTAL ); |
|
} |
|
/** |
|
* Returns the name of the L&F class that renders this component. |
|
* |
|
* @return the string "PopupMenuSeparatorUI" |
|
* @see JComponent#getUIClassID |
|
* @see UIDefaults#getUI |
|
*/ |
|
public String getUIClassID() |
|
{ |
|
return "PopupMenuSeparatorUI"; |
|
} |
|
} |
|
/** |
|
* Returns true if the <code>MouseEvent</code> is considered a popup trigger |
|
* by the <code>JPopupMenu</code>'s currently installed UI. |
|
* |
|
* @return true if the mouse event is a popup trigger |
|
* @since 1.3 |
|
*/ |
|
public boolean isPopupTrigger(MouseEvent e) { |
|
return getUI().isPopupTrigger(e); |
|
} |
|
} |