Frames | No Frames |
1: /* JMenu.java -- 2: Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 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) 9: any later version. 10: 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. 15: 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 19: 02110-1301 USA. 20: 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 24: combination. 25: 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. */ 37: 38: 39: package javax.swing; 40: 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.ArrayList; 50: import java.util.EventListener; 51: 52: import javax.accessibility.Accessible; 53: import javax.accessibility.AccessibleContext; 54: import javax.accessibility.AccessibleRole; 55: import javax.accessibility.AccessibleSelection; 56: import javax.swing.event.MenuEvent; 57: import javax.swing.event.MenuListener; 58: import javax.swing.plaf.MenuItemUI; 59: 60: /** 61: * This class represents a menu that can be added to a menu bar or 62: * can be a submenu in some other menu. When JMenu is selected it 63: * displays JPopupMenu containing its menu items. 64: * 65: * <p> 66: * JMenu's fires MenuEvents when this menu's selection changes. If this menu 67: * is selected, then fireMenuSelectedEvent() is invoked. In case when menu is 68: * deselected or cancelled, then fireMenuDeselectedEvent() or 69: * fireMenuCancelledEvent() is invoked, respectivelly. 70: * </p> 71: */ 72: public class JMenu extends JMenuItem implements Accessible, MenuElement 73: { 74: private static final long serialVersionUID = 4227225638931828014L; 75: 76: /** A Popup menu associated with this menu, which pops up when menu is selected */ 77: private JPopupMenu popupMenu = new JPopupMenu(); 78: 79: /** Whenever menu is selected or deselected the MenuEvent is fired to 80: menu's registered listeners. */ 81: private MenuEvent menuEvent = new MenuEvent(this); 82: 83: /*Amount of time, in milliseconds, that should pass before popupMenu 84: associated with this menu appears or disappers */ 85: private int delay; 86: 87: /* PopupListener */ 88: protected WinListener popupListener; 89: 90: /** Location at which popup menu associated with this menu will be 91: displayed */ 92: private Point menuLocation; 93: 94: /** 95: * Creates a new JMenu object. 96: */ 97: public JMenu() 98: { 99: super(); 100: setOpaque(false); 101: } 102: 103: /** 104: * Creates a new <code>JMenu</code> with the specified label. 105: * 106: * @param text label for this menu 107: */ 108: public JMenu(String text) 109: { 110: super(text); 111: popupMenu.setInvoker(this); 112: setOpaque(false); 113: } 114: 115: /** 116: * Creates a new <code>JMenu</code> object. 117: * 118: * @param action Action that is used to create menu item tha will be 119: * added to the menu. 120: */ 121: public JMenu(Action action) 122: { 123: super(action); 124: createActionChangeListener(this); 125: popupMenu.setInvoker(this); 126: setOpaque(false); 127: } 128: 129: /** 130: * Creates a new <code>JMenu</code> with specified label and an option 131: * for this menu to be tear-off menu. 132: * 133: * @param text label for this menu 134: * @param tearoff true if this menu should be tear-off and false otherwise 135: */ 136: public JMenu(String text, boolean tearoff) 137: { 138: // FIXME: tearoff not implemented 139: this(text); 140: } 141: 142: /** 143: * Adds specified menu item to this menu 144: * 145: * @param item Menu item to add to this menu 146: * 147: * @return Menu item that was added 148: */ 149: public JMenuItem add(JMenuItem item) 150: { 151: return popupMenu.add(item); 152: } 153: 154: /** 155: * Adds specified component to this menu. 156: * 157: * @param component Component to add to this menu 158: * 159: * @return Component that was added 160: */ 161: public Component add(Component component) 162: { 163: popupMenu.insert(component, -1); 164: return component; 165: } 166: 167: /** 168: * Adds specified component to this menu at the given index 169: * 170: * @param component Component to add 171: * @param index Position of this menu item in the menu 172: * 173: * @return Component that was added 174: */ 175: public Component add(Component component, int index) 176: { 177: return popupMenu.add(component, index); 178: } 179: 180: /** 181: * Adds JMenuItem constructed with the specified label to this menu 182: * 183: * @param text label for the menu item that will be added 184: * 185: * @return Menu Item that was added to this menu 186: */ 187: public JMenuItem add(String text) 188: { 189: return popupMenu.add(text); 190: } 191: 192: /** 193: * Adds JMenuItem constructed using properties from specified action. 194: * 195: * @param action action to construct the menu item with 196: * 197: * @return Menu Item that was added to this menu 198: */ 199: public JMenuItem add(Action action) 200: { 201: return popupMenu.add(action); 202: } 203: 204: /** 205: * Removes given menu item from this menu. Nothing happens if 206: * this menu doesn't contain specified menu item. 207: * 208: * @param item Menu Item which needs to be removed 209: */ 210: public void remove(JMenuItem item) 211: { 212: popupMenu.remove(item); 213: } 214: 215: /** 216: * Removes component at the specified index from this menu 217: * 218: * @param index Position of the component that needs to be removed in the menu 219: */ 220: public void remove(int index) 221: { 222: popupMenu.remove(index); 223: } 224: 225: /** 226: * Removes given component from this menu. 227: * 228: * @param component Component to remove 229: */ 230: public void remove(Component component) 231: { 232: int index = popupMenu.getComponentIndex(component); 233: popupMenu.remove(index); 234: } 235: 236: /** 237: * Removes all menu items from the menu 238: */ 239: public void removeAll() 240: { 241: popupMenu.removeAll(); 242: } 243: 244: /** 245: * Creates JMenuItem with the specified text and inserts it in the 246: * at the specified index 247: * 248: * @param text label for the new menu item 249: * @param index index at which to insert newly created menu item. 250: */ 251: public void insert(String text, int index) 252: { 253: this.insert(new JMenuItem(text), index); 254: } 255: 256: /** 257: * Creates JMenuItem with the specified text and inserts it in the 258: * at the specified index. IllegalArgumentException is thrown 259: * if index is less than 0 260: * 261: * @param item menu item to insert 262: * @param index index at which to insert menu item. 263: * @return Menu item that was added to the menu 264: */ 265: public JMenuItem insert(JMenuItem item, int index) 266: { 267: if (index < 0) 268: throw new IllegalArgumentException("index less than zero"); 269: 270: popupMenu.insert(item, index); 271: return item; 272: } 273: 274: /** 275: * Creates JMenuItem with the associated action and inserts it to the menu 276: * at the specified index. IllegalArgumentException is thrown 277: * if index is less than 0 278: * 279: * @param action Action for the new menu item 280: * @param index index at which to insert newly created menu item. 281: * @return Menu item that was added to the menu 282: */ 283: public JMenuItem insert(Action action, int index) 284: { 285: JMenuItem item = new JMenuItem(action); 286: this.insert(item, index); 287: 288: return item; 289: } 290: 291: /** 292: * This method sets this menuItem's UI to the UIManager's default for the 293: * current look and feel. 294: */ 295: public void updateUI() 296: { 297: setUI((MenuItemUI) UIManager.getUI(this)); 298: } 299: 300: /** 301: * This method returns a name to identify which look and feel class will be 302: * the UI delegate for the menu. 303: * 304: * @return The Look and Feel classID. "MenuUI" 305: */ 306: public String getUIClassID() 307: { 308: return "MenuUI"; 309: } 310: 311: /** 312: * Sets model for this menu. 313: * 314: * @param model model to set 315: */ 316: public void setModel(ButtonModel model) 317: { 318: super.setModel(model); 319: } 320: 321: /** 322: * Returns true if the menu is selected and false otherwise 323: * 324: * @return true if the menu is selected and false otherwise 325: */ 326: public boolean isSelected() 327: { 328: return super.isSelected(); 329: } 330: 331: /** 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 340: * based calls. 341: * @param showMenu whether or not to show the popup menu 342: */ 343: private void setSelectedHelper(boolean selected, boolean menuEnabled, boolean showMenu) 344: { 345: // If menu is selected and enabled, activates the menu and 346: // displays associated popup. 347: if (selected && menuEnabled) 348: { 349: super.setArmed(true); 350: super.setSelected(true); 351: 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. 355: if (isShowing()) 356: { 357: fireMenuSelected(); 358: 359: int x = 0; 360: int y = 0; 361: if (showMenu) 362: if (menuLocation == null) 363: { 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(); 368: else 369: x = this.getWidth(); 370: getPopupMenu().show(this, x, y); 371: } 372: else 373: { 374: getPopupMenu().show(this, menuLocation.x, menuLocation.y); 375: } 376: } 377: } 378: 379: else 380: { 381: super.setSelected(false); 382: super.setArmed(false); 383: fireMenuDeselected(); 384: popupMenu.setVisible(false); 385: } 386: } 387: 388: /** 389: * Changes this menu selected state if selected is true and false otherwise 390: * This method fires menuEvents to menu's registered listeners. 391: * 392: * @param selected true if the menu should be selected and false otherwise 393: */ 394: public void setSelected(boolean selected) 395: { 396: setSelectedHelper(selected, true, false); 397: } 398: 399: /** 400: * Checks if PopupMenu associated with this menu is visible 401: * 402: * @return true if the popup associated with this menu is currently visible 403: * on the screen and false otherwise. 404: */ 405: public boolean isPopupMenuVisible() 406: { 407: return popupMenu.isVisible(); 408: } 409: 410: /** 411: * Sets popup menu visibility 412: * 413: * @param popup true if popup should be visible and false otherwise 414: */ 415: public void setPopupMenuVisible(boolean popup) 416: { 417: if (getModel().isEnabled()) 418: popupMenu.setVisible(popup); 419: } 420: 421: /** 422: * Returns origin point of the popup menu 423: * 424: * @return Point containing 425: */ 426: protected Point getPopupMenuOrigin() 427: { 428: // if menu in the menu bar 429: if (isTopLevelMenu()) 430: return new Point(0, this.getHeight()); 431: 432: // if submenu 433: return new Point(this.getWidth(), 0); 434: } 435: 436: /** 437: * Returns delay property. 438: * 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 442: */ 443: public int getDelay() 444: { 445: return delay; 446: } 447: 448: /** 449: * Sets delay property for this menu. If given time for the delay 450: * property is negative, then IllegalArgumentException is thrown 451: * 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 455: */ 456: public void setDelay(int delay) 457: { 458: if (delay < 0) 459: throw new IllegalArgumentException("delay less than 0"); 460: this.delay = delay; 461: } 462: 463: /** 464: * Sets location at which popup menu should be displayed 465: * The location given is relative to this menu item 466: * 467: * @param x x-coordinate of the menu location 468: * @param y y-coordinate of the menu location 469: */ 470: public void setMenuLocation(int x, int y) 471: { 472: menuLocation = new Point(x, y); 473: } 474: 475: /** 476: * Creates and returns JMenuItem associated with the given action 477: * 478: * @param action Action to use for creation of JMenuItem 479: * 480: * @return JMenuItem that was creted with given action 481: */ 482: protected JMenuItem createActionComponent(Action action) 483: { 484: return new JMenuItem(action); 485: } 486: 487: /** 488: * Creates ActionChangeListener to listen for PropertyChangeEvents occuring 489: * in the action that is associated with this menu 490: * 491: * @param item menu that contains action to listen to 492: * 493: * @return The PropertyChangeListener 494: */ 495: protected PropertyChangeListener createActionChangeListener(JMenuItem item) 496: { 497: return new ActionChangedListener(item); 498: } 499: 500: /** 501: * Adds separator to the end of the menu items in the menu. 502: */ 503: public void addSeparator() 504: { 505: getPopupMenu().addSeparator(); 506: } 507: 508: /** 509: * Inserts separator in the menu at the specified index. 510: * 511: * @param index Index at which separator should be inserted 512: */ 513: public void insertSeparator(int index) 514: { 515: if (index < 0) 516: throw new IllegalArgumentException("index less than 0"); 517: 518: getPopupMenu().insert(new JPopupMenu.Separator(), index); 519: } 520: 521: /** 522: * Returns menu item located at the specified index in the menu 523: * 524: * @param index Index at which to look for the menu item 525: * 526: * @return menu item located at the specified index in the menu 527: */ 528: public JMenuItem getItem(int index) 529: { 530: if (index < 0) 531: throw new IllegalArgumentException("index less than 0"); 532: 533: Component c = popupMenu.getComponentAtIndex(index); 534: 535: if (c instanceof JMenuItem) 536: return (JMenuItem) c; 537: else 538: return null; 539: } 540: 541: /** 542: * Returns number of items in the menu including separators. 543: * 544: * @return number of items in the menu 545: * 546: * @see #getMenuComponentCount() 547: */ 548: public int getItemCount() 549: { 550: return getMenuComponentCount(); 551: } 552: 553: /** 554: * Checks if this menu is a tear-off menu. 555: * 556: * @return true if this menu is a tear-off menu and false otherwise 557: */ 558: public boolean isTearOff() 559: { 560: // NOT YET IMPLEMENTED 561: return false; 562: } 563: 564: /** 565: * Returns number of menu components in this menu 566: * 567: * @return number of menu components in this menu 568: */ 569: public int getMenuComponentCount() 570: { 571: return popupMenu.getComponentCount(); 572: } 573: 574: /** 575: * Returns menu component located at the givent index 576: * in the menu 577: * 578: * @param index index at which to get the menu component in the menu 579: * 580: * @return Menu Component located in the menu at the specified index 581: */ 582: public Component getMenuComponent(int index) 583: { 584: return (Component) popupMenu.getComponentAtIndex(index); 585: } 586: 587: /** 588: * Return components belonging to this menu 589: * 590: * @return components belonging to this menu 591: */ 592: public Component[] getMenuComponents() 593: { 594: return popupMenu.getComponents(); 595: } 596: 597: /** 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. 601: * 602: * @return true if this menu is top level menu, and false otherwise 603: */ 604: public boolean isTopLevelMenu() 605: { 606: return getParent() instanceof JMenuBar; 607: } 608: 609: /** 610: * Checks if given component exists in this menu. The submenus of 611: * this menu are checked as well 612: * 613: * @param component Component to look for 614: * 615: * @return true if the given component exists in this menu, and false otherwise 616: */ 617: public boolean isMenuComponent(Component component) 618: { 619: return false; 620: } 621: 622: /** 623: * Returns popup menu associated with the menu. 624: * 625: * @return popup menu associated with the menu. 626: */ 627: public JPopupMenu getPopupMenu() 628: { 629: return popupMenu; 630: } 631: 632: /** 633: * Adds MenuListener to the menu 634: * 635: * @param listener MenuListener to add 636: */ 637: public void addMenuListener(MenuListener listener) 638: { 639: listenerList.add(MenuListener.class, listener); 640: } 641: 642: /** 643: * Removes MenuListener from the menu 644: * 645: * @param listener MenuListener to remove 646: */ 647: public void removeMenuListener(MenuListener listener) 648: { 649: listenerList.remove(MenuListener.class, listener); 650: } 651: 652: /** 653: * Returns all registered <code>MenuListener</code> objects. 654: * 655: * @return an array of listeners 656: * 657: * @since 1.4 658: */ 659: public MenuListener[] getMenuListeners() 660: { 661: return (MenuListener[]) listenerList.getListeners(MenuListener.class); 662: } 663: 664: /** 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 667: * was selected. 668: */ 669: protected void fireMenuSelected() 670: { 671: MenuListener[] listeners = getMenuListeners(); 672: 673: for (int index = 0; index < listeners.length; ++index) 674: listeners[index].menuSelected(menuEvent); 675: } 676: 677: /** 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 680: * was deselected. 681: */ 682: protected void fireMenuDeselected() 683: { 684: EventListener[] ll = listenerList.getListeners(MenuListener.class); 685: 686: for (int i = 0; i < ll.length; i++) 687: ((MenuListener) ll[i]).menuDeselected(menuEvent); 688: } 689: 690: /** 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. 694: */ 695: protected void fireMenuCanceled() 696: { 697: EventListener[] ll = listenerList.getListeners(MenuListener.class); 698: 699: for (int i = 0; i < ll.length; i++) 700: ((MenuListener) ll[i]).menuCanceled(menuEvent); 701: } 702: 703: /** 704: * Creates WinListener that listens to the menu;s popup menu. 705: * 706: * @param popup JPopupMenu to listen to 707: * 708: * @return The WinListener 709: */ 710: protected WinListener createWinListener(JPopupMenu popup) 711: { 712: return new WinListener(popup); 713: } 714: 715: /** 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. 720: * 721: * @param changed true if the menu was selected and false otherwise 722: */ 723: public void menuSelectionChanged(boolean changed) 724: { 725: // if this menu selection is true, then activate this menu and 726: // display popup associated with this menu 727: setSelectedHelper(changed, isEnabled(), true); 728: } 729: 730: /** 731: * Method of MenuElement interface. Returns sub components of 732: * this menu. 733: * 734: * @return array containing popupMenu that is associated with this menu 735: */ 736: public MenuElement[] getSubElements() 737: { 738: return new MenuElement[] { popupMenu }; 739: } 740: 741: /** 742: * @return Returns reference to itself 743: */ 744: public Component getComponent() 745: { 746: return this; 747: } 748: 749: /** 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. 753: * 754: * @param keystroke accelerator for this menu 755: */ 756: public void setAccelerator(KeyStroke keystroke) 757: { 758: throw new Error("setAccelerator() is not defined for JMenu. Use setMnemonic() instead."); 759: } 760: 761: /** 762: * This method process KeyEvent occuring when the menu is visible 763: * 764: * @param event The KeyEvent 765: */ 766: protected void processKeyEvent(KeyEvent event) 767: { 768: MenuSelectionManager.defaultManager().processKeyEvent(event); 769: } 770: 771: /** 772: * Programatically performs click 773: * 774: * @param time Number of milliseconds for which this menu stays pressed 775: */ 776: public void doClick(int time) 777: { 778: getModel().setArmed(true); 779: getModel().setPressed(true); 780: try 781: { 782: java.lang.Thread.sleep(time); 783: } 784: catch (java.lang.InterruptedException e) 785: { 786: // probably harmless 787: } 788: 789: getModel().setPressed(false); 790: getModel().setArmed(false); 791: popupMenu.show(this, this.getWidth(), 0); 792: } 793: 794: /** 795: * A string that describes this JMenu. Normally only used 796: * for debugging. 797: * 798: * @return A string describing this JMenu 799: */ 800: protected String paramString() 801: { 802: return super.paramString(); 803: } 804: 805: public AccessibleContext getAccessibleContext() 806: { 807: if (accessibleContext == null) 808: accessibleContext = new AccessibleJMenu(); 809: 810: return accessibleContext; 811: } 812: 813: /** 814: * Implements support for assisitive technologies for <code>JMenu</code>. 815: */ 816: protected class AccessibleJMenu extends AccessibleJMenuItem 817: implements AccessibleSelection 818: { 819: private static final long serialVersionUID = -8131864021059524309L; 820: 821: protected AccessibleJMenu() 822: { 823: // Nothing to do here. 824: } 825: 826: /** 827: * Returns the number of accessible children of this object. 828: * 829: * @return the number of accessible children of this object 830: */ 831: public int getAccessibleChildrenCount() 832: { 833: Component[] children = getMenuComponents(); 834: int count = 0; 835: for (int i = 0; i < children.length; i++) 836: { 837: if (children[i] instanceof Accessible) 838: count++; 839: } 840: return count; 841: } 842: 843: /** 844: * Returns the accessible child with the specified <code>index</code>. 845: * 846: * @param index the index of the child to fetch 847: * 848: * @return the accessible child with the specified <code>index</code> 849: */ 850: public Accessible getAccessibleChild(int index) 851: { 852: Component[] children = getMenuComponents(); 853: int count = 0; 854: Accessible found = null; 855: for (int i = 0; i < children.length; i++) 856: { 857: if (children[i] instanceof Accessible) 858: { 859: if (count == index) 860: { 861: found = (Accessible) children[i]; 862: break; 863: } 864: count++; 865: } 866: } 867: return found; 868: } 869: 870: /** 871: * Returns the accessible selection of this object. AccessibleJMenus handle 872: * their selection themselves, so we always return <code>this</code> here. 873: * 874: * @return the accessible selection of this object 875: */ 876: public AccessibleSelection getAccessibleSelection() 877: { 878: return this; 879: } 880: 881: /** 882: * Returns the selected accessible child with the specified 883: * <code>index</code>. 884: * 885: * @param index the index of the accessible selected child to return 886: * 887: * @return the selected accessible child with the specified 888: * <code>index</code> 889: */ 890: public Accessible getAccessibleSelection(int index) 891: { 892: Accessible selected = null; 893: // Only one item can be selected, which must therefore have index == 0. 894: if (index == 0) 895: { 896: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 897: MenuElement[] me = msm.getSelectedPath(); 898: if (me != null) 899: { 900: for (int i = 0; i < me.length; i++) 901: { 902: if (me[i] == JMenu.this) 903: { 904: // This JMenu is selected, find and return the next 905: // JMenuItem in the path. 906: do 907: { 908: if (me[i] instanceof Accessible) 909: { 910: selected = (Accessible) me[i]; 911: break; 912: } 913: i++; 914: } while (i < me.length); 915: } 916: if (selected != null) 917: break; 918: } 919: } 920: } 921: return selected; 922: } 923: 924: /** 925: * Returns <code>true</code> if the accessible child with the specified 926: * index is selected, <code>false</code> otherwise. 927: * 928: * @param index the index of the accessible child to check 929: * 930: * @return <code>true</code> if the accessible child with the specified 931: * index is selected, <code>false</code> otherwise 932: */ 933: public boolean isAccessibleChildSelected(int index) 934: { 935: boolean selected = false; 936: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 937: MenuElement[] me = msm.getSelectedPath(); 938: if (me != null) 939: { 940: Accessible toBeFound = getAccessibleChild(index); 941: for (int i = 0; i < me.length; i++) 942: { 943: if (me[i] == toBeFound) 944: { 945: selected = true; 946: break; 947: } 948: } 949: } 950: return selected; 951: } 952: 953: /** 954: * Returns the accessible role of this object, which is 955: * {@link AccessibleRole#MENU} for the AccessibleJMenu. 956: * 957: * @return the accessible role of this object 958: */ 959: public AccessibleRole getAccessibleRole() 960: { 961: return AccessibleRole.MENU; 962: } 963: 964: /** 965: * Returns the number of selected accessible children. This will be 966: * <code>0</code> if no item is selected, or <code>1</code> if an item 967: * is selected. AccessibleJMenu can have maximum 1 selected item. 968: * 969: * @return the number of selected accessible children 970: */ 971: public int getAccessibleSelectionCount() 972: { 973: int count = 0; 974: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 975: MenuElement[] me = msm.getSelectedPath(); 976: if (me != null) 977: { 978: for (int i = 0; i < me.length; i++) 979: { 980: if (me[i] == JMenu.this) 981: { 982: if (i + 1 < me.length) 983: { 984: count = 1; 985: break; 986: } 987: } 988: } 989: } 990: return count; 991: } 992: 993: /** 994: * Selects the accessible child with the specified index. 995: * 996: * @param index the index of the accessible child to select 997: */ 998: public void addAccessibleSelection(int index) 999: { 1000: Accessible child = getAccessibleChild(index); 1001: if (child != null && child instanceof JMenuItem) 1002: { 1003: JMenuItem mi = (JMenuItem) child; 1004: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 1005: msm.setSelectedPath(createPath(JMenu.this)); 1006: } 1007: } 1008: 1009: /** 1010: * Removes the item with the specified index from the selection. 1011: * 1012: * @param index the index of the selected item to remove from the selection 1013: */ 1014: public void removeAccessibleSelection(int index) 1015: { 1016: Accessible child = getAccessibleChild(index); 1017: if (child != null) 1018: { 1019: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 1020: MenuElement[] oldSelection = msm.getSelectedPath(); 1021: for (int i = 0; i < oldSelection.length; i++) 1022: { 1023: if (oldSelection[i] == child) 1024: { 1025: // Found the specified child in the selection. Remove it 1026: // from the selection. 1027: MenuElement[] newSel = new MenuElement[i - 1]; 1028: System.arraycopy(oldSelection, 0, newSel, 0, i - 1); 1029: msm.setSelectedPath(newSel); 1030: break; 1031: } 1032: } 1033: } 1034: } 1035: 1036: /** 1037: * Removes all possibly selected accessible children of this object from 1038: * the selection. 1039: */ 1040: public void clearAccessibleSelection() 1041: { 1042: MenuSelectionManager msm = MenuSelectionManager.defaultManager(); 1043: MenuElement[] oldSelection = msm.getSelectedPath(); 1044: for (int i = 0; i < oldSelection.length; i++) 1045: { 1046: if (oldSelection[i] == JMenu.this) 1047: { 1048: // Found this menu in the selection. Remove all children from 1049: // the selection. 1050: MenuElement[] newSel = new MenuElement[i]; 1051: System.arraycopy(oldSelection, 0, newSel, 0, i); 1052: msm.setSelectedPath(newSel); 1053: break; 1054: } 1055: } 1056: } 1057: 1058: /** 1059: * AccessibleJMenu don't support multiple selection, so this method 1060: * does nothing. 1061: */ 1062: public void selectAllAccessibleSelection() 1063: { 1064: // Nothing to do here. 1065: } 1066: } 1067: 1068: protected class WinListener extends WindowAdapter implements Serializable 1069: { 1070: private static final long serialVersionUID = -6415815570638474823L; 1071: 1072: /** 1073: * Creates a new <code>WinListener</code>. 1074: * 1075: * @param popup the popup menu which is observed 1076: */ 1077: public WinListener(JPopupMenu popup) 1078: { 1079: // TODO: What should we do with the popup argument? 1080: } 1081: 1082: /** 1083: * Receives notification when the popup menu is closing and deselects 1084: * the menu. 1085: * 1086: * @param event the window event 1087: */ 1088: public void windowClosing(WindowEvent event) 1089: { 1090: setSelected(false); 1091: } 1092: } 1093: 1094: /** 1095: * This class listens to PropertyChangeEvents occuring in menu's action 1096: */ 1097: private class ActionChangedListener implements PropertyChangeListener 1098: { 1099: /** menu item associated with the action */ 1100: private JMenuItem menuItem; 1101: 1102: /** Creates new ActionChangedListener and adds it to menuItem's action */ 1103: public ActionChangedListener(JMenuItem menuItem) 1104: { 1105: this.menuItem = menuItem; 1106: 1107: Action a = menuItem.getAction(); 1108: if (a != null) 1109: a.addPropertyChangeListener(this); 1110: } 1111: 1112: /**This method is invoked when some change occures in menuItem's action*/ 1113: public void propertyChange(PropertyChangeEvent evt) 1114: { 1115: // FIXME: Need to implement 1116: } 1117: } 1118: 1119: /** 1120: * Creates an array to be feeded as argument to 1121: * {@link MenuSelectionManager#setSelectedPath(MenuElement[])} for the 1122: * specified element. This has the effect of selecting the specified element 1123: * and all its parents. 1124: * 1125: * @param leaf the leaf element for which to create the selected path 1126: * 1127: * @return the selected path array 1128: */ 1129: MenuElement[] createPath(JMenu leaf) 1130: { 1131: ArrayList path = new ArrayList(); 1132: MenuElement[] array = null; 1133: Component current = leaf.getPopupMenu(); 1134: while (true) 1135: { 1136: if (current instanceof JPopupMenu) 1137: { 1138: JPopupMenu popupMenu = (JPopupMenu) current; 1139: path.add(0, popupMenu); 1140: current = popupMenu.getInvoker(); 1141: } 1142: else if (current instanceof JMenu) 1143: { 1144: JMenu menu = (JMenu) current; 1145: path.add(0, menu); 1146: current = menu.getParent(); 1147: } 1148: else if (current instanceof JMenuBar) 1149: { 1150: JMenuBar menuBar = (JMenuBar) current; 1151: path.add(0, menuBar); 1152: array = new MenuElement[path.size()]; 1153: array = (MenuElement[]) path.toArray(array); 1154: break; 1155: } 1156: } 1157: return array; 1158: } 1159: }