1 /* JPopupMenu.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; 40 41 import gnu.java.lang.CPStringBuilder; 42 43 import java.awt.Component; 44 import java.awt.Dimension; 45 import java.awt.Insets; 46 import java.awt.Point; 47 import java.awt.event.KeyEvent; 48 import java.awt.event.MouseEvent; 49 import java.beans.PropertyChangeEvent; 50 import java.beans.PropertyChangeListener; 51 import java.util.ArrayList; 52 import java.util.EventListener; 53 54 import javax.accessibility.Accessible; 55 import javax.accessibility.AccessibleContext; 56 import javax.accessibility.AccessibleRole; 57 import javax.swing.event.MenuKeyListener; 58 import javax.swing.event.PopupMenuEvent; 59 import javax.swing.event.PopupMenuListener; 60 import javax.swing.plaf.PopupMenuUI; 61 62 /** 63 * JPopupMenu is a container that is used to display popup menu's menu 64 * items. By default JPopupMenu is a lightweight container, however if it 65 * is the case that JPopupMenu's bounds are outside of main window, then 66 * heawyweight container will be used to display menu items. It is also 67 * possible to change JPopupMenu's default behavior and set JPopupMenu 68 * to always use heavyweight container. 69 * 70 * JPopupMenu can be displayed anywhere; it is a floating free popup menu. 71 * However before JPopupMenu is diplayed, its invoker property should be set. 72 * JPopupMenu's invoker is a component relative to which popup menu is 73 * displayed. 74 * 75 * JPopupMenu fires PopupMenuEvents to its registered listeners. Whenever 76 * JPopupMenu becomes visible on the screen then PopupMenuEvent indicating 77 * that popup menu became visible will be fired. In the case when 78 * JPopupMenu becomes invisible or cancelled without selection, then 79 * popupMenuBecomeInvisible() or popupMenuCancelled() methods of 80 * PopupMenuListeners will be invoked. 81 * 82 * JPopupMenu also fires PropertyChangeEvents when its bound properties 83 * change.In addittion to inheritted bound properties, JPopupMenu has 84 * 'visible' bound property. When JPopupMenu becomes visible/invisible on 85 * the screen it fires PropertyChangeEvents to its registered 86 * PropertyChangeListeners. 87 */ 88 public class JPopupMenu extends JComponent implements Accessible, MenuElement 89 { 90 private static final long serialVersionUID = -8336996630009646009L; 91 92 /* indicates if popup's menu border should be painted*/ 93 private boolean borderPainted = true; 94 95 /** Flag indicating whether lightweight, mediumweight or heavyweight popup 96 is used to display menu items. 97 98 These are the possible cases: 99 100 1. if DefaultLightWeightPopupEnabled true 101 (i) use lightweight container if popup feets inside top-level window 102 (ii) only use heavyweight container (JDialog) if popup doesn't fit. 103 104 2. if DefaultLightWeightPopupEnabled false 105 (i) if popup fits, use awt.Panel (mediumWeight) 106 (ii) if popup doesn't fit, use JDialog (heavyWeight) 107 */ 108 private static boolean DefaultLightWeightPopupEnabled = true; 109 110 /* Component that invokes popup menu. */ 111 transient Component invoker; 112 113 /* Label for this popup menu. It is not used in most of the look and feel themes. */ 114 private String label; 115 116 /*Amount of space between menuItem's in JPopupMenu and JPopupMenu's border */ 117 private Insets margin; 118 119 /** Indicates whether ligthWeight container can be used to display popup 120 menu. This flag is the same as DefaultLightWeightPopupEnabled, but setting 121 this flag can change popup menu after creation of the object */ 122 private boolean lightWeightPopupEnabled; 123 124 /** SelectionModel that keeps track of menu selection. */ 125 protected SingleSelectionModel selectionModel; 126 127 /* Popup that is used to display JPopupMenu */ 128 private transient Popup popup; 129 130 /** 131 * Location of the popup, X coordinate. 132 */ 133 private int popupLocationX; 134 135 /** 136 * Location of the popup, Y coordinate. 137 */ 138 private int popupLocationY; 139 140 /* Field indicating if popup menu is visible or not */ 141 private boolean visible = false; 142 143 /** 144 * Creates a new JPopupMenu object. 145 */ JPopupMenu()146 public JPopupMenu() 147 { 148 this(null); 149 } 150 151 /** 152 * Creates a new JPopupMenu with specified label 153 * 154 * @param label Label for popup menu. 155 */ JPopupMenu(String label)156 public JPopupMenu(String label) 157 { 158 lightWeightPopupEnabled = getDefaultLightWeightPopupEnabled(); 159 setLabel(label); 160 setSelectionModel(new DefaultSingleSelectionModel()); 161 super.setVisible(false); 162 updateUI(); 163 } 164 165 /** 166 * Adds given menu item to the popup menu 167 * 168 * @param item menu item to add to the popup menu 169 * 170 * @return menu item that was added to the popup menu 171 */ add(JMenuItem item)172 public JMenuItem add(JMenuItem item) 173 { 174 this.insert(item, -1); 175 return item; 176 } 177 178 /** 179 * Constructs menu item with a specified label and adds it to 180 * popup menu 181 * 182 * @param text label for the menu item to be added 183 * 184 * @return constructed menu item that was added to the popup menu 185 */ add(String text)186 public JMenuItem add(String text) 187 { 188 JMenuItem item = new JMenuItem(text); 189 return add(item); 190 } 191 192 /** 193 * Constructs menu item associated with the specified action 194 * and adds it to the popup menu 195 * 196 * @param action Action for the new menu item 197 * 198 * @return menu item that was added to the menu 199 */ add(Action action)200 public JMenuItem add(Action action) 201 { 202 JMenuItem item = createActionComponent(action); 203 204 if (action != null) 205 action.addPropertyChangeListener(createActionChangeListener(item)); 206 207 return add(item); 208 } 209 210 /** 211 * Revomes component at the given index from the menu. 212 * 213 * @param index index of the component that will be removed in the menu 214 */ remove(int index)215 public void remove(int index) 216 { 217 super.remove(index); 218 revalidate(); 219 } 220 221 /** 222 * Create menu item associated with the given action 223 * and inserts it into the popup menu at the specified index 224 * 225 * @param action Action for the new menu item 226 * @param index index in the popup menu at which to insert new menu item. 227 */ insert(Action action, int index)228 public void insert(Action action, int index) 229 { 230 JMenuItem item = new JMenuItem(action); 231 this.insert(item, index); 232 } 233 234 /** 235 * Insert given component to the popup menu at the 236 * specified index 237 * 238 * @param component Component to insert 239 * @param index Index at which to insert given component 240 */ insert(Component component, int index)241 public void insert(Component component, int index) 242 { 243 super.add(component, index); 244 } 245 246 /** 247 * Returns flag indicating if newly created JPopupMenu will use 248 * heavyweight or lightweight container to display its menu items 249 * 250 * @return true if JPopupMenu will use lightweight container to display 251 * menu items by default, and false otherwise. 252 */ getDefaultLightWeightPopupEnabled()253 public static boolean getDefaultLightWeightPopupEnabled() 254 { 255 return DefaultLightWeightPopupEnabled; 256 } 257 258 /** 259 * Sets whether JPopupMenu should use ligthWeight container to 260 * display it menu items by default 261 * 262 * @param enabled true if JPopupMenu should use lightweight container 263 * for displaying its menu items, and false otherwise. 264 */ setDefaultLightWeightPopupEnabled(boolean enabled)265 public static void setDefaultLightWeightPopupEnabled(boolean enabled) 266 { 267 DefaultLightWeightPopupEnabled = enabled; 268 } 269 270 /** 271 * This method returns the UI used to display the JPopupMenu. 272 * 273 * @return The UI used to display the JPopupMenu. 274 */ getUI()275 public PopupMenuUI getUI() 276 { 277 return (PopupMenuUI) ui; 278 } 279 280 /** 281 * Set the "UI" property of the menu item, which is a look and feel class 282 * responsible for handling popupMenu's input events and painting it. 283 * 284 * @param ui The new "UI" property 285 */ setUI(PopupMenuUI ui)286 public void setUI(PopupMenuUI ui) 287 { 288 super.setUI(ui); 289 } 290 291 /** 292 * This method sets this menuItem's UI to the UIManager's default for the 293 * current look and feel. 294 */ updateUI()295 public void updateUI() 296 { 297 setUI((PopupMenuUI) 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 menuItem. 303 * 304 * @return The Look and Feel classID. "PopupMenuUI" 305 */ getUIClassID()306 public String getUIClassID() 307 { 308 return "PopupMenuUI"; 309 } 310 311 /** 312 * Returns selectionModel used by this popup menu to keep 313 * track of the selection. 314 * 315 * @return popup menu's selection model 316 */ getSelectionModel()317 public SingleSelectionModel getSelectionModel() 318 { 319 return selectionModel; 320 } 321 322 /** 323 * Sets selection model for this popup menu 324 * 325 * @param model new selection model of this popup menu 326 */ setSelectionModel(SingleSelectionModel model)327 public void setSelectionModel(SingleSelectionModel model) 328 { 329 selectionModel = model; 330 } 331 332 /** 333 * Creates new menu item associated with a given action. 334 * 335 * @param action Action used to create new menu item 336 * 337 * @return new created menu item associated with a given action. 338 */ createActionComponent(Action action)339 protected JMenuItem createActionComponent(Action action) 340 { 341 return new JMenuItem(action); 342 } 343 344 /** 345 * Creates PropertyChangeListener that listens to PropertyChangeEvents 346 * occuring in the Action associated with given menu item in this popup menu. 347 * 348 * @param item MenuItem 349 * 350 * @return The PropertyChangeListener 351 */ createActionChangeListener(JMenuItem item)352 protected PropertyChangeListener createActionChangeListener(JMenuItem item) 353 { 354 return new ActionChangeListener(); 355 } 356 357 /** 358 * Returns true if this popup menu will display its menu item in 359 * a lightweight container and false otherwise. 360 * 361 * @return true if this popup menu will display its menu items 362 * in a lightweight container and false otherwise. 363 */ isLightWeightPopupEnabled()364 public boolean isLightWeightPopupEnabled() 365 { 366 return lightWeightPopupEnabled; 367 } 368 369 /** 370 * DOCUMENT ME! 371 * 372 * @param enabled DOCUMENT ME! 373 */ setLightWeightPopupEnabled(boolean enabled)374 public void setLightWeightPopupEnabled(boolean enabled) 375 { 376 lightWeightPopupEnabled = enabled; 377 } 378 379 /** 380 * Returns label for this popup menu 381 * 382 * @return label for this popup menu 383 */ getLabel()384 public String getLabel() 385 { 386 return label; 387 } 388 389 /** 390 * Sets label for this popup menu. This method fires PropertyChangeEvent 391 * when the label property is changed. Please note that most 392 * of the Look & Feel will ignore this property. 393 * 394 * @param label label for this popup menu 395 */ setLabel(String label)396 public void setLabel(String label) 397 { 398 if (label != this.label) 399 { 400 String oldLabel = this.label; 401 this.label = label; 402 firePropertyChange("label", oldLabel, label); 403 } 404 } 405 406 /** 407 * Adds separator to this popup menu 408 */ addSeparator()409 public void addSeparator() 410 { 411 // insert separator at the end of the list of menu items 412 this.insert(new Separator(), -1); 413 } 414 415 /** 416 * Adds a MenuKeyListener to the popup. 417 * 418 * @param l - the listener to add. 419 */ addMenuKeyListener(MenuKeyListener l)420 public void addMenuKeyListener(MenuKeyListener l) 421 { 422 listenerList.add(MenuKeyListener.class, l); 423 } 424 425 /** 426 * Removes a MenuKeyListener from the popup. 427 * 428 * @param l - the listener to remove. 429 */ removeMenuKeyListener(MenuKeyListener l)430 public void removeMenuKeyListener(MenuKeyListener l) 431 { 432 listenerList.remove(MenuKeyListener.class, l); 433 } 434 435 /** 436 * Returns array of getMenuKeyListeners that are listening to JPopupMenu. 437 * 438 * @return array of getMenuKeyListeners that are listening to JPopupMenu 439 */ getMenuKeyListeners()440 public MenuKeyListener[] getMenuKeyListeners() 441 { 442 return ((MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class)); 443 } 444 445 /** 446 * Adds popupMenuListener to listen for PopupMenuEvents fired 447 * by the JPopupMenu 448 * 449 * @param listener PopupMenuListener to add to JPopupMenu 450 */ addPopupMenuListener(PopupMenuListener listener)451 public void addPopupMenuListener(PopupMenuListener listener) 452 { 453 listenerList.add(PopupMenuListener.class, listener); 454 } 455 456 /** 457 * Removes PopupMenuListener from JPopupMenu's list of listeners 458 * 459 * @param listener PopupMenuListener which needs to be removed 460 */ removePopupMenuListener(PopupMenuListener listener)461 public void removePopupMenuListener(PopupMenuListener listener) 462 { 463 listenerList.remove(PopupMenuListener.class, listener); 464 } 465 466 /** 467 * Returns array of PopupMenuListeners that are listening to JPopupMenu 468 * 469 * @return Array of PopupMenuListeners that are listening to JPopupMenu 470 */ getPopupMenuListeners()471 public PopupMenuListener[] getPopupMenuListeners() 472 { 473 return ((PopupMenuListener[]) listenerList.getListeners(PopupMenuListener.class)); 474 } 475 476 /** 477 * This method calls popupMenuWillBecomeVisible() of popup menu's 478 * PopupMenuListeners. This method is invoked just before popup menu 479 * will appear on the screen. 480 */ firePopupMenuWillBecomeVisible()481 protected void firePopupMenuWillBecomeVisible() 482 { 483 EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); 484 485 for (int i = 0; i < ll.length; i++) 486 ((PopupMenuListener) ll[i]).popupMenuWillBecomeVisible(new PopupMenuEvent(this)); 487 } 488 489 /** 490 * This method calls popupMenuWillBecomeInvisible() of popup 491 * menu's PopupMenuListeners. This method is invoked just before popup 492 * menu will disappear from the screen 493 */ firePopupMenuWillBecomeInvisible()494 protected void firePopupMenuWillBecomeInvisible() 495 { 496 EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); 497 498 for (int i = 0; i < ll.length; i++) 499 ((PopupMenuListener) ll[i]).popupMenuWillBecomeInvisible(new PopupMenuEvent(this)); 500 } 501 502 /** 503 * This method calls popupMenuCanceled() of popup menu's PopupMenuListeners. 504 * This method is invoked just before popup menu is cancelled. This happens 505 * when popup menu is closed without selecting any of its menu items. This 506 * usually happens when the top-level window is resized or moved. 507 */ firePopupMenuCanceled()508 protected void firePopupMenuCanceled() 509 { 510 EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); 511 512 for (int i = 0; i < ll.length; i++) 513 ((PopupMenuListener) ll[i]).popupMenuCanceled(new PopupMenuEvent(this)); 514 } 515 516 /** 517 * This methods sets popup menu's size to its' preferred size. If the 518 * popup menu's size is previously set it will be ignored. 519 */ pack()520 public void pack() 521 { 522 // Hook up this call so that it gets executed on the event thread in order 523 // to avoid synchronization problems when calling the layout manager. 524 if (! SwingUtilities.isEventDispatchThread()) 525 { 526 SwingUtilities.invokeLater(new Runnable() 527 { 528 public void run() 529 { 530 show(); 531 } 532 }); 533 } 534 535 setSize(getPreferredSize()); 536 } 537 538 /** 539 * Return visibility of the popup menu 540 * 541 * @return true if popup menu is visible on the screen and false otherwise. 542 */ isVisible()543 public boolean isVisible() 544 { 545 return visible; 546 } 547 548 /** 549 * Sets visibility property of this popup menu. If the property is 550 * set to true then popup menu will be dispayed and popup menu will 551 * hide itself if visible property is set to false. 552 * 553 * @param visible true if popup menu will become visible and false otherwise. 554 */ setVisible(final boolean visible)555 public void setVisible(final boolean visible) 556 { 557 // Hook up this call so that it gets executed on the event thread in order 558 // to avoid synchronization problems when calling the layout manager. 559 if (! SwingUtilities.isEventDispatchThread()) 560 { 561 SwingUtilities.invokeLater(new Runnable() 562 { 563 public void run() 564 { 565 setVisible(visible); 566 } 567 }); 568 } 569 570 if (visible == isVisible()) 571 return; 572 573 boolean old = isVisible(); 574 this.visible = visible; 575 if (old != isVisible()) 576 { 577 if (visible) 578 { 579 if (invoker != null && !(invoker instanceof JMenu)) 580 { 581 MenuElement[] menuEls; 582 if (getSubElements().length > 0) 583 { 584 menuEls = new MenuElement[2]; 585 menuEls[0] = this; 586 menuEls[1] = getSubElements()[0]; 587 } 588 else 589 { 590 menuEls = new MenuElement[1]; 591 menuEls[0] = this; 592 } 593 MenuSelectionManager.defaultManager().setSelectedPath(menuEls); 594 } 595 firePopupMenuWillBecomeVisible(); 596 PopupFactory pf = PopupFactory.getSharedInstance(); 597 pack(); 598 popup = pf.getPopup(invoker, this, popupLocationX, popupLocationY); 599 popup.show(); 600 } 601 else 602 { 603 getSelectionModel().clearSelection(); 604 firePopupMenuWillBecomeInvisible(); 605 popup.hide(); 606 } 607 firePropertyChange("visible", old, isVisible()); 608 } 609 } 610 611 /** 612 * Sets location of the popup menu. 613 * 614 * @param x X coordinate of the popup menu's location 615 * @param y Y coordinate of the popup menu's location 616 */ setLocation(int x, int y)617 public void setLocation(int x, int y) 618 { 619 popupLocationX = x; 620 popupLocationY = y; 621 // Handle the case when the popup is already showing. In this case we need 622 // to fetch a new popup from PopupFactory and use this. See the general 623 // contract of the PopupFactory. 624 } 625 626 /** 627 * Returns popup menu's invoker. 628 * 629 * @return popup menu's invoker 630 */ getInvoker()631 public Component getInvoker() 632 { 633 return invoker; 634 } 635 636 /** 637 * Sets popup menu's invoker. 638 * 639 * @param component The new invoker of this popup menu 640 */ setInvoker(Component component)641 public void setInvoker(Component component) 642 { 643 invoker = component; 644 } 645 646 /** 647 * This method displays JPopupMenu on the screen at the specified 648 * location. Note that x and y coordinates given to this method 649 * should be expressed in terms of the popup menus' invoker. 650 * 651 * @param component Invoker for this popup menu 652 * @param x x-coordinate of the popup menu relative to the specified invoker 653 * @param y y-coordiate of the popup menu relative to the specified invoker 654 */ show(Component component, int x, int y)655 public void show(Component component, int x, int y) 656 { 657 if (component.isShowing()) 658 { 659 setInvoker(component); 660 Point p = new Point(x, y); 661 SwingUtilities.convertPointToScreen(p, component); 662 setLocation(p.x, p.y); 663 setVisible(true); 664 } 665 } 666 667 /** 668 * Returns component located at the specified index in the popup menu 669 * 670 * @param index index of the component to return 671 * 672 * @return component located at the specified index in the popup menu 673 * 674 * @deprecated Replaced by getComponent(int) 675 */ getComponentAtIndex(int index)676 public Component getComponentAtIndex(int index) 677 { 678 return getComponent(index); 679 } 680 681 /** 682 * Returns index of the specified component in the popup menu 683 * 684 * @param component Component to look for 685 * 686 * @return index of the specified component in the popup menu 687 */ getComponentIndex(Component component)688 public int getComponentIndex(Component component) 689 { 690 Component[] items = getComponents(); 691 692 for (int i = 0; i < items.length; i++) 693 { 694 if (items[i].equals(component)) 695 return i; 696 } 697 698 return -1; 699 } 700 701 /** 702 * Sets size of the popup 703 * 704 * @param size Dimensions representing new size of the popup menu 705 */ setPopupSize(Dimension size)706 public void setPopupSize(Dimension size) 707 { 708 super.setSize(size); 709 } 710 711 /** 712 * Sets size of the popup menu 713 * 714 * @param width width for the new size 715 * @param height height for the new size 716 */ setPopupSize(int width, int height)717 public void setPopupSize(int width, int height) 718 { 719 super.setSize(width, height); 720 } 721 722 /** 723 * Selects specified component in this popup menu. 724 * 725 * @param selected component to select 726 */ setSelected(Component selected)727 public void setSelected(Component selected) 728 { 729 int index = getComponentIndex(selected); 730 selectionModel.setSelectedIndex(index); 731 } 732 733 /** 734 * Checks if this popup menu paints its border. 735 * 736 * @return true if this popup menu paints its border and false otherwise. 737 */ isBorderPainted()738 public boolean isBorderPainted() 739 { 740 return borderPainted; 741 } 742 743 /** 744 * Sets if the border of the popup menu should be 745 * painter or not. 746 * 747 * @param painted true if the border should be painted and false otherwise 748 */ setBorderPainted(boolean painted)749 public void setBorderPainted(boolean painted) 750 { 751 borderPainted = painted; 752 } 753 754 /** 755 * Returns margin for this popup menu. 756 * 757 * @return margin for this popup menu. 758 */ getMargin()759 public Insets getMargin() 760 { 761 return margin; 762 } 763 764 /** 765 * A string that describes this JPopupMenu. Normally only used 766 * for debugging. 767 * 768 * @return A string describing this JMenuItem 769 */ paramString()770 protected String paramString() 771 { 772 CPStringBuilder sb = new CPStringBuilder(); 773 sb.append(super.paramString()); 774 sb.append(",label="); 775 if (getLabel() != null) 776 sb.append(getLabel()); 777 sb.append(",lightWeightPopupEnabled=").append(isLightWeightPopupEnabled()); 778 sb.append(",margin="); 779 if (getMargin() != null) 780 sb.append(margin); 781 sb.append(",paintBorder=").append(isBorderPainted()); 782 return sb.toString(); 783 } 784 785 /** 786 * Process mouse events forwarded from MenuSelectionManager. This method 787 * doesn't do anything. It is here to conform to the MenuElement interface. 788 * 789 * @param event event forwarded from MenuSelectionManager 790 * @param path path to the menu element from which event was generated 791 * @param manager MenuSelectionManager for the current menu hierarchy 792 */ processMouseEvent(MouseEvent event, MenuElement[] path, MenuSelectionManager manager)793 public void processMouseEvent(MouseEvent event, MenuElement[] path, 794 MenuSelectionManager manager) 795 { 796 // Empty Implementation. This method is needed for the implementation 797 // of MenuElement interface 798 } 799 800 /** 801 * Process key events forwarded from MenuSelectionManager. This method 802 * doesn't do anything. It is here to conform to the MenuElement interface. 803 * 804 * @param event event forwarded from MenuSelectionManager 805 * @param path path to the menu element from which event was generated 806 * @param manager MenuSelectionManager for the current menu hierarchy 807 * 808 */ processKeyEvent(KeyEvent event, MenuElement[] path, MenuSelectionManager manager)809 public void processKeyEvent(KeyEvent event, MenuElement[] path, 810 MenuSelectionManager manager) 811 { 812 // Empty Implementation. This method is needed for the implementation 813 // of MenuElement interface 814 } 815 816 /** 817 * Method of MenuElement Interface. It is invoked when 818 * popupMenu's selection has changed 819 * 820 * @param changed true if this popupMenu is part of current menu 821 * hierarchy and false otherwise. 822 */ menuSelectionChanged(boolean changed)823 public void menuSelectionChanged(boolean changed) 824 { 825 if (invoker instanceof JMenu) 826 { 827 // We need to special case this since the JMenu calculates the 828 // position etc of the popup. 829 JMenu menu = (JMenu) invoker; 830 menu.setPopupMenuVisible(changed); 831 } 832 else if (! changed) 833 setVisible(false); 834 } 835 836 /** 837 * Return subcomonents of this popup menu. This method returns only 838 * components that implement the <code>MenuElement</code> interface. 839 * 840 * @return array of menu items belonging to this popup menu 841 */ getSubElements()842 public MenuElement[] getSubElements() 843 { 844 Component[] items = getComponents(); 845 ArrayList subElements = new ArrayList(); 846 847 for (int i = 0; i < items.length; i++) 848 if (items[i] instanceof MenuElement) 849 subElements.add(items[i]); 850 851 return (MenuElement[]) 852 subElements.toArray(new MenuElement[subElements.size()]); 853 } 854 855 /** 856 * Method of the MenuElement interface. Returns reference to itself. 857 * 858 * @return Returns reference to itself 859 */ getComponent()860 public Component getComponent() 861 { 862 return this; 863 } 864 865 /** 866 * Checks if observing mouse event should trigger popup 867 * menu to show on the screen. 868 * 869 * @param event MouseEvent to check 870 * 871 * @return true if the observing mouse event is popup trigger and false otherwise 872 */ isPopupTrigger(MouseEvent event)873 public boolean isPopupTrigger(MouseEvent event) 874 { 875 return ((PopupMenuUI) getUI()).isPopupTrigger(event); 876 } 877 878 /** 879 * DOCUMENT ME! 880 * 881 * @return DOCUMENT ME! 882 */ getAccessibleContext()883 public AccessibleContext getAccessibleContext() 884 { 885 if (accessibleContext == null) 886 accessibleContext = new AccessibleJPopupMenu(); 887 888 return accessibleContext; 889 } 890 891 /** 892 * This is the separator that can be used in popup menu. 893 */ 894 public static class Separator extends JSeparator 895 { Separator()896 public Separator() 897 { 898 super(); 899 } 900 getUIClassID()901 public String getUIClassID() 902 { 903 return "PopupMenuSeparatorUI"; 904 } 905 } 906 907 /** 908 * Returns <code>true</code> if the component is guaranteed to be painted 909 * on top of others. This returns false by default and is overridden by 910 * components like JMenuItem, JPopupMenu and JToolTip to return true for 911 * added efficiency. 912 * 913 * @return <code>true</code> if the component is guaranteed to be painted 914 * on top of others 915 */ onTop()916 boolean onTop() 917 { 918 return true; 919 } 920 921 protected class AccessibleJPopupMenu extends AccessibleJComponent 922 { 923 private static final long serialVersionUID = 7423261328879849768L; 924 AccessibleJPopupMenu()925 protected AccessibleJPopupMenu() 926 { 927 // Nothing to do here. 928 } 929 getAccessibleRole()930 public AccessibleRole getAccessibleRole() 931 { 932 return AccessibleRole.POPUP_MENU; 933 } 934 } 935 936 /* This class resizes popup menu and repaints popup menu appropriately if one 937 of item's action has changed */ 938 private class ActionChangeListener implements PropertyChangeListener 939 { propertyChange(PropertyChangeEvent evt)940 public void propertyChange(PropertyChangeEvent evt) 941 { 942 // We used to have a revalidate() and repaint() call here. However I think 943 // this is not needed. Instead, a new Popup has to be fetched from the 944 // PopupFactory and used here. 945 } 946 } 947 } 948