Frames | No Frames |
1: /* BasicMenuUI.java 2: Copyright (C) 2002, 2004, 2005 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.plaf.basic; 40: 41: import gnu.classpath.NotImplementedException; 42: 43: import java.awt.Component; 44: import java.awt.Dimension; 45: import java.awt.event.MouseEvent; 46: import java.beans.PropertyChangeListener; 47: 48: import javax.swing.JComponent; 49: import javax.swing.JMenu; 50: import javax.swing.JMenuBar; 51: import javax.swing.JPopupMenu; 52: import javax.swing.LookAndFeel; 53: import javax.swing.MenuSelectionManager; 54: import javax.swing.UIDefaults; 55: import javax.swing.UIManager; 56: import javax.swing.event.ChangeEvent; 57: import javax.swing.event.ChangeListener; 58: import javax.swing.event.MenuDragMouseEvent; 59: import javax.swing.event.MenuDragMouseListener; 60: import javax.swing.event.MenuEvent; 61: import javax.swing.event.MenuKeyEvent; 62: import javax.swing.event.MenuKeyListener; 63: import javax.swing.event.MenuListener; 64: import javax.swing.event.MouseInputListener; 65: import javax.swing.plaf.ComponentUI; 66: 67: /** 68: * UI Delegate for JMenu 69: */ 70: public class BasicMenuUI extends BasicMenuItemUI 71: { 72: protected ChangeListener changeListener; 73: 74: /* MenuListener listens to MenuEvents fired by JMenu */ 75: protected MenuListener menuListener; 76: 77: /* PropertyChangeListner that listens to propertyChangeEvents occuring in JMenu*/ 78: protected PropertyChangeListener propertyChangeListener; 79: 80: /** 81: * Creates a new BasicMenuUI object. 82: */ 83: public BasicMenuUI() 84: { 85: mouseInputListener = createMouseInputListener((JMenu) menuItem); 86: menuListener = createMenuListener((JMenu) menuItem); 87: propertyChangeListener = createPropertyChangeListener((JMenu) menuItem); 88: } 89: 90: /** 91: * This method creates a new ChangeListener. 92: * 93: * @return A new ChangeListener. 94: */ 95: protected ChangeListener createChangeListener(JComponent c) 96: { 97: return new ChangeHandler((JMenu) c, this); 98: } 99: 100: /** 101: * This method creates new MenuDragMouseListener to listen to mouse dragged events 102: * occuring in the Menu 103: * 104: * @param c the menu to listen to 105: * 106: * @return The MenuDrageMouseListener 107: */ 108: protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) 109: { 110: return new MenuDragMouseHandler(); 111: } 112: 113: /** 114: * This method creates new MenuDragKeyListener to listen to key events 115: * 116: * @param c the menu to listen to 117: * 118: * @return The MenuKeyListener 119: */ 120: protected MenuKeyListener createMenuKeyListener(JComponent c) 121: { 122: return new MenuKeyHandler(); 123: } 124: 125: /** 126: * This method creates new MenuListener to listen to menu events 127: * occuring in the Menu 128: * 129: * @param c the menu to listen to 130: * 131: * @return The MenuListener 132: */ 133: protected MenuListener createMenuListener(JComponent c) 134: { 135: return new MenuHandler(); 136: } 137: 138: /** 139: * This method creates new MouseInputListener to listen to mouse input events 140: * occuring in the Menu 141: * 142: * @param c the menu to listen to 143: * 144: * @return The MouseInputListener 145: */ 146: protected MouseInputListener createMouseInputListener(JComponent c) 147: { 148: return new MouseInputHandler(); 149: } 150: 151: /** 152: * This method creates newPropertyChangeListener to listen to property changes 153: * occuring in the Menu 154: * 155: * @param c the menu to listen to 156: * 157: * @return The PropertyChangeListener 158: */ 159: protected PropertyChangeListener createPropertyChangeListener(JComponent c) 160: { 161: return new PropertyChangeHandler(); 162: } 163: 164: /** 165: * This method creates a new BasicMenuUI. 166: * 167: * @param c The JComponent to create a UI for. 168: * 169: * @return A new BasicMenuUI. 170: */ 171: public static ComponentUI createUI(JComponent c) 172: { 173: return new BasicMenuUI(); 174: } 175: 176: /** 177: * Get the component's maximum size. 178: * 179: * @param c The JComponent for which to get maximum size 180: * 181: * @return The maximum size of the component 182: */ 183: public Dimension getMaximumSize(JComponent c) 184: { 185: return c.getPreferredSize(); 186: } 187: 188: /** 189: * Returns the prefix for entries in the {@link UIDefaults} table. 190: * 191: * @return "Menu" 192: */ 193: protected String getPropertyPrefix() 194: { 195: return "Menu"; 196: } 197: 198: /** 199: * Initializes any default properties that this UI has from the defaults for 200: * the Basic look and feel. 201: */ 202: protected void installDefaults() 203: { 204: LookAndFeel.installBorder(menuItem, "Menu.border"); 205: LookAndFeel.installColorsAndFont(menuItem, "Menu.background", 206: "Menu.foreground", "Menu.font"); 207: menuItem.setMargin(UIManager.getInsets("Menu.margin")); 208: acceleratorFont = UIManager.getFont("Menu.acceleratorFont"); 209: acceleratorForeground = UIManager.getColor("Menu.acceleratorForeground"); 210: acceleratorSelectionForeground = UIManager.getColor("Menu.acceleratorSelectionForeground"); 211: selectionBackground = UIManager.getColor("Menu.selectionBackground"); 212: selectionForeground = UIManager.getColor("Menu.selectionForeground"); 213: arrowIcon = UIManager.getIcon("Menu.arrowIcon"); 214: oldBorderPainted = UIManager.getBoolean("Menu.borderPainted"); 215: } 216: 217: /** 218: * Installs any keyboard actions. The list of keys that need to be bound are 219: * listed in Basic look and feel's defaults. 220: * 221: */ 222: protected void installKeyboardActions() 223: { 224: super.installKeyboardActions(); 225: } 226: 227: /** 228: * Creates and registers all the listeners for this UI delegate. 229: */ 230: protected void installListeners() 231: { 232: super.installListeners(); 233: ((JMenu) menuItem).addMenuListener(menuListener); 234: } 235: 236: protected void setupPostTimer(JMenu menu) 237: throws NotImplementedException 238: { 239: // TODO: Implement this properly. 240: } 241: 242: /** 243: * This method uninstalls the defaults and sets any objects created during 244: * install to null 245: */ 246: protected void uninstallDefaults() 247: { 248: menuItem.setBackground(null); 249: menuItem.setBorder(null); 250: menuItem.setFont(null); 251: menuItem.setForeground(null); 252: menuItem.setMargin(null); 253: acceleratorFont = null; 254: acceleratorForeground = null; 255: acceleratorSelectionForeground = null; 256: selectionBackground = null; 257: selectionForeground = null; 258: arrowIcon = null; 259: } 260: 261: /** 262: * Uninstalls any keyboard actions. The list of keys used are listed in 263: * Basic look and feel's defaults. 264: */ 265: protected void uninstallKeyboardActions() 266: { 267: super.installKeyboardActions(); 268: } 269: 270: /** 271: * Unregisters all the listeners that this UI delegate was using. In 272: * addition, it will also null any listeners that it was using. 273: */ 274: protected void uninstallListeners() 275: { 276: super.uninstallListeners(); 277: ((JMenu) menuItem).removeMenuListener(menuListener); 278: } 279: 280: /** 281: * This class is used by menus to handle mouse events occuring in the 282: * menu. 283: */ 284: protected class MouseInputHandler implements MouseInputListener 285: { 286: public void mouseClicked(MouseEvent e) 287: { 288: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 289: manager.processMouseEvent(e); 290: } 291: 292: public void mouseDragged(MouseEvent e) 293: { 294: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 295: manager.processMouseEvent(e); 296: } 297: 298: private boolean popupVisible() 299: { 300: JMenuBar mb = (JMenuBar) ((JMenu) menuItem).getParent(); 301: // check if mb.isSelected because if no menus are selected 302: // we don't have to look through the list for popup menus 303: if (!mb.isSelected()) 304: return false; 305: for (int i = 0; i < mb.getMenuCount(); i++) 306: { 307: JMenu m = mb.getMenu(i); 308: if (m != null && m.isPopupMenuVisible()) 309: return true; 310: } 311: return false; 312: } 313: 314: public void mouseEntered(MouseEvent e) 315: { 316: /* When mouse enters menu item, it should be considered selected 317: 318: if (i) if this menu is a submenu in some other menu 319: (ii) or if this menu is in a menu bar and some other menu in a 320: menu bar was just selected and has its popup menu visible. 321: (If nothing was selected, menu should be pressed before 322: it will be selected) 323: */ 324: JMenu menu = (JMenu) menuItem; 325: 326: // NOTE: the following if used to require !menu.isArmed but I could find 327: // no reason for this and it was preventing some JDK-compatible behaviour. 328: // Specifically, if a menu is selected but its popup menu not visible, 329: // and then another menu is selected whose popup menu IS visible, when 330: // the mouse is moved over the first menu, its popup menu should become 331: // visible. 332: 333: if (! menu.isTopLevelMenu() || popupVisible()) 334: { 335: // set new selection and forward this event to MenuSelectionManager 336: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 337: manager.setSelectedPath(getPath()); 338: manager.processMouseEvent(e); 339: } 340: } 341: 342: public void mouseExited(MouseEvent e) 343: { 344: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 345: manager.processMouseEvent(e); 346: } 347: 348: public void mouseMoved(MouseEvent e) 349: { 350: // Nothing to do here. 351: } 352: 353: public void mousePressed(MouseEvent e) 354: { 355: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 356: JMenu menu = (JMenu) menuItem; 357: manager.processMouseEvent(e); 358: 359: // Menu should be displayed when the menu is pressed only if 360: // it is top-level menu 361: if (menu.isTopLevelMenu()) 362: { 363: if (menu.getPopupMenu().isVisible()) 364: // If menu is visible and menu button was pressed.. 365: // then need to cancel the menu 366: manager.clearSelectedPath(); 367: else 368: { 369: // Display the menu 370: int x = 0; 371: int y = menu.getHeight(); 372: 373: manager.setSelectedPath(getPath()); 374: 375: JMenuBar mb = (JMenuBar) menu.getParent(); 376: 377: // set selectedIndex of the selectionModel of a menuBar 378: mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu)); 379: } 380: } 381: } 382: 383: public void mouseReleased(MouseEvent e) 384: { 385: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 386: manager.processMouseEvent(e); 387: } 388: } 389: 390: /** 391: * This class handles MenuEvents fired by the JMenu 392: */ 393: private class MenuHandler implements MenuListener 394: { 395: /** 396: * This method is called when menu is cancelled. The menu is cancelled 397: * when its popup menu is closed without selection. It clears selected index 398: * in the selectionModel of the menu parent. 399: * 400: * @param e The MenuEvent. 401: */ 402: public void menuCanceled(MenuEvent e) 403: { 404: menuDeselected(e); 405: } 406: 407: /** 408: * This method is called when menu is deselected. It clears selected index 409: * in the selectionModel of the menu parent. 410: * 411: * @param e The MenuEvent. 412: */ 413: public void menuDeselected(MenuEvent e) 414: { 415: JMenu menu = (JMenu) menuItem; 416: if (menu.getParent() != null) 417: { 418: if (menu.isTopLevelMenu()) 419: ((JMenuBar) menu.getParent()).getSelectionModel().clearSelection(); 420: else 421: ((JPopupMenu) menu.getParent()).getSelectionModel().clearSelection(); 422: } 423: } 424: 425: /** 426: * This method is called when menu is selected. It sets selected index 427: * in the selectionModel of the menu parent. 428: * 429: * @param e The MenuEvent. 430: */ 431: public void menuSelected(MenuEvent e) 432: { 433: JMenu menu = (JMenu) menuItem; 434: if (menu.isTopLevelMenu()) 435: ((JMenuBar) menu.getParent()).setSelected(menu); 436: else 437: ((JPopupMenu) menu.getParent()).setSelected(menu); 438: } 439: } 440: 441: /** 442: * Obsolete as of JDK1.4. 443: */ 444: public class ChangeHandler implements ChangeListener 445: { 446: /** 447: * Not used. 448: */ 449: public boolean isSelected; 450: 451: /** 452: * Not used. 453: */ 454: public JMenu menu; 455: 456: /** 457: * Not used. 458: */ 459: public BasicMenuUI ui; 460: 461: /** 462: * Not used. 463: */ 464: public Component wasFocused; 465: 466: /** 467: * Not used. 468: */ 469: public ChangeHandler(JMenu m, BasicMenuUI ui) 470: { 471: menu = m; 472: this.ui = ui; 473: } 474: 475: /** 476: * Not used. 477: */ 478: public void stateChanged(ChangeEvent e) 479: { 480: // Not used. 481: } 482: } 483: 484: /** 485: * This class handles mouse dragged events occuring in the menu. 486: */ 487: private class MenuDragMouseHandler implements MenuDragMouseListener 488: { 489: /** 490: * This method is invoked when mouse is dragged over the menu item. 491: * 492: * @param e The MenuDragMouseEvent 493: */ 494: public void menuDragMouseDragged(MenuDragMouseEvent e) 495: { 496: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 497: manager.setSelectedPath(e.getPath()); 498: } 499: 500: /** 501: * This method is invoked when mouse enters the menu item while it is 502: * being dragged. 503: * 504: * @param e The MenuDragMouseEvent 505: */ 506: public void menuDragMouseEntered(MenuDragMouseEvent e) 507: { 508: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 509: manager.setSelectedPath(e.getPath()); 510: } 511: 512: /** 513: * This method is invoked when mouse exits the menu item while 514: * it is being dragged 515: * 516: * @param e The MenuDragMouseEvent 517: */ 518: public void menuDragMouseExited(MenuDragMouseEvent e) 519: { 520: // Nothing to do here. 521: } 522: 523: /** 524: * This method is invoked when mouse was dragged and released 525: * inside the menu item. 526: * 527: * @param e The MenuDragMouseEvent 528: */ 529: public void menuDragMouseReleased(MenuDragMouseEvent e) 530: { 531: // Nothing to do here. 532: } 533: } 534: 535: /** 536: * This class handles key events occuring when menu item is visible on the 537: * screen. 538: */ 539: private class MenuKeyHandler implements MenuKeyListener 540: { 541: /** 542: * This method is invoked when key has been pressed 543: * 544: * @param e A {@link MenuKeyEvent}. 545: */ 546: public void menuKeyPressed(MenuKeyEvent e) 547: { 548: // Nothing to do here. 549: } 550: 551: /** 552: * This method is invoked when key has been pressed 553: * 554: * @param e A {@link MenuKeyEvent}. 555: */ 556: public void menuKeyReleased(MenuKeyEvent e) 557: { 558: // Nothing to do here. 559: } 560: 561: /** 562: * This method is invoked when key has been typed 563: * It handles the mnemonic key for the menu item. 564: * 565: * @param e A {@link MenuKeyEvent}. 566: */ 567: public void menuKeyTyped(MenuKeyEvent e) 568: throws NotImplementedException 569: { 570: // TODO: What should be done here, if anything? 571: } 572: } 573: }