2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
41 import java
.awt
.Component
;
42 import java
.awt
.Point
;
43 import java
.awt
.event
.KeyEvent
;
44 import java
.awt
.event
.WindowAdapter
;
45 import java
.awt
.event
.WindowEvent
;
46 import java
.beans
.PropertyChangeEvent
;
47 import java
.beans
.PropertyChangeListener
;
48 import java
.io
.Serializable
;
49 import java
.util
.EventListener
;
51 import javax
.accessibility
.Accessible
;
52 import javax
.accessibility
.AccessibleContext
;
53 import javax
.accessibility
.AccessibleRole
;
54 import javax
.accessibility
.AccessibleSelection
;
55 import javax
.swing
.event
.MenuEvent
;
56 import javax
.swing
.event
.MenuListener
;
57 import javax
.swing
.plaf
.MenuItemUI
;
60 * This class represents a menu that can be added to a menu bar or
61 * can be a submenu in some other menu. When JMenu is selected it
62 * displays JPopupMenu containing its menu items.
65 * JMenu's fires MenuEvents when this menu's selection changes. If this menu
66 * is selected, then fireMenuSelectedEvent() is invoked. In case when menu is
67 * deselected or cancelled, then fireMenuDeselectedEvent() or
68 * fireMenuCancelledEvent() is invoked, respectivelly.
71 public class JMenu
extends JMenuItem
implements Accessible
, MenuElement
73 private static final long serialVersionUID
= 4227225638931828014L;
75 /** A Popup menu associated with this menu, which pops up when menu is selected */
76 private JPopupMenu popupMenu
= new JPopupMenu();
78 /** Whenever menu is selected or deselected the MenuEvent is fired to
79 menu's registered listeners. */
80 private MenuEvent menuEvent
= new MenuEvent(this);
82 /*Amount of time, in milliseconds, that should pass before popupMenu
83 associated with this menu appears or disappers */
87 protected WinListener popupListener
;
89 /** Location at which popup menu associated with this menu will be
91 private Point menuLocation
;
94 * Creates a new JMenu object.
103 * Creates a new <code>JMenu</code> with the specified label.
105 * @param text label for this menu
107 public JMenu(String text
)
110 popupMenu
.setInvoker(this);
115 * Creates a new <code>JMenu</code> object.
117 * @param action Action that is used to create menu item tha will be
120 public JMenu(Action action
)
123 createActionChangeListener(this);
124 popupMenu
.setInvoker(this);
129 * Creates a new <code>JMenu</code> with specified label and an option
130 * for this menu to be tear-off menu.
132 * @param text label for this menu
133 * @param tearoff true if this menu should be tear-off and false otherwise
135 public JMenu(String text
, boolean tearoff
)
137 // FIXME: tearoff not implemented
142 * Adds specified menu item to this menu
144 * @param item Menu item to add to this menu
146 * @return Menu item that was added
148 public JMenuItem
add(JMenuItem item
)
150 return popupMenu
.add(item
);
154 * Adds specified component to this menu.
156 * @param component Component to add to this menu
158 * @return Component that was added
160 public Component
add(Component component
)
162 popupMenu
.insert(component
, -1);
167 * Adds specified component to this menu at the given index
169 * @param component Component to add
170 * @param index Position of this menu item in the menu
172 * @return Component that was added
174 public Component
add(Component component
, int index
)
176 return popupMenu
.add(component
, index
);
180 * Adds JMenuItem constructed with the specified label to this menu
182 * @param text label for the menu item that will be added
184 * @return Menu Item that was added to this menu
186 public JMenuItem
add(String text
)
188 return popupMenu
.add(text
);
192 * Adds JMenuItem constructed using properties from specified action.
194 * @param action action to construct the menu item with
196 * @return Menu Item that was added to this menu
198 public JMenuItem
add(Action action
)
200 return popupMenu
.add(action
);
204 * Removes given menu item from this menu. Nothing happens if
205 * this menu doesn't contain specified menu item.
207 * @param item Menu Item which needs to be removed
209 public void remove(JMenuItem item
)
211 popupMenu
.remove(item
);
215 * Removes component at the specified index from this menu
217 * @param index Position of the component that needs to be removed in the menu
219 public void remove(int index
)
221 popupMenu
.remove(index
);
225 * Removes given component from this menu.
227 * @param component Component to remove
229 public void remove(Component component
)
231 int index
= popupMenu
.getComponentIndex(component
);
232 popupMenu
.remove(index
);
236 * Removes all menu items from the menu
238 public void removeAll()
240 popupMenu
.removeAll();
244 * Creates JMenuItem with the specified text and inserts it in the
245 * at the specified index
247 * @param text label for the new menu item
248 * @param index index at which to insert newly created menu item.
250 public void insert(String text
, int index
)
252 this.insert(new JMenuItem(text
), index
);
256 * Creates JMenuItem with the specified text and inserts it in the
257 * at the specified index. IllegalArgumentException is thrown
258 * if index is less than 0
260 * @param item menu item to insert
261 * @param index index at which to insert menu item.
262 * @return Menu item that was added to the menu
264 public JMenuItem
insert(JMenuItem item
, int index
)
267 throw new IllegalArgumentException("index less than zero");
269 popupMenu
.insert(item
, index
);
274 * Creates JMenuItem with the associated action and inserts it to the menu
275 * at the specified index. IllegalArgumentException is thrown
276 * if index is less than 0
278 * @param action Action for the new menu item
279 * @param index index at which to insert newly created menu item.
280 * @return Menu item that was added to the menu
282 public JMenuItem
insert(Action action
, int index
)
284 JMenuItem item
= new JMenuItem(action
);
285 this.insert(item
, index
);
291 * This method sets this menuItem's UI to the UIManager's default for the
292 * current look and feel.
294 public void updateUI()
296 super.setUI((MenuItemUI
) UIManager
.getUI(this));
301 * This method returns a name to identify which look and feel class will be
302 * the UI delegate for the menu.
304 * @return The Look and Feel classID. "MenuUI"
306 public String
getUIClassID()
312 * Sets model for this menu.
314 * @param model model to set
316 public void setModel(ButtonModel model
)
318 super.setModel(model
);
322 * Returns true if the menu is selected and false otherwise
324 * @return true if the menu is selected and false otherwise
326 public boolean isSelected()
328 return super.isSelected();
332 * A helper method to handle setSelected calls from both mouse events and
333 * direct calls to setSelected. Direct calls shouldn't expand the popup
334 * menu and should select the JMenu even if it is disabled. Mouse events
335 * only select the JMenu if it is enabled and should expand the popup menu
336 * associated with this JMenu.
337 * @param selected whether or not the JMenu was selected
338 * @param menuEnabled whether or not selecting the menu is "enabled". This
339 * is always true for direct calls, and is set to isEnabled() for mouse
341 * @param showMenu whether or not to show the popup menu
343 private void setSelectedHelper(boolean selected
, boolean menuEnabled
, boolean showMenu
)
345 // If menu is selected and enabled, activates the menu and
346 // displays associated popup.
347 if (selected
&& menuEnabled
)
349 super.setArmed(true);
350 super.setSelected(true);
352 // FIXME: The popup menu should be shown on the screen after certain
353 // number of seconds pass. The 'delay' property of this menu indicates
354 // this amount of seconds. 'delay' property is 0 by default.
362 if (menuLocation
== null)
364 // Calculate correct position of the popup. Note that location of the popup
365 // passed to show() should be relative to the popup's invoker
366 if (isTopLevelMenu())
367 y
= this.getHeight();
370 getPopupMenu().show(this, x
, y
);
374 getPopupMenu().show(this, menuLocation
.x
, menuLocation
.y
);
381 super.setSelected(false);
382 super.setArmed(false);
383 fireMenuDeselected();
384 popupMenu
.setVisible(false);
389 * Changes this menu selected state if selected is true and false otherwise
390 * This method fires menuEvents to menu's registered listeners.
392 * @param selected true if the menu should be selected and false otherwise
394 public void setSelected(boolean selected
)
396 setSelectedHelper(selected
, true, false);
400 * Checks if PopupMenu associated with this menu is visible
402 * @return true if the popup associated with this menu is currently visible
403 * on the screen and false otherwise.
405 public boolean isPopupMenuVisible()
407 return popupMenu
.isVisible();
411 * Sets popup menu visibility
413 * @param popup true if popup should be visible and false otherwise
415 public void setPopupMenuVisible(boolean popup
)
417 if (getModel().isEnabled())
418 popupMenu
.setVisible(popup
);
422 * Returns origin point of the popup menu
424 * @return Point containing
426 protected Point
getPopupMenuOrigin()
428 // if menu in the menu bar
429 if (isTopLevelMenu())
430 return new Point(0, this.getHeight());
433 return new Point(this.getWidth(), 0);
437 * Returns delay property.
439 * @return delay property, indicating number of milliseconds before
440 * popup menu associated with the menu appears or disappears after
441 * menu was selected or deselected respectively
443 public int getDelay()
449 * Sets delay property for this menu. If given time for the delay
450 * property is negative, then IllegalArgumentException is thrown
452 * @param delay number of milliseconds before
453 * popup menu associated with the menu appears or disappears after
454 * menu was selected or deselected respectively
456 public void setDelay(int delay
)
459 throw new IllegalArgumentException("delay less than 0");
464 * Sets location at which popup menu should be displayed
465 * The location given is relative to this menu item
467 * @param x x-coordinate of the menu location
468 * @param y y-coordinate of the menu location
470 public void setMenuLocation(int x
, int y
)
472 menuLocation
= new Point(x
, y
);
476 * Creates and returns JMenuItem associated with the given action
478 * @param action Action to use for creation of JMenuItem
480 * @return JMenuItem that was creted with given action
482 protected JMenuItem
createActionComponent(Action action
)
484 return new JMenuItem(action
);
488 * Creates ActionChangeListener to listen for PropertyChangeEvents occuring
489 * in the action that is associated with this menu
491 * @param item menu that contains action to listen to
493 * @return The PropertyChangeListener
495 protected PropertyChangeListener
createActionChangeListener(JMenuItem item
)
497 return new ActionChangedListener(item
);
501 * Adds separator to the end of the menu items in the menu.
503 public void addSeparator()
505 getPopupMenu().addSeparator();
509 * Inserts separator in the menu at the specified index.
511 * @param index Index at which separator should be inserted
513 public void insertSeparator(int index
)
516 throw new IllegalArgumentException("index less than 0");
518 getPopupMenu().insert(new JPopupMenu
.Separator(), index
);
522 * Returns menu item located at the specified index in the menu
524 * @param index Index at which to look for the menu item
526 * @return menu item located at the specified index in the menu
528 public JMenuItem
getItem(int index
)
531 throw new IllegalArgumentException("index less than 0");
533 Component c
= popupMenu
.getComponentAtIndex(index
);
535 if (c
instanceof JMenuItem
)
536 return (JMenuItem
) c
;
542 * Returns number of items in the menu including separators.
544 * @return number of items in the menu
546 * @see #getMenuComponentCount()
548 public int getItemCount()
550 return getMenuComponentCount();
554 * Checks if this menu is a tear-off menu.
556 * @return true if this menu is a tear-off menu and false otherwise
558 public boolean isTearOff()
560 // NOT YET IMPLEMENTED
565 * Returns number of menu components in this menu
567 * @return number of menu components in this menu
569 public int getMenuComponentCount()
571 return popupMenu
.getComponentCount();
575 * Returns menu component located at the givent index
578 * @param index index at which to get the menu component in the menu
580 * @return Menu Component located in the menu at the specified index
582 public Component
getMenuComponent(int index
)
584 return (Component
) popupMenu
.getComponentAtIndex(index
);
588 * Return components belonging to this menu
590 * @return components belonging to this menu
592 public Component
[] getMenuComponents()
594 return popupMenu
.getComponents();
598 * Checks if this menu is a top level menu. The menu is top
599 * level menu if it is inside the menu bar. While if the menu
600 * inside some other menu, it is considered to be a pull-right menu.
602 * @return true if this menu is top level menu, and false otherwise
604 public boolean isTopLevelMenu()
606 return getParent() instanceof JMenuBar
;
610 * Checks if given component exists in this menu. The submenus of
611 * this menu are checked as well
613 * @param component Component to look for
615 * @return true if the given component exists in this menu, and false otherwise
617 public boolean isMenuComponent(Component component
)
623 * Returns popup menu associated with the menu.
625 * @return popup menu associated with the menu.
627 public JPopupMenu
getPopupMenu()
633 * Adds MenuListener to the menu
635 * @param listener MenuListener to add
637 public void addMenuListener(MenuListener listener
)
639 listenerList
.add(MenuListener
.class, listener
);
643 * Removes MenuListener from the menu
645 * @param listener MenuListener to remove
647 public void removeMenuListener(MenuListener listener
)
649 listenerList
.remove(MenuListener
.class, listener
);
653 * Returns all registered <code>MenuListener</code> objects.
655 * @return an array of listeners
659 public MenuListener
[] getMenuListeners()
661 return (MenuListener
[]) listenerList
.getListeners(MenuListener
.class);
665 * This method fires MenuEvents to all menu's MenuListeners. In this case
666 * menuSelected() method of MenuListeners is called to indicated that the menu
669 protected void fireMenuSelected()
671 MenuListener
[] listeners
= getMenuListeners();
673 for (int index
= 0; index
< listeners
.length
; ++index
)
674 listeners
[index
].menuSelected(menuEvent
);
678 * This method fires MenuEvents to all menu's MenuListeners. In this case
679 * menuDeselected() method of MenuListeners is called to indicated that the menu
682 protected void fireMenuDeselected()
684 EventListener
[] ll
= listenerList
.getListeners(MenuListener
.class);
686 for (int i
= 0; i
< ll
.length
; i
++)
687 ((MenuListener
) ll
[i
]).menuDeselected(menuEvent
);
691 * This method fires MenuEvents to all menu's MenuListeners. In this case
692 * menuSelected() method of MenuListeners is called to indicated that the menu
693 * was cancelled. The menu is cancelled when it's popup menu is close without selection.
695 protected void fireMenuCanceled()
697 EventListener
[] ll
= listenerList
.getListeners(MenuListener
.class);
699 for (int i
= 0; i
< ll
.length
; i
++)
700 ((MenuListener
) ll
[i
]).menuCanceled(menuEvent
);
704 * Creates WinListener that listens to the menu;s popup menu.
706 * @param popup JPopupMenu to listen to
708 * @return The WinListener
710 protected WinListener
createWinListener(JPopupMenu popup
)
712 return new WinListener(popup
);
716 * Method of the MenuElementInterface. It reacts to the selection
717 * changes in the menu. If this menu was selected, then it
718 * displayes popup menu associated with it and if this menu was
719 * deselected it hides the popup menu.
721 * @param changed true if the menu was selected and false otherwise
723 public void menuSelectionChanged(boolean changed
)
725 // if this menu selection is true, then activate this menu and
726 // display popup associated with this menu
727 setSelectedHelper(changed
, isEnabled(), true);
731 * Method of MenuElement interface. Returns sub components of
734 * @return array containing popupMenu that is associated with this menu
736 public MenuElement
[] getSubElements()
738 return new MenuElement
[] { popupMenu
};
742 * @return Returns reference to itself
744 public Component
getComponent()
750 * This method is overriden with empty implementation, s.t the
751 * accelerator couldn't be set for the menu. The mnemonic should
752 * be used for the menu instead.
754 * @param keystroke accelerator for this menu
756 public void setAccelerator(KeyStroke keystroke
)
758 throw new Error("setAccelerator() is not defined for JMenu. Use setMnemonic() instead.");
762 * This method process KeyEvent occuring when the menu is visible
764 * @param event The KeyEvent
766 protected void processKeyEvent(KeyEvent event
)
768 // TODO: Implement this properly.
772 * Programatically performs click
774 * @param time Number of milliseconds for which this menu stays pressed
776 public void doClick(int time
)
778 getModel().setArmed(true);
779 getModel().setPressed(true);
782 java
.lang
.Thread
.sleep(time
);
784 catch (java
.lang
.InterruptedException e
)
789 getModel().setPressed(false);
790 getModel().setArmed(false);
791 popupMenu
.show(this, this.getWidth(), 0);
795 * A string that describes this JMenu. Normally only used
798 * @return A string describing this JMenu
800 protected String
paramString()
802 return super.paramString();
805 public AccessibleContext
getAccessibleContext()
807 if (accessibleContext
== null)
808 accessibleContext
= new AccessibleJMenu();
810 return accessibleContext
;
813 // FIXME: This inner class is a complete stub and needs to be implemented.
814 protected class AccessibleJMenu
extends AccessibleJMenuItem
815 implements AccessibleSelection
817 private static final long serialVersionUID
= -8131864021059524309L;
819 protected AccessibleJMenu()
821 // Nothing to do here.
824 public int getAccessibleChildrenCount()
829 public Accessible
getAccessibleChild(int value0
)
834 public AccessibleSelection
getAccessibleSelection()
839 public Accessible
getAccessibleSelection(int value0
)
844 public boolean isAccessibleChildSelected(int value0
)
849 public AccessibleRole
getAccessibleRole()
851 return AccessibleRole
.MENU
;
854 public int getAccessibleSelectionCount()
859 public void addAccessibleSelection(int value0
)
861 // TODO: Implement this properly.
864 public void removeAccessibleSelection(int value0
)
866 // TODO: Implement this properly.
869 public void clearAccessibleSelection()
871 // TODO: Implement this properly.
874 public void selectAllAccessibleSelection()
876 // TODO: Implement this properly.
880 protected class WinListener
extends WindowAdapter
implements Serializable
882 private static final long serialVersionUID
= -6415815570638474823L;
885 * Creates a new <code>WinListener</code>.
887 * @param popup the popup menu which is observed
889 public WinListener(JPopupMenu popup
)
891 // TODO: What should we do with the popup argument?
895 * Receives notification when the popup menu is closing and deselects
898 * @param event the window event
900 public void windowClosing(WindowEvent event
)
907 * This class listens to PropertyChangeEvents occuring in menu's action
909 private class ActionChangedListener
implements PropertyChangeListener
911 /** menu item associated with the action */
912 private JMenuItem menuItem
;
914 /** Creates new ActionChangedListener and adds it to menuItem's action */
915 public ActionChangedListener(JMenuItem menuItem
)
917 this.menuItem
= menuItem
;
919 Action a
= menuItem
.getAction();
921 a
.addPropertyChangeListener(this);
924 /**This method is invoked when some change occures in menuItem's action*/
925 public void propertyChange(PropertyChangeEvent evt
)
927 // FIXME: Need to implement