5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package javax.swing;
27
28 import java.awt.AWTEvent;
29 import java.awt.Component;
30 import java.awt.ComponentOrientation;
31 import java.awt.Container;
32 import java.awt.Dimension;
33 import java.awt.Frame;
34 import java.awt.Graphics;
35 import java.awt.GraphicsConfiguration;
36 import java.awt.GraphicsDevice;
37 import java.awt.GraphicsEnvironment;
38 import java.awt.Insets;
39 import java.awt.Point;
40 import java.awt.Polygon;
41 import java.awt.Rectangle;
42 import java.awt.Toolkit;
43 import java.awt.event.*;
44 import java.beans.*;
45
46 import java.util.*;
47
48 import java.io.Serializable;
49 import java.io.ObjectOutputStream;
50 import java.io.ObjectInputStream;
51 import java.io.IOException;
52
53 import javax.swing.event.*;
54 import javax.swing.plaf.*;
55 import javax.swing.plaf.basic.*;
56 import javax.accessibility.*;
57
58 import java.lang.ref.WeakReference;
59
60 /**
61 * An implementation of a menu -- a popup window containing
62 * <code>JMenuItem</code>s that
63 * is displayed when the user selects an item on the <code>JMenuBar</code>.
64 * In addition to <code>JMenuItem</code>s, a <code>JMenu</code> can
65 * also contain <code>JSeparator</code>s.
66 * <p>
67 * In essence, a menu is a button with an associated <code>JPopupMenu</code>.
68 * When the "button" is pressed, the <code>JPopupMenu</code> appears. If the
69 * "button" is on the <code>JMenuBar</code>, the menu is a top-level window.
70 * If the "button" is another menu item, then the <code>JPopupMenu</code> is
71 * "pull-right" menu.
72 * <p>
73 * Menus can be configured, and to some degree controlled, by
74 * <code><a href="Action.html">Action</a></code>s. Using an
75 * <code>Action</code> with a menu has many benefits beyond directly
76 * configuring a menu. Refer to <a href="Action.html#buttonActions">
77 * Swing Components Supporting <code>Action</code></a> for more
78 * details, and you can find more information in <a
79 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
80 * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
81 * <p>
82 * For information and examples of using menus see
83 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
84 * a section in <em>The Java Tutorial.</em>
85 * <p>
86 * <strong>Warning:</strong> Swing is not thread safe. For more
87 * information see <a
88 * href="package-summary.html#threading">Swing's Threading
89 * Policy</a>.
90 * <p>
91 * <strong>Warning:</strong>
92 * Serialized objects of this class will not be compatible with
93 * future Swing releases. The current serialization support is
94 * appropriate for short term storage or RMI between applications running
95 * the same version of Swing. As of 1.4, support for long term storage
96 * of all JavaBeans™
97 * has been added to the <code>java.beans</code> package.
98 * Please see {@link java.beans.XMLEncoder}.
99 *
100 * @beaninfo
101 * attribute: isContainer true
102 * description: A popup window containing menu items displayed in a menu bar.
103 *
104 * @author Georges Saab
105 * @author David Karlton
106 * @author Arnaud Weber
107 * @see JMenuItem
108 * @see JSeparator
109 * @see JMenuBar
110 * @see JPopupMenu
111 * @since 1.2
112 */
113 @SuppressWarnings("serial")
114 public class JMenu extends JMenuItem implements Accessible,MenuElement
115 {
116 /**
117 * @see #getUIClassID
118 * @see #readObject
119 */
120 private static final String uiClassID = "MenuUI";
121
122 /*
123 * The popup menu portion of the menu.
124 */
125 private JPopupMenu popupMenu;
126
127 /*
128 * The button's model listeners. Default is <code>null</code>.
129 */
130 private ChangeListener menuChangeListener = null;
131
132 /*
215 * @see JComponent#updateUI
216 */
217 public void updateUI() {
218 setUI((MenuItemUI)UIManager.getUI(this));
219
220 if ( popupMenu != null )
221 {
222 popupMenu.setUI((PopupMenuUI)UIManager.getUI(popupMenu));
223 }
224
225 }
226
227
228 /**
229 * Returns the name of the L&F class that renders this component.
230 *
231 * @return the string "MenuUI"
232 * @see JComponent#getUIClassID
233 * @see UIDefaults#getUI
234 */
235 public String getUIClassID() {
236 return uiClassID;
237 }
238
239 // public void repaint(long tm, int x, int y, int width, int height) {
240 // Thread.currentThread().dumpStack();
241 // super.repaint(tm,x,y,width,height);
242 // }
243
244 /**
245 * Sets the data model for the "menu button" -- the label
246 * that the user clicks to open or close the menu.
247 *
248 * @param newModel the <code>ButtonModel</code>
249 * @see #getModel
250 * @beaninfo
251 * description: The menu's model
252 * bound: true
253 * expert: true
254 * hidden: true
255 */
256 public void setModel(ButtonModel newModel) {
257 ButtonModel oldModel = getModel();
258
259 super.setModel(newModel);
260
261 if (oldModel != null && menuChangeListener != null) {
262 oldModel.removeChangeListener(menuChangeListener);
263 menuChangeListener = null;
264 }
265
266 model = newModel;
267
268 if (newModel != null) {
269 menuChangeListener = createMenuChangeListener();
270 newModel.addChangeListener(menuChangeListener);
271 }
272 }
273
274 /**
275 * Returns true if the menu is currently selected (highlighted).
276 *
277 * @return true if the menu is selected, else false
278 */
279 public boolean isSelected() {
280 return getModel().isSelected();
281 }
282
283 /**
284 * Sets the selection status of the menu.
285 *
286 * @param b true to select (highlight) the menu; false to de-select
287 * the menu
288 * @beaninfo
289 * description: When the menu is selected, its popup child is shown.
290 * expert: true
291 * hidden: true
292 */
293 public void setSelected(boolean b) {
294 ButtonModel model = getModel();
295 boolean oldValue = model.isSelected();
296
297 // TIGER - 4840653
298 // Removed code which fired an AccessibleState.SELECTED
299 // PropertyChangeEvent since this resulted in two
300 // identical events being fired since
301 // AbstractButton.fireItemStateChanged also fires the
302 // same event. This caused screen readers to speak the
303 // name of the item twice.
304
305 if (b != model.isSelected()) {
306 getModel().setSelected(b);
307 }
308 }
309
310 /**
311 * Returns true if the menu's popup window is visible.
312 *
313 * @return true if the menu is visible, else false
314 */
315 public boolean isPopupMenuVisible() {
316 ensurePopupMenuCreated();
317 return popupMenu.isVisible();
318 }
319
320 /**
321 * Sets the visibility of the menu's popup. If the menu is
322 * not enabled, this method will have no effect.
323 *
324 * @param b a boolean value -- true to make the menu visible,
325 * false to hide it
326 * @beaninfo
327 * description: The popup menu's visibility
328 * expert: true
329 * hidden: true
330 */
331 public void setPopupMenuVisible(boolean b) {
332 if (DEBUG) {
333 System.out.println("in JMenu.setPopupMenuVisible " + b);
334 // Thread.dumpStack();
335 }
336
337 boolean isVisible = isPopupMenuVisible();
338 if (b != isVisible && (isEnabled() || !b)) {
339 ensurePopupMenuCreated();
340 if ((b==true) && isShowing()) {
341 // Set location of popupMenu (pulldown or pullright)
342 Point p = getCustomMenuLocation();
343 if (p == null) {
344 p = getPopupMenuOrigin();
345 }
346 getPopupMenu().show(this, p.x, p.y);
347 } else {
348 getPopupMenu().setVisible(false);
349 }
350 }
499 * to manage the idiosyncrasies of the various UI implementations.
500 *
501 *
502 * @return the <code>delay</code> property
503 */
504 public int getDelay() {
505 return delay;
506 }
507
508 /**
509 * Sets the suggested delay before the menu's <code>PopupMenu</code>
510 * is popped up or down. Each look and feel (L&F) may determine
511 * it's own policy for observing the delay property. In most cases,
512 * the delay is not observed for top level menus or while dragging.
513 * This method is a property of the look and feel code and is used
514 * to manage the idiosyncrasies of the various UI implementations.
515 *
516 * @param d the number of milliseconds to delay
517 * @exception IllegalArgumentException if <code>d</code>
518 * is less than 0
519 * @beaninfo
520 * description: The delay between menu selection and making the popup menu visible
521 * expert: true
522 */
523 public void setDelay(int d) {
524 if (d < 0)
525 throw new IllegalArgumentException("Delay must be a positive integer");
526
527 delay = d;
528 }
529
530 /**
531 * The window-closing listener for the popup.
532 *
533 * @see WinListener
534 */
535 protected WinListener popupListener;
536
537 private void ensurePopupMenuCreated() {
538 if (popupMenu == null) {
539 final JMenu thisMenu = this;
540 this.popupMenu = new JPopupMenu();
541 popupMenu.setInvoker(this);
542 popupListener = createWinListener(popupMenu);
770 throw new IllegalArgumentException("index less than zero.");
771 }
772
773 Component c = getMenuComponent(pos);
774 if (c instanceof JMenuItem) {
775 JMenuItem mi = (JMenuItem) c;
776 return mi;
777 }
778
779 // 4173633
780 return null;
781 }
782
783 /**
784 * Returns the number of items on the menu, including separators.
785 * This method is included for AWT compatibility.
786 *
787 * @return an integer equal to the number of items on the menu
788 * @see #getMenuComponentCount
789 */
790 public int getItemCount() {
791 return getMenuComponentCount();
792 }
793
794 /**
795 * Returns true if the menu can be torn off. This method is not
796 * yet implemented.
797 *
798 * @return true if the menu can be torn off, else false
799 * @exception Error if invoked -- this method is not yet implemented
800 */
801 public boolean isTearOff() {
802 throw new Error("boolean isTearOff() {} not yet implemented");
803 }
804
805 /**
806 * Removes the specified menu item from this menu. If there is no
807 * popup menu, this method will have no effect.
808 *
809 * @param item the <code>JMenuItem</code> to be removed from the menu
810 */
811 public void remove(JMenuItem item) {
812 if (popupMenu != null)
813 popupMenu.remove(item);
814 }
815
816 /**
817 * Removes the menu item at the specified index from this menu.
818 *
819 * @param pos the position of the item to be removed
820 * @exception IllegalArgumentException if the value of
838 * @param c the component to be removed
839 */
840 public void remove(Component c) {
841 if (popupMenu != null)
842 popupMenu.remove(c);
843 }
844
845 /**
846 * Removes all menu items from this menu.
847 */
848 public void removeAll() {
849 if (popupMenu != null)
850 popupMenu.removeAll();
851 }
852
853 /**
854 * Returns the number of components on the menu.
855 *
856 * @return an integer containing the number of components on the menu
857 */
858 public int getMenuComponentCount() {
859 int componentCount = 0;
860 if (popupMenu != null)
861 componentCount = popupMenu.getComponentCount();
862 return componentCount;
863 }
864
865 /**
866 * Returns the component at position <code>n</code>.
867 *
868 * @param n the position of the component to be returned
869 * @return the component requested, or <code>null</code>
870 * if there is no popup menu
871 *
872 */
873 public Component getMenuComponent(int n) {
874 if (popupMenu != null)
875 return popupMenu.getComponent(n);
876
877 return null;
878 }
879
880 /**
881 * Returns an array of <code>Component</code>s of the menu's
882 * subcomponents. Note that this returns all <code>Component</code>s
883 * in the popup menu, including separators.
884 *
885 * @return an array of <code>Component</code>s or an empty array
886 * if there is no popup menu
887 */
888 public Component[] getMenuComponents() {
889 if (popupMenu != null)
890 return popupMenu.getComponents();
891
892 return new Component[0];
893 }
894
895 /**
896 * Returns true if the menu is a 'top-level menu', that is, if it is
897 * the direct child of a menubar.
898 *
899 * @return true if the menu is activated from the menu bar;
900 * false if the menu is activated from a menu item
901 * on another menu
902 */
903 public boolean isTopLevelMenu() {
904 return getParent() instanceof JMenuBar;
905
906 }
907
908 /**
909 * Returns true if the specified component exists in the
910 * submenu hierarchy.
911 *
912 * @param c the <code>Component</code> to be tested
913 * @return true if the <code>Component</code> exists, false otherwise
914 */
915 public boolean isMenuComponent(Component c) {
916 // Are we in the MenuItem part of the menu
917 if (c == this)
918 return true;
919 // Are we in the PopupMenu?
920 if (c instanceof JPopupMenu) {
921 JPopupMenu comp = (JPopupMenu) c;
922 if (comp == this.getPopupMenu())
967 int newX;
968 int newY;
969
970 if (getParent() instanceof JPopupMenu) {
971 newX = x - getSize().width;
972 newY = y;
973 } else {
974 newX = x;
975 newY = y - getSize().height;
976 }
977
978 return new Point(newX, newY);
979 }
980
981 /**
982 * Returns the popupmenu associated with this menu. If there is
983 * no popupmenu, it will create one.
984 *
985 * @return the {@code JPopupMenu} associated with this menu
986 */
987 public JPopupMenu getPopupMenu() {
988 ensurePopupMenuCreated();
989 return popupMenu;
990 }
991
992 /**
993 * Adds a listener for menu events.
994 *
995 * @param l the listener to be added
996 */
997 public void addMenuListener(MenuListener l) {
998 listenerList.add(MenuListener.class, l);
999 }
1000
1001 /**
1002 * Removes a listener for menu events.
1003 *
1004 * @param l the listener to be removed
1005 */
1006 public void removeMenuListener(MenuListener l) {
1007 listenerList.remove(MenuListener.class, l);
1008 }
1009
1010 /**
1011 * Returns an array of all the <code>MenuListener</code>s added
1012 * to this JMenu with addMenuListener().
1013 *
1014 * @return all of the <code>MenuListener</code>s added or an empty
1015 * array if no listeners have been added
1016 * @since 1.4
1017 */
1018 public MenuListener[] getMenuListeners() {
1019 return listenerList.getListeners(MenuListener.class);
1020 }
1021
1022 /**
1023 * Notifies all listeners that have registered interest for
1024 * notification on this event type. The event instance
1025 * is created lazily.
1026 *
1027 * @exception Error if there is a <code>null</code> listener
1028 * @see EventListenerList
1029 */
1030 protected void fireMenuSelected() {
1031 if (DEBUG) {
1032 System.out.println("In JMenu.fireMenuSelected");
1033 }
1034 // Guaranteed to return a non-null array
1035 Object[] listeners = listenerList.getListenerList();
1036 // Process the listeners last to first, notifying
1037 // those that are interested in this event
1190 * @param isIncluded true if this menu is active, false if
1191 * it is not
1192 */
1193 public void menuSelectionChanged(boolean isIncluded) {
1194 if (DEBUG) {
1195 System.out.println("In JMenu.menuSelectionChanged to " + isIncluded);
1196 }
1197 setSelected(isIncluded);
1198 }
1199
1200 /**
1201 * Returns an array of <code>MenuElement</code>s containing the submenu
1202 * for this menu component. If popup menu is <code>null</code> returns
1203 * an empty array. This method is required to conform to the
1204 * <code>MenuElement</code> interface. Note that since
1205 * <code>JSeparator</code>s do not conform to the <code>MenuElement</code>
1206 * interface, this array will only contain <code>JMenuItem</code>s.
1207 *
1208 * @return an array of <code>MenuElement</code> objects
1209 */
1210 public MenuElement[] getSubElements() {
1211 if(popupMenu == null)
1212 return new MenuElement[0];
1213 else {
1214 MenuElement result[] = new MenuElement[1];
1215 result[0] = popupMenu;
1216 return result;
1217 }
1218 }
1219
1220
1221 // implements javax.swing.MenuElement
1222 /**
1223 * Returns the <code>java.awt.Component</code> used to
1224 * paint this <code>MenuElement</code>.
1225 * The returned component is used to convert events and detect if
1226 * an event is inside a menu component.
1227 */
1228 public Component getComponent() {
1229 return this;
1252 }
1253 popupMenu.setComponentOrientation(o);
1254 }
1255 }
1256
1257 public void setComponentOrientation(ComponentOrientation o) {
1258 super.setComponentOrientation(o);
1259 if ( popupMenu != null ) {
1260 popupMenu.setComponentOrientation(o);
1261 }
1262 }
1263
1264 /**
1265 * <code>setAccelerator</code> is not defined for <code>JMenu</code>.
1266 * Use <code>setMnemonic</code> instead.
1267 * @param keyStroke the keystroke combination which will invoke
1268 * the <code>JMenuItem</code>'s actionlisteners
1269 * without navigating the menu hierarchy
1270 * @exception Error if invoked -- this method is not defined for JMenu.
1271 * Use <code>setMnemonic</code> instead
1272 *
1273 * @beaninfo
1274 * description: The keystroke combination which will invoke the JMenuItem's
1275 * actionlisteners without navigating the menu hierarchy
1276 * hidden: true
1277 */
1278 public void setAccelerator(KeyStroke keyStroke) {
1279 throw new Error("setAccelerator() is not defined for JMenu. Use setMnemonic() instead.");
1280 }
1281
1282 /**
1283 * Processes key stroke events such as mnemonics and accelerators.
1284 *
1285 * @param evt the key event to be processed
1286 */
1287 protected void processKeyEvent(KeyEvent evt) {
1288 MenuSelectionManager.defaultManager().processKeyEvent(evt);
1289 if (evt.isConsumed())
1290 return;
1291
1292 super.processKeyEvent(evt);
1293 }
1294
1295 /**
1296 * Programmatically performs a "click". This overrides the method
1363 * @return a string representation of this JMenu.
1364 */
1365 protected String paramString() {
1366 return super.paramString();
1367 }
1368
1369
1370 /////////////////
1371 // Accessibility support
1372 ////////////////
1373
1374 /**
1375 * Gets the AccessibleContext associated with this JMenu.
1376 * For JMenus, the AccessibleContext takes the form of an
1377 * AccessibleJMenu.
1378 * A new AccessibleJMenu instance is created if necessary.
1379 *
1380 * @return an AccessibleJMenu that serves as the
1381 * AccessibleContext of this JMenu
1382 */
1383 public AccessibleContext getAccessibleContext() {
1384 if (accessibleContext == null) {
1385 accessibleContext = new AccessibleJMenu();
1386 }
1387 return accessibleContext;
1388 }
1389
1390 /**
1391 * This class implements accessibility support for the
1392 * <code>JMenu</code> class. It provides an implementation of the
1393 * Java Accessibility API appropriate to menu user-interface elements.
1394 * <p>
1395 * <strong>Warning:</strong>
1396 * Serialized objects of this class will not be compatible with
1397 * future Swing releases. The current serialization support is
1398 * appropriate for short term storage or RMI between applications running
1399 * the same version of Swing. As of 1.4, support for long term storage
1400 * of all JavaBeans™
1401 * has been added to the <code>java.beans</code> package.
1402 * Please see {@link java.beans.XMLEncoder}.
|
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 package javax.swing;
26
27 import java.awt.Component;
28 import java.awt.ComponentOrientation;
29 import java.awt.Container;
30 import java.awt.Dimension;
31 import java.awt.GraphicsConfiguration;
32 import java.awt.GraphicsDevice;
33 import java.awt.GraphicsEnvironment;
34 import java.awt.Insets;
35 import java.awt.Point;
36 import java.awt.Rectangle;
37 import java.awt.Toolkit;
38 import java.awt.event.*;
39 import java.beans.JavaBean;
40 import java.beans.BeanProperty;
41 import java.beans.PropertyChangeListener;
42
43 import java.util.*;
44
45 import java.io.Serializable;
46 import java.io.ObjectOutputStream;
47 import java.io.IOException;
48
49 import javax.swing.event.*;
50 import javax.swing.plaf.*;
51 import javax.accessibility.*;
52
53 /**
54 * An implementation of a menu -- a popup window containing
55 * <code>JMenuItem</code>s that
56 * is displayed when the user selects an item on the <code>JMenuBar</code>.
57 * In addition to <code>JMenuItem</code>s, a <code>JMenu</code> can
58 * also contain <code>JSeparator</code>s.
59 * <p>
60 * In essence, a menu is a button with an associated <code>JPopupMenu</code>.
61 * When the "button" is pressed, the <code>JPopupMenu</code> appears. If the
62 * "button" is on the <code>JMenuBar</code>, the menu is a top-level window.
63 * If the "button" is another menu item, then the <code>JPopupMenu</code> is
64 * "pull-right" menu.
65 * <p>
66 * Menus can be configured, and to some degree controlled, by
67 * <code><a href="Action.html">Action</a></code>s. Using an
68 * <code>Action</code> with a menu has many benefits beyond directly
69 * configuring a menu. Refer to <a href="Action.html#buttonActions">
70 * Swing Components Supporting <code>Action</code></a> for more
71 * details, and you can find more information in <a
72 * href="http://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
73 * to Use Actions</a>, a section in <em>The Java Tutorial</em>.
74 * <p>
75 * For information and examples of using menus see
76 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
77 * a section in <em>The Java Tutorial.</em>
78 * <p>
79 * <strong>Warning:</strong> Swing is not thread safe. For more
80 * information see <a
81 * href="package-summary.html#threading">Swing's Threading
82 * Policy</a>.
83 * <p>
84 * <strong>Warning:</strong>
85 * Serialized objects of this class will not be compatible with
86 * future Swing releases. The current serialization support is
87 * appropriate for short term storage or RMI between applications running
88 * the same version of Swing. As of 1.4, support for long term storage
89 * of all JavaBeans™
90 * has been added to the <code>java.beans</code> package.
91 * Please see {@link java.beans.XMLEncoder}.
92 *
93 * @author Georges Saab
94 * @author David Karlton
95 * @author Arnaud Weber
96 * @see JMenuItem
97 * @see JSeparator
98 * @see JMenuBar
99 * @see JPopupMenu
100 * @since 1.2
101 */
102 @JavaBean(description = "A popup window containing menu items displayed in a menu bar.")
103 @SwingContainer
104 @SuppressWarnings("serial")
105 public class JMenu extends JMenuItem implements Accessible,MenuElement
106 {
107 /**
108 * @see #getUIClassID
109 * @see #readObject
110 */
111 private static final String uiClassID = "MenuUI";
112
113 /*
114 * The popup menu portion of the menu.
115 */
116 private JPopupMenu popupMenu;
117
118 /*
119 * The button's model listeners. Default is <code>null</code>.
120 */
121 private ChangeListener menuChangeListener = null;
122
123 /*
206 * @see JComponent#updateUI
207 */
208 public void updateUI() {
209 setUI((MenuItemUI)UIManager.getUI(this));
210
211 if ( popupMenu != null )
212 {
213 popupMenu.setUI((PopupMenuUI)UIManager.getUI(popupMenu));
214 }
215
216 }
217
218
219 /**
220 * Returns the name of the L&F class that renders this component.
221 *
222 * @return the string "MenuUI"
223 * @see JComponent#getUIClassID
224 * @see UIDefaults#getUI
225 */
226 @BeanProperty(bound = false)
227 public String getUIClassID() {
228 return uiClassID;
229 }
230
231 // public void repaint(long tm, int x, int y, int width, int height) {
232 // Thread.currentThread().dumpStack();
233 // super.repaint(tm,x,y,width,height);
234 // }
235
236 /**
237 * Sets the data model for the "menu button" -- the label
238 * that the user clicks to open or close the menu.
239 *
240 * @param newModel the <code>ButtonModel</code>
241 * @see #getModel
242 */
243 public void setModel(ButtonModel newModel) {
244 ButtonModel oldModel = getModel();
245
246 super.setModel(newModel);
247
248 if (oldModel != null && menuChangeListener != null) {
249 oldModel.removeChangeListener(menuChangeListener);
250 menuChangeListener = null;
251 }
252
253 model = newModel;
254
255 if (newModel != null) {
256 menuChangeListener = createMenuChangeListener();
257 newModel.addChangeListener(menuChangeListener);
258 }
259 }
260
261 /**
262 * Returns true if the menu is currently selected (highlighted).
263 *
264 * @return true if the menu is selected, else false
265 */
266 public boolean isSelected() {
267 return getModel().isSelected();
268 }
269
270 /**
271 * Sets the selection status of the menu.
272 *
273 * @param b true to select (highlight) the menu; false to de-select
274 * the menu
275 */
276 @BeanProperty(expert = true, hidden = true, description
277 = "When the menu is selected, its popup child is shown.")
278 public void setSelected(boolean b) {
279 ButtonModel model = getModel();
280 boolean oldValue = model.isSelected();
281
282 // TIGER - 4840653
283 // Removed code which fired an AccessibleState.SELECTED
284 // PropertyChangeEvent since this resulted in two
285 // identical events being fired since
286 // AbstractButton.fireItemStateChanged also fires the
287 // same event. This caused screen readers to speak the
288 // name of the item twice.
289
290 if (b != model.isSelected()) {
291 getModel().setSelected(b);
292 }
293 }
294
295 /**
296 * Returns true if the menu's popup window is visible.
297 *
298 * @return true if the menu is visible, else false
299 */
300 public boolean isPopupMenuVisible() {
301 ensurePopupMenuCreated();
302 return popupMenu.isVisible();
303 }
304
305 /**
306 * Sets the visibility of the menu's popup. If the menu is
307 * not enabled, this method will have no effect.
308 *
309 * @param b a boolean value -- true to make the menu visible,
310 * false to hide it
311 */
312 @BeanProperty(bound = false, expert = true, hidden = true, description
313 = "The popup menu's visibility")
314 public void setPopupMenuVisible(boolean b) {
315 if (DEBUG) {
316 System.out.println("in JMenu.setPopupMenuVisible " + b);
317 // Thread.dumpStack();
318 }
319
320 boolean isVisible = isPopupMenuVisible();
321 if (b != isVisible && (isEnabled() || !b)) {
322 ensurePopupMenuCreated();
323 if ((b==true) && isShowing()) {
324 // Set location of popupMenu (pulldown or pullright)
325 Point p = getCustomMenuLocation();
326 if (p == null) {
327 p = getPopupMenuOrigin();
328 }
329 getPopupMenu().show(this, p.x, p.y);
330 } else {
331 getPopupMenu().setVisible(false);
332 }
333 }
482 * to manage the idiosyncrasies of the various UI implementations.
483 *
484 *
485 * @return the <code>delay</code> property
486 */
487 public int getDelay() {
488 return delay;
489 }
490
491 /**
492 * Sets the suggested delay before the menu's <code>PopupMenu</code>
493 * is popped up or down. Each look and feel (L&F) may determine
494 * it's own policy for observing the delay property. In most cases,
495 * the delay is not observed for top level menus or while dragging.
496 * This method is a property of the look and feel code and is used
497 * to manage the idiosyncrasies of the various UI implementations.
498 *
499 * @param d the number of milliseconds to delay
500 * @exception IllegalArgumentException if <code>d</code>
501 * is less than 0
502 */
503 @BeanProperty(bound = false, expert = true, description
504 = "The delay between menu selection and making the popup menu visible")
505 public void setDelay(int d) {
506 if (d < 0)
507 throw new IllegalArgumentException("Delay must be a positive integer");
508
509 delay = d;
510 }
511
512 /**
513 * The window-closing listener for the popup.
514 *
515 * @see WinListener
516 */
517 protected WinListener popupListener;
518
519 private void ensurePopupMenuCreated() {
520 if (popupMenu == null) {
521 final JMenu thisMenu = this;
522 this.popupMenu = new JPopupMenu();
523 popupMenu.setInvoker(this);
524 popupListener = createWinListener(popupMenu);
752 throw new IllegalArgumentException("index less than zero.");
753 }
754
755 Component c = getMenuComponent(pos);
756 if (c instanceof JMenuItem) {
757 JMenuItem mi = (JMenuItem) c;
758 return mi;
759 }
760
761 // 4173633
762 return null;
763 }
764
765 /**
766 * Returns the number of items on the menu, including separators.
767 * This method is included for AWT compatibility.
768 *
769 * @return an integer equal to the number of items on the menu
770 * @see #getMenuComponentCount
771 */
772 @BeanProperty(bound = false)
773 public int getItemCount() {
774 return getMenuComponentCount();
775 }
776
777 /**
778 * Returns true if the menu can be torn off. This method is not
779 * yet implemented.
780 *
781 * @return true if the menu can be torn off, else false
782 * @exception Error if invoked -- this method is not yet implemented
783 */
784 @BeanProperty(bound = false)
785 public boolean isTearOff() {
786 throw new Error("boolean isTearOff() {} not yet implemented");
787 }
788
789 /**
790 * Removes the specified menu item from this menu. If there is no
791 * popup menu, this method will have no effect.
792 *
793 * @param item the <code>JMenuItem</code> to be removed from the menu
794 */
795 public void remove(JMenuItem item) {
796 if (popupMenu != null)
797 popupMenu.remove(item);
798 }
799
800 /**
801 * Removes the menu item at the specified index from this menu.
802 *
803 * @param pos the position of the item to be removed
804 * @exception IllegalArgumentException if the value of
822 * @param c the component to be removed
823 */
824 public void remove(Component c) {
825 if (popupMenu != null)
826 popupMenu.remove(c);
827 }
828
829 /**
830 * Removes all menu items from this menu.
831 */
832 public void removeAll() {
833 if (popupMenu != null)
834 popupMenu.removeAll();
835 }
836
837 /**
838 * Returns the number of components on the menu.
839 *
840 * @return an integer containing the number of components on the menu
841 */
842 @BeanProperty(bound = false)
843 public int getMenuComponentCount() {
844 int componentCount = 0;
845 if (popupMenu != null)
846 componentCount = popupMenu.getComponentCount();
847 return componentCount;
848 }
849
850 /**
851 * Returns the component at position <code>n</code>.
852 *
853 * @param n the position of the component to be returned
854 * @return the component requested, or <code>null</code>
855 * if there is no popup menu
856 *
857 */
858 public Component getMenuComponent(int n) {
859 if (popupMenu != null)
860 return popupMenu.getComponent(n);
861
862 return null;
863 }
864
865 /**
866 * Returns an array of <code>Component</code>s of the menu's
867 * subcomponents. Note that this returns all <code>Component</code>s
868 * in the popup menu, including separators.
869 *
870 * @return an array of <code>Component</code>s or an empty array
871 * if there is no popup menu
872 */
873 @BeanProperty(bound = false)
874 public Component[] getMenuComponents() {
875 if (popupMenu != null)
876 return popupMenu.getComponents();
877
878 return new Component[0];
879 }
880
881 /**
882 * Returns true if the menu is a 'top-level menu', that is, if it is
883 * the direct child of a menubar.
884 *
885 * @return true if the menu is activated from the menu bar;
886 * false if the menu is activated from a menu item
887 * on another menu
888 */
889 @BeanProperty(bound = false)
890 public boolean isTopLevelMenu() {
891 return getParent() instanceof JMenuBar;
892
893 }
894
895 /**
896 * Returns true if the specified component exists in the
897 * submenu hierarchy.
898 *
899 * @param c the <code>Component</code> to be tested
900 * @return true if the <code>Component</code> exists, false otherwise
901 */
902 public boolean isMenuComponent(Component c) {
903 // Are we in the MenuItem part of the menu
904 if (c == this)
905 return true;
906 // Are we in the PopupMenu?
907 if (c instanceof JPopupMenu) {
908 JPopupMenu comp = (JPopupMenu) c;
909 if (comp == this.getPopupMenu())
954 int newX;
955 int newY;
956
957 if (getParent() instanceof JPopupMenu) {
958 newX = x - getSize().width;
959 newY = y;
960 } else {
961 newX = x;
962 newY = y - getSize().height;
963 }
964
965 return new Point(newX, newY);
966 }
967
968 /**
969 * Returns the popupmenu associated with this menu. If there is
970 * no popupmenu, it will create one.
971 *
972 * @return the {@code JPopupMenu} associated with this menu
973 */
974 @BeanProperty(bound = false)
975 public JPopupMenu getPopupMenu() {
976 ensurePopupMenuCreated();
977 return popupMenu;
978 }
979
980 /**
981 * Adds a listener for menu events.
982 *
983 * @param l the listener to be added
984 */
985 public void addMenuListener(MenuListener l) {
986 listenerList.add(MenuListener.class, l);
987 }
988
989 /**
990 * Removes a listener for menu events.
991 *
992 * @param l the listener to be removed
993 */
994 public void removeMenuListener(MenuListener l) {
995 listenerList.remove(MenuListener.class, l);
996 }
997
998 /**
999 * Returns an array of all the <code>MenuListener</code>s added
1000 * to this JMenu with addMenuListener().
1001 *
1002 * @return all of the <code>MenuListener</code>s added or an empty
1003 * array if no listeners have been added
1004 * @since 1.4
1005 */
1006 @BeanProperty(bound = false)
1007 public MenuListener[] getMenuListeners() {
1008 return listenerList.getListeners(MenuListener.class);
1009 }
1010
1011 /**
1012 * Notifies all listeners that have registered interest for
1013 * notification on this event type. The event instance
1014 * is created lazily.
1015 *
1016 * @exception Error if there is a <code>null</code> listener
1017 * @see EventListenerList
1018 */
1019 protected void fireMenuSelected() {
1020 if (DEBUG) {
1021 System.out.println("In JMenu.fireMenuSelected");
1022 }
1023 // Guaranteed to return a non-null array
1024 Object[] listeners = listenerList.getListenerList();
1025 // Process the listeners last to first, notifying
1026 // those that are interested in this event
1179 * @param isIncluded true if this menu is active, false if
1180 * it is not
1181 */
1182 public void menuSelectionChanged(boolean isIncluded) {
1183 if (DEBUG) {
1184 System.out.println("In JMenu.menuSelectionChanged to " + isIncluded);
1185 }
1186 setSelected(isIncluded);
1187 }
1188
1189 /**
1190 * Returns an array of <code>MenuElement</code>s containing the submenu
1191 * for this menu component. If popup menu is <code>null</code> returns
1192 * an empty array. This method is required to conform to the
1193 * <code>MenuElement</code> interface. Note that since
1194 * <code>JSeparator</code>s do not conform to the <code>MenuElement</code>
1195 * interface, this array will only contain <code>JMenuItem</code>s.
1196 *
1197 * @return an array of <code>MenuElement</code> objects
1198 */
1199 @BeanProperty(bound = false)
1200 public MenuElement[] getSubElements() {
1201 if(popupMenu == null)
1202 return new MenuElement[0];
1203 else {
1204 MenuElement result[] = new MenuElement[1];
1205 result[0] = popupMenu;
1206 return result;
1207 }
1208 }
1209
1210
1211 // implements javax.swing.MenuElement
1212 /**
1213 * Returns the <code>java.awt.Component</code> used to
1214 * paint this <code>MenuElement</code>.
1215 * The returned component is used to convert events and detect if
1216 * an event is inside a menu component.
1217 */
1218 public Component getComponent() {
1219 return this;
1242 }
1243 popupMenu.setComponentOrientation(o);
1244 }
1245 }
1246
1247 public void setComponentOrientation(ComponentOrientation o) {
1248 super.setComponentOrientation(o);
1249 if ( popupMenu != null ) {
1250 popupMenu.setComponentOrientation(o);
1251 }
1252 }
1253
1254 /**
1255 * <code>setAccelerator</code> is not defined for <code>JMenu</code>.
1256 * Use <code>setMnemonic</code> instead.
1257 * @param keyStroke the keystroke combination which will invoke
1258 * the <code>JMenuItem</code>'s actionlisteners
1259 * without navigating the menu hierarchy
1260 * @exception Error if invoked -- this method is not defined for JMenu.
1261 * Use <code>setMnemonic</code> instead
1262 */
1263 public void setAccelerator(KeyStroke keyStroke) {
1264 throw new Error("setAccelerator() is not defined for JMenu. Use setMnemonic() instead.");
1265 }
1266
1267 /**
1268 * Processes key stroke events such as mnemonics and accelerators.
1269 *
1270 * @param evt the key event to be processed
1271 */
1272 protected void processKeyEvent(KeyEvent evt) {
1273 MenuSelectionManager.defaultManager().processKeyEvent(evt);
1274 if (evt.isConsumed())
1275 return;
1276
1277 super.processKeyEvent(evt);
1278 }
1279
1280 /**
1281 * Programmatically performs a "click". This overrides the method
1348 * @return a string representation of this JMenu.
1349 */
1350 protected String paramString() {
1351 return super.paramString();
1352 }
1353
1354
1355 /////////////////
1356 // Accessibility support
1357 ////////////////
1358
1359 /**
1360 * Gets the AccessibleContext associated with this JMenu.
1361 * For JMenus, the AccessibleContext takes the form of an
1362 * AccessibleJMenu.
1363 * A new AccessibleJMenu instance is created if necessary.
1364 *
1365 * @return an AccessibleJMenu that serves as the
1366 * AccessibleContext of this JMenu
1367 */
1368 @BeanProperty(bound = false)
1369 public AccessibleContext getAccessibleContext() {
1370 if (accessibleContext == null) {
1371 accessibleContext = new AccessibleJMenu();
1372 }
1373 return accessibleContext;
1374 }
1375
1376 /**
1377 * This class implements accessibility support for the
1378 * <code>JMenu</code> class. It provides an implementation of the
1379 * Java Accessibility API appropriate to menu user-interface elements.
1380 * <p>
1381 * <strong>Warning:</strong>
1382 * Serialized objects of this class will not be compatible with
1383 * future Swing releases. The current serialization support is
1384 * appropriate for short term storage or RMI between applications running
1385 * the same version of Swing. As of 1.4, support for long term storage
1386 * of all JavaBeans™
1387 * has been added to the <code>java.beans</code> package.
1388 * Please see {@link java.beans.XMLEncoder}.
|