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: throws NotImplementedException 224: { 225: // FIXME: Need to implement 226: } 227: 228: /** 229: * Creates and registers all the listeners for this UI delegate. 230: */ 231: protected void installListeners() 232: { 233: ((JMenu) menuItem).addMouseListener(mouseInputListener); 234: ((JMenu) menuItem).addMouseMotionListener(mouseInputListener); 235: ((JMenu) menuItem).addMenuListener(menuListener); 236: ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener); 237: } 238: 239: protected void setupPostTimer(JMenu menu) 240: { 241: // TODO: Implement this properly. 242: } 243: 244: /** 245: * This method uninstalls the defaults and sets any objects created during 246: * install to null 247: */ 248: protected void uninstallDefaults() 249: { 250: menuItem.setBackground(null); 251: menuItem.setBorder(null); 252: menuItem.setFont(null); 253: menuItem.setForeground(null); 254: menuItem.setMargin(null); 255: acceleratorFont = null; 256: acceleratorForeground = null; 257: acceleratorSelectionForeground = null; 258: selectionBackground = null; 259: selectionForeground = null; 260: arrowIcon = null; 261: } 262: 263: /** 264: * Uninstalls any keyboard actions. The list of keys used are listed in 265: * Basic look and feel's defaults. 266: */ 267: protected void uninstallKeyboardActions() 268: throws NotImplementedException 269: { 270: // FIXME: Need to implement 271: } 272: 273: /** 274: * Unregisters all the listeners that this UI delegate was using. In 275: * addition, it will also null any listeners that it was using. 276: */ 277: protected void uninstallListeners() 278: { 279: ((JMenu) menuItem).removeMouseListener(mouseInputListener); 280: ((JMenu) menuItem).removeMenuListener(menuListener); 281: ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener); 282: } 283: 284: /** 285: * This class is used by menus to handle mouse events occuring in the 286: * menu. 287: */ 288: protected class MouseInputHandler implements MouseInputListener 289: { 290: public void mouseClicked(MouseEvent e) 291: { 292: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 293: manager.processMouseEvent(e); 294: } 295: 296: public void mouseDragged(MouseEvent e) 297: { 298: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 299: manager.processMouseEvent(e); 300: } 301: 302: private boolean popupVisible() 303: { 304: JMenuBar mb = (JMenuBar) ((JMenu) menuItem).getParent(); 305: // check if mb.isSelected because if no menus are selected 306: // we don't have to look through the list for popup menus 307: if (!mb.isSelected()) 308: return false; 309: for (int i = 0; i < mb.getMenuCount(); i++) 310: { 311: JMenu m = mb.getMenu(i); 312: if (m != null && m.isPopupMenuVisible()) 313: return true; 314: } 315: return false; 316: } 317: 318: public void mouseEntered(MouseEvent e) 319: { 320: /* When mouse enters menu item, it should be considered selected 321: 322: if (i) if this menu is a submenu in some other menu 323: (ii) or if this menu is in a menu bar and some other menu in a 324: menu bar was just selected and has its popup menu visible. 325: (If nothing was selected, menu should be pressed before 326: it will be selected) 327: */ 328: JMenu menu = (JMenu) menuItem; 329: 330: // NOTE: the following if used to require !menu.isArmed but I could find 331: // no reason for this and it was preventing some JDK-compatible behaviour. 332: // Specifically, if a menu is selected but its popup menu not visible, 333: // and then another menu is selected whose popup menu IS visible, when 334: // the mouse is moved over the first menu, its popup menu should become 335: // visible. 336: 337: if (! menu.isTopLevelMenu() || popupVisible()) 338: { 339: // set new selection and forward this event to MenuSelectionManager 340: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 341: manager.setSelectedPath(getPath()); 342: manager.processMouseEvent(e); 343: } 344: } 345: 346: public void mouseExited(MouseEvent e) 347: { 348: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 349: manager.processMouseEvent(e); 350: } 351: 352: public void mouseMoved(MouseEvent e) 353: { 354: // TODO: What should be done here, if anything? 355: } 356: 357: public void mousePressed(MouseEvent e) 358: { 359: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 360: JMenu menu = (JMenu) menuItem; 361: manager.processMouseEvent(e); 362: 363: // Menu should be displayed when the menu is pressed only if 364: // it is top-level menu 365: if (menu.isTopLevelMenu()) 366: { 367: if (menu.getPopupMenu().isVisible()) 368: // If menu is visible and menu button was pressed.. 369: // then need to cancel the menu 370: manager.clearSelectedPath(); 371: else 372: { 373: // Display the menu 374: int x = 0; 375: int y = menu.getHeight(); 376: 377: manager.setSelectedPath(getPath()); 378: 379: JMenuBar mb = (JMenuBar) menu.getParent(); 380: 381: // set selectedIndex of the selectionModel of a menuBar 382: mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu)); 383: } 384: } 385: } 386: 387: public void mouseReleased(MouseEvent e) 388: { 389: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 390: manager.processMouseEvent(e); 391: } 392: } 393: 394: /** 395: * This class handles MenuEvents fired by the JMenu 396: */ 397: private class MenuHandler implements MenuListener 398: { 399: /** 400: * This method is called when menu is cancelled. The menu is cancelled 401: * when its popup menu is closed without selection. It clears selected index 402: * in the selectionModel of the menu parent. 403: * 404: * @param e The MenuEvent. 405: */ 406: public void menuCanceled(MenuEvent e) 407: { 408: menuDeselected(e); 409: } 410: 411: /** 412: * This method is called when menu is deselected. It clears selected index 413: * in the selectionModel of the menu parent. 414: * 415: * @param e The MenuEvent. 416: */ 417: public void menuDeselected(MenuEvent e) 418: { 419: JMenu menu = (JMenu) menuItem; 420: if (menu.getParent() != null) 421: { 422: if (menu.isTopLevelMenu()) 423: ((JMenuBar) menu.getParent()).getSelectionModel().clearSelection(); 424: else 425: ((JPopupMenu) menu.getParent()).getSelectionModel().clearSelection(); 426: } 427: } 428: 429: /** 430: * This method is called when menu is selected. It sets selected index 431: * in the selectionModel of the menu parent. 432: * 433: * @param e The MenuEvent. 434: */ 435: public void menuSelected(MenuEvent e) 436: { 437: JMenu menu = (JMenu) menuItem; 438: if (menu.isTopLevelMenu()) 439: ((JMenuBar) menu.getParent()).setSelected(menu); 440: else 441: ((JPopupMenu) menu.getParent()).setSelected(menu); 442: } 443: } 444: 445: /** 446: * Obsolete as of JDK1.4. 447: */ 448: public class ChangeHandler implements ChangeListener 449: { 450: /** 451: * Not used. 452: */ 453: public boolean isSelected; 454: 455: /** 456: * Not used. 457: */ 458: public JMenu menu; 459: 460: /** 461: * Not used. 462: */ 463: public BasicMenuUI ui; 464: 465: /** 466: * Not used. 467: */ 468: public Component wasFocused; 469: 470: /** 471: * Not used. 472: */ 473: public ChangeHandler(JMenu m, BasicMenuUI ui) 474: { 475: // Not used. 476: } 477: 478: /** 479: * Not used. 480: */ 481: public void stateChanged(ChangeEvent e) 482: { 483: // Not used. 484: } 485: } 486: 487: /** 488: * This class handles mouse dragged events occuring in the menu. 489: */ 490: private class MenuDragMouseHandler implements MenuDragMouseListener 491: { 492: /** 493: * This method is invoked when mouse is dragged over the menu item. 494: * 495: * @param e The MenuDragMouseEvent 496: */ 497: public void menuDragMouseDragged(MenuDragMouseEvent e) 498: { 499: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 500: manager.setSelectedPath(e.getPath()); 501: } 502: 503: /** 504: * This method is invoked when mouse enters the menu item while it is 505: * being dragged. 506: * 507: * @param e The MenuDragMouseEvent 508: */ 509: public void menuDragMouseEntered(MenuDragMouseEvent e) 510: { 511: MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 512: manager.setSelectedPath(e.getPath()); 513: } 514: 515: /** 516: * This method is invoked when mouse exits the menu item while 517: * it is being dragged 518: * 519: * @param e The MenuDragMouseEvent 520: */ 521: public void menuDragMouseExited(MenuDragMouseEvent e) 522: { 523: // TODO: What should be done here, if anything? 524: } 525: 526: /** 527: * This method is invoked when mouse was dragged and released 528: * inside the menu item. 529: * 530: * @param e The MenuDragMouseEvent 531: */ 532: public void menuDragMouseReleased(MenuDragMouseEvent e) 533: { 534: // TODO: What should be done here, if anything? 535: } 536: } 537: 538: /** 539: * This class handles key events occuring when menu item is visible on the 540: * screen. 541: */ 542: private class MenuKeyHandler implements MenuKeyListener 543: { 544: /** 545: * This method is invoked when key has been pressed 546: * 547: * @param e A {@link MenuKeyEvent}. 548: */ 549: public void menuKeyPressed(MenuKeyEvent e) 550: { 551: // TODO: What should be done here, if anything? 552: } 553: 554: /** 555: * This method is invoked when key has been pressed 556: * 557: * @param e A {@link MenuKeyEvent}. 558: */ 559: public void menuKeyReleased(MenuKeyEvent e) 560: { 561: // TODO: What should be done here, if anything? 562: } 563: 564: /** 565: * This method is invoked when key has been typed 566: * It handles the mnemonic key for the menu item. 567: * 568: * @param e A {@link MenuKeyEvent}. 569: */ 570: public void menuKeyTyped(MenuKeyEvent e) 571: { 572: // TODO: What should be done here, if anything? 573: } 574: } 575: }