001    /* JMenuItem.java --
002       Copyright (C) 2002, 2004, 2005, 2006  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing;
040    
041    import java.awt.Component;
042    import java.awt.event.KeyEvent;
043    import java.awt.event.MouseEvent;
044    import java.beans.PropertyChangeEvent;
045    import java.beans.PropertyChangeListener;
046    import java.util.EventListener;
047    
048    import javax.accessibility.Accessible;
049    import javax.accessibility.AccessibleContext;
050    import javax.accessibility.AccessibleRole;
051    import javax.accessibility.AccessibleState;
052    import javax.swing.event.ChangeEvent;
053    import javax.swing.event.ChangeListener;
054    import javax.swing.event.MenuDragMouseEvent;
055    import javax.swing.event.MenuDragMouseListener;
056    import javax.swing.event.MenuKeyEvent;
057    import javax.swing.event.MenuKeyListener;
058    import javax.swing.plaf.MenuItemUI;
059    
060    /**
061     * JMenuItem represents element in the menu. It inherits most of
062     * its functionality from AbstractButton, however its behavior somewhat
063     * varies from it. JMenuItem fire different kinds of events.
064     * PropertyChangeEvents are fired when menuItems properties are modified;
065     * ChangeEvents are fired when menuItem's state changes and actionEvents are
066     * fired when menu item is selected. In addition to this events menuItem also
067     * fire MenuDragMouseEvent and MenuKeyEvents when mouse is dragged over
068     * the menu item or associated key with menu item is invoked respectively.
069     */
070    public class JMenuItem extends AbstractButton implements Accessible,
071                                                             MenuElement
072    {
073      private static final long serialVersionUID = -1681004643499461044L;
074    
075      /** Combination of keyboard keys that can be used to activate this menu item */
076      private KeyStroke accelerator;
077    
078      /**
079       * Indicates if we are currently dragging the mouse.
080       */
081      private boolean isDragging;
082    
083      /**
084       * Creates a new JMenuItem object.
085       */
086      public JMenuItem()
087      {
088        this(null, null);
089      }
090    
091      /**
092       * Creates a new JMenuItem with the given icon.
093       *
094       * @param icon Icon that will be displayed on the menu item
095       */
096      public JMenuItem(Icon icon)
097      {
098        // FIXME: The requestedFocusEnabled property should
099        // be set to false, when only icon is set for menu item.
100        this(null, icon);
101      }
102    
103      /**
104       * Creates a new JMenuItem with the given label.
105       *
106       * @param text label for the menu item
107       */
108      public JMenuItem(String text)
109      {
110        this(text, null);
111      }
112    
113      /**
114       * Creates a new JMenuItem associated with the specified action.
115       *
116       * @param action action for this menu item
117       */
118      public JMenuItem(Action action)
119      {
120        super();
121        super.setAction(action);
122        setModel(new DefaultButtonModel());
123        init(null, null);
124        if (action != null)
125          {
126            String name = (String) action.getValue(Action.NAME);
127            if (name != null)
128              setName(name);
129    
130            KeyStroke accel = (KeyStroke) action.getValue(Action.ACCELERATOR_KEY);
131            if (accel != null)
132              setAccelerator(accel);
133    
134            Integer mnemonic = (Integer) action.getValue(Action.MNEMONIC_KEY);
135            if (mnemonic != null)
136              setMnemonic(mnemonic.intValue());
137    
138            String command = (String) action.getValue(Action.ACTION_COMMAND_KEY);
139            if (command != null)
140              setActionCommand(command);
141          }
142      }
143    
144      /**
145       * Creates a new JMenuItem with specified text and icon.
146       * Text is displayed to the left of icon by default.
147       *
148       * @param text label for this menu item
149       * @param icon icon that will be displayed on this menu item
150       */
151      public JMenuItem(String text, Icon icon)
152      {
153        super();
154        setModel(new DefaultButtonModel());
155        init(text, icon);
156      }
157    
158      /**
159       * Creates a new JMenuItem object.
160       *
161       * @param text label for this menu item
162       * @param mnemonic - Single key that can be used with a
163       * look-and-feel meta key to activate this menu item. However
164       * menu item should be visible on the screen when mnemonic is used.
165       */
166      public JMenuItem(String text, int mnemonic)
167      {
168        this(text, null);
169        setMnemonic(mnemonic);
170      }
171    
172      /**
173       * Initializes this menu item
174       *
175       * @param text label for this menu item
176       * @param icon icon to be displayed for this menu item
177       */
178      protected void init(String text, Icon icon)
179      {
180        super.init(text, icon);
181    
182        // Initializes properties for this menu item, that are different
183        // from Abstract button properties.
184        /* NOTE: According to java specifications paint_border should be set to false,
185          since menu item should not have a border. However running few java programs
186          it seems that menu items and menues can have a border. Commenting
187          out statement below for now. */
188        //borderPainted = false;
189        focusPainted = false;
190        horizontalAlignment = JButton.LEADING;
191        horizontalTextPosition = JButton.TRAILING;
192      }
193    
194      /**
195       * Set the "UI" property of the menu item, which is a look and feel class
196       * responsible for handling menuItem's input events and painting it.
197       *
198       * @param ui The new "UI" property
199       */
200      public void setUI(MenuItemUI ui)
201      {
202        super.setUI(ui);
203      }
204    
205      /**
206       * This method sets this menuItem's UI to the UIManager's default for the
207       * current look and feel.
208       */
209      public void updateUI()
210      {
211        setUI((MenuItemUI) UIManager.getUI(this));
212      }
213    
214      /**
215       * This method returns a name to identify which look and feel class will be
216       * the UI delegate for the menuItem.
217       *
218       * @return The Look and Feel classID. "MenuItemUI"
219       */
220      public String getUIClassID()
221      {
222        return "MenuItemUI";
223      }
224    
225      /**
226       * Returns true if button's model is armed and false otherwise. The
227       * button model is armed if menu item has focus or it is selected.
228       *
229       * @return $boolean$ true if button's model is armed and false otherwise
230       */
231      public boolean isArmed()
232      {
233        return getModel().isArmed();
234      }
235    
236      /**
237       * Sets menuItem's "ARMED" property
238       *
239       * @param armed DOCUMENT ME!
240       */
241      public void setArmed(boolean armed)
242      {
243        getModel().setArmed(armed);
244      }
245    
246      /**
247       * Enable or disable menu item. When menu item is disabled,
248       * its text and icon are grayed out if they exist.
249       *
250       * @param enabled if true enable menu item, and disable otherwise.
251       */
252      public void setEnabled(boolean enabled)
253      {
254        super.setEnabled(enabled);
255      }
256    
257      /**
258       * Return accelerator for this menu item.
259       *
260       * @return $KeyStroke$ accelerator for this menu item.
261       */
262      public KeyStroke getAccelerator()
263      {
264        return accelerator;
265      }
266    
267      /**
268       * Sets the key combination which invokes the menu item's action
269       * listeners without navigating the menu hierarchy. Note that when the
270       * keyboard accelerator is typed, it will work whether or not the
271       * menu is currently displayed.
272       *
273       * @param keystroke accelerator for this menu item.
274       */
275      public void setAccelerator(KeyStroke keystroke)
276      {
277        KeyStroke old = this.accelerator;
278        this.accelerator = keystroke;
279        firePropertyChange ("accelerator", old, keystroke);
280      }
281    
282      /**
283       * Configures menu items' properties from properties of the specified action.
284       * This method overrides configurePropertiesFromAction from AbstractButton
285       * to also set accelerator property.
286       *
287       * @param action action to configure properties from
288       */
289      protected void configurePropertiesFromAction(Action action)
290      {
291        super.configurePropertiesFromAction(action);
292    
293        if (! (this instanceof JMenu) && action != null)
294          {
295            setAccelerator((KeyStroke) (action.getValue(Action.ACCELERATOR_KEY)));
296            if (accelerator != null)
297              super.registerKeyboardAction(action, accelerator,
298                                           JComponent.WHEN_IN_FOCUSED_WINDOW);
299          }
300      }
301    
302      /**
303       * Creates PropertyChangeListener to listen for the changes in action
304       * properties.
305       *
306       * @param action action to listen to for property changes
307       *
308       * @return $PropertyChangeListener$ Listener that listens to changes in
309       * action properties.
310       */
311      protected PropertyChangeListener createActionPropertyChangeListener(Action action)
312      {
313        return new PropertyChangeListener()
314          {
315            public void propertyChange(PropertyChangeEvent e)
316            {
317              Action act = (Action) (e.getSource());
318              configurePropertiesFromAction(act);
319            }
320          };
321      }
322    
323      /**
324       * Process mouse events forwarded from MenuSelectionManager.
325       *
326       * @param ev event forwarded from MenuSelectionManager
327       * @param path path to the menu element from which event was generated
328       * @param manager MenuSelectionManager for the current menu hierarchy
329       */
330      public void processMouseEvent(MouseEvent ev, MenuElement[] path,
331                                    MenuSelectionManager manager)
332      {
333        MenuDragMouseEvent e = new MenuDragMouseEvent(ev.getComponent(),
334                                                      ev.getID(), ev.getWhen(),
335                                                      ev.getModifiers(), ev.getX(),
336                                                      ev.getY(),
337                                                      ev.getClickCount(),
338                                                      ev.isPopupTrigger(), path,
339                                                      manager);
340        processMenuDragMouseEvent(e);
341      }
342    
343      /**
344       * Process key events forwarded from MenuSelectionManager.
345       *
346       * @param event event forwarded from MenuSelectionManager
347       * @param path path to the menu element from which event was generated
348       * @param manager MenuSelectionManager for the current menu hierarchy
349       */
350      public void processKeyEvent(KeyEvent event, MenuElement[] path,
351                                  MenuSelectionManager manager)
352      {
353        MenuKeyEvent e = new MenuKeyEvent(event.getComponent(), event.getID(),
354                                          event.getWhen(), event.getModifiers(),
355                                          event.getKeyCode(), event.getKeyChar(),
356                                          path, manager);
357        processMenuKeyEvent(e);
358    
359        // Consume original key event, if the menu key event has been consumed.
360        if (e.isConsumed())
361          event.consume();
362      }
363    
364      /**
365       * This method fires MenuDragMouseEvents to registered listeners.
366       * Different types of MenuDragMouseEvents are fired depending
367       * on the observed mouse event.
368       *
369       * @param event Mouse
370       */
371      public void processMenuDragMouseEvent(MenuDragMouseEvent event)
372      {
373        switch (event.getID())
374          {
375          case MouseEvent.MOUSE_ENTERED:
376            isDragging = false;
377            fireMenuDragMouseEntered(event);
378            break;
379          case MouseEvent.MOUSE_EXITED:
380            isDragging = false;
381            fireMenuDragMouseExited(event);
382            break;
383          case MouseEvent.MOUSE_DRAGGED:
384            isDragging = true;
385            fireMenuDragMouseDragged(event);
386            break;
387          case MouseEvent.MOUSE_RELEASED:
388            if (isDragging)
389              fireMenuDragMouseReleased(event);
390            break;
391          }
392      }
393    
394      /**
395       * This method fires MenuKeyEvent to registered listeners.
396       * Different types of MenuKeyEvents are fired depending
397       * on the observed key event.
398       *
399       * @param event DOCUMENT ME!
400       */
401      public void processMenuKeyEvent(MenuKeyEvent event)
402      {
403        switch (event.getID())
404        {
405          case KeyEvent.KEY_PRESSED:
406            fireMenuKeyPressed(event);
407            break;
408          case KeyEvent.KEY_RELEASED:
409            fireMenuKeyReleased(event);
410            break;
411          case KeyEvent.KEY_TYPED:
412            fireMenuKeyTyped(event);
413            break;
414          default:
415            break;
416        }
417      }
418    
419      /**
420       * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners.
421       *
422       * @param event The event signifying that mouse entered menuItem while it was dragged
423       */
424      protected void fireMenuDragMouseEntered(MenuDragMouseEvent event)
425      {
426        EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class);
427    
428        for (int i = 0; i < ll.length; i++)
429          ((MenuDragMouseListener) ll[i]).menuDragMouseEntered(event);
430      }
431    
432      /**
433       * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners.
434       *
435       * @param event The event signifying that mouse has exited menu item, while it was dragged
436       */
437      protected void fireMenuDragMouseExited(MenuDragMouseEvent event)
438      {
439        EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class);
440    
441        for (int i = 0; i < ll.length; i++)
442          ((MenuDragMouseListener) ll[i]).menuDragMouseExited(event);
443      }
444    
445      /**
446       * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners.
447       *
448       * @param event The event signifying that mouse is being dragged over the menuItem
449       */
450      protected void fireMenuDragMouseDragged(MenuDragMouseEvent event)
451      {
452        EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class);
453    
454        for (int i = 0; i < ll.length; i++)
455          ((MenuDragMouseListener) ll[i]).menuDragMouseDragged(event);
456      }
457    
458      /**
459       * This method fires a MenuDragMouseEvent to all the MenuItem's MouseInputListeners.
460       *
461       * @param event The event signifying that mouse was released while it was dragged over the menuItem
462       */
463      protected void fireMenuDragMouseReleased(MenuDragMouseEvent event)
464      {
465        EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class);
466    
467        for (int i = 0; i < ll.length; i++)
468          ((MenuDragMouseListener) ll[i]).menuDragMouseReleased(event);
469      }
470    
471      /**
472       * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners.
473       *
474       * @param event The event signifying that key associated with this menu was pressed
475       */
476      protected void fireMenuKeyPressed(MenuKeyEvent event)
477      {
478        EventListener[] ll = listenerList.getListeners(MenuKeyListener.class);
479    
480        for (int i = 0; i < ll.length; i++)
481          ((MenuKeyListener) ll[i]).menuKeyPressed(event);
482      }
483    
484      /**
485       * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners.
486       *
487       * @param event The event signifying that key associated with this menu was released
488       */
489      protected void fireMenuKeyReleased(MenuKeyEvent event)
490      {
491        EventListener[] ll = listenerList.getListeners(MenuKeyListener.class);
492    
493        for (int i = 0; i < ll.length; i++)
494          ((MenuKeyListener) ll[i]).menuKeyTyped(event);
495      }
496    
497      /**
498       * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners.
499       *
500       * @param event The event signifying that key associated with this menu was typed.
501       *        The key is typed when it was pressed and then released
502       */
503      protected void fireMenuKeyTyped(MenuKeyEvent event)
504      {
505        EventListener[] ll = listenerList.getListeners(MenuKeyListener.class);
506    
507        for (int i = 0; i < ll.length; i++)
508          ((MenuKeyListener) ll[i]).menuKeyTyped(event);
509      }
510    
511      /**
512       * Method of the MenuElement interface.
513       * This method is invoked by MenuSelectionManager when selection of
514       * this menu item has changed. If this menu item was selected then
515       * arm it's model, and disarm the model otherwise. The menu item
516       * is considered to be selected, and thus highlighted when its model
517       * is armed.
518       *
519       * @param changed indicates selection status of this menu item. If changed is
520       * true then menu item is selected and deselected otherwise.
521       */
522      public void menuSelectionChanged(boolean changed)
523      {
524        Component parent = this.getParent();
525        if (changed)
526          {
527            model.setArmed(true);
528    
529            if (parent != null && parent instanceof JPopupMenu)
530              ((JPopupMenu) parent).setSelected(this);
531          }
532        else
533          {
534            model.setArmed(false);
535    
536            if (parent != null && parent instanceof JPopupMenu)
537              ((JPopupMenu) parent).getSelectionModel().clearSelection();
538          }
539      }
540    
541      /**
542       * Method of the MenuElement interface.
543       *
544       * @return $MenuElement[]$ Returns array of sub-components for this menu
545       *         item. By default menuItem doesn't have any subcomponents and so
546       *         empty array is returned instead.
547       */
548      public MenuElement[] getSubElements()
549      {
550        return new MenuElement[0];
551      }
552    
553      /**
554       * Returns reference to the component that will paint this menu item.
555       *
556       * @return $Component$ Component that will paint this menu item.
557       *         Simply returns reference to this menu item.
558       */
559      public Component getComponent()
560      {
561        return this;
562      }
563    
564      /**
565       * Adds a MenuDragMouseListener to this menu item. When mouse
566       * is dragged over the menu item the MenuDragMouseEvents will be
567       * fired, and these listeners will be called.
568       *
569       * @param listener The new listener to add
570       */
571      public void addMenuDragMouseListener(MenuDragMouseListener listener)
572      {
573        listenerList.add(MenuDragMouseListener.class, listener);
574      }
575    
576      /**
577       * Removes a MenuDragMouseListener from the menuItem's listener list.
578       *
579       * @param listener The listener to remove
580       */
581      public void removeMenuDragMouseListener(MenuDragMouseListener listener)
582      {
583        listenerList.remove(MenuDragMouseListener.class, listener);
584      }
585    
586      /**
587       * Returns all added MenuDragMouseListener objects.
588       *
589       * @return an array of listeners
590       *
591       * @since 1.4
592       */
593      public MenuDragMouseListener[] getMenuDragMouseListeners()
594      {
595        return (MenuDragMouseListener[]) listenerList.getListeners(MenuDragMouseListener.class);
596      }
597    
598      /**
599       * Adds an MenuKeyListener to this menu item.  This listener will be
600       * invoked when MenuKeyEvents will be fired by this menu item.
601       *
602       * @param listener The new listener to add
603       */
604      public void addMenuKeyListener(MenuKeyListener listener)
605      {
606        listenerList.add(MenuKeyListener.class, listener);
607      }
608    
609      /**
610       * Removes an MenuKeyListener from the menuItem's listener list.
611       *
612       * @param listener The listener to remove
613       */
614      public void removeMenuKeyListener(MenuKeyListener listener)
615      {
616        listenerList.remove(MenuKeyListener.class, listener);
617      }
618    
619      /**
620       * Returns all added MenuKeyListener objects.
621       *
622       * @return an array of listeners
623       *
624       * @since 1.4
625       */
626      public MenuKeyListener[] getMenuKeyListeners()
627      {
628        return (MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class);
629      }
630    
631      /**
632       * Returns a string describing the attributes for the <code>JMenuItem</code>
633       * component, for use in debugging.  The return value is guaranteed to be
634       * non-<code>null</code>, but the format of the string may vary between
635       * implementations.
636       *
637       * @return A string describing the attributes of the <code>JMenuItem</code>.
638       */
639      protected String paramString()
640      {
641        // calling super seems to be sufficient here...
642        return super.paramString();
643      }
644    
645      /**
646       * Returns the object that provides accessibility features for this
647       * <code>JMenuItem</code> component.
648       *
649       * @return The accessible context (an instance of
650       *     {@link AccessibleJMenuItem}).
651       */
652      public AccessibleContext getAccessibleContext()
653      {
654        if (accessibleContext == null)
655          {
656            AccessibleJMenuItem ctx = new AccessibleJMenuItem();
657            addChangeListener(ctx);
658            accessibleContext = ctx;
659          }
660    
661        return accessibleContext;
662      }
663    
664      /**
665       * Provides the accessibility features for the <code>JMenuItem</code>
666       * component.
667       *
668       * @see JMenuItem#getAccessibleContext()
669       */
670      protected class AccessibleJMenuItem extends AccessibleAbstractButton
671        implements ChangeListener
672      {
673        private static final long serialVersionUID = 6748924232082076534L;
674    
675        private boolean armed;
676        private boolean focusOwner;
677        private boolean pressed;
678        private boolean selected;
679    
680        /**
681         * Creates a new <code>AccessibleJMenuItem</code> instance.
682         */
683        AccessibleJMenuItem()
684        {
685          //super(component);
686        }
687    
688        /**
689         * Receives notification when the menu item's state changes and fires
690         * appropriate property change events to registered listeners.
691         *
692         * @param event the change event
693         */
694        public void stateChanged(ChangeEvent event)
695        {
696          // This is fired in all cases.
697          firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
698                             Boolean.FALSE, Boolean.TRUE);
699    
700          ButtonModel model = getModel();
701    
702          // Handle the armed property.
703          if (model.isArmed())
704            {
705              if (! armed)
706                {
707                  armed = true;
708                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
709                                     AccessibleState.ARMED, null);
710                }
711            }
712          else
713            {
714              if (armed)
715                {
716                  armed = false;
717                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
718                                     null, AccessibleState.ARMED);
719                }
720            }
721    
722          // Handle the pressed property.
723          if (model.isPressed())
724            {
725              if (! pressed)
726                {
727                  pressed = true;
728                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
729                                     AccessibleState.PRESSED, null);
730                }
731            }
732          else
733            {
734              if (pressed)
735                {
736                  pressed = false;
737                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
738                                     null, AccessibleState.PRESSED);
739                }
740            }
741    
742          // Handle the selected property.
743          if (model.isSelected())
744            {
745              if (! selected)
746                {
747                  selected = true;
748                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
749                                     AccessibleState.SELECTED, null);
750                }
751            }
752          else
753            {
754              if (selected)
755                {
756                  selected = false;
757                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
758                                     null, AccessibleState.SELECTED);
759                }
760            }
761    
762          // Handle the focusOwner property.
763          if (isFocusOwner())
764            {
765              if (! focusOwner)
766                {
767                  focusOwner = true;
768                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
769                                     AccessibleState.FOCUSED, null);
770                }
771            }
772          else
773            {
774              if (focusOwner)
775                {
776                  focusOwner = false;
777                  firePropertyChange(AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
778                                     null, AccessibleState.FOCUSED);
779                }
780            }
781        }
782    
783        /**
784         * Returns the accessible role for the <code>JMenuItem</code> component.
785         *
786         * @return {@link AccessibleRole#MENU_ITEM}.
787         */
788        public AccessibleRole getAccessibleRole()
789        {
790          return AccessibleRole.MENU_ITEM;
791        }
792      }
793    
794      /**
795       * Returns <code>true</code> if the component is guaranteed to be painted
796       * on top of others. This returns false by default and is overridden by
797       * components like JMenuItem, JPopupMenu and JToolTip to return true for
798       * added efficiency.
799       *
800       * @return <code>true</code> if the component is guaranteed to be painted
801       *         on top of others
802       */
803      boolean onTop()
804      {
805        return SwingUtilities.getAncestorOfClass(JInternalFrame.class, this)
806               == null;
807      }
808    
809    }