001    /* JPopupMenu.java --
002       Copyright (C) 2002, 2004, 2005  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 gnu.java.lang.CPStringBuilder;
042    
043    import java.awt.Component;
044    import java.awt.Dimension;
045    import java.awt.Insets;
046    import java.awt.Point;
047    import java.awt.event.KeyEvent;
048    import java.awt.event.MouseEvent;
049    import java.beans.PropertyChangeEvent;
050    import java.beans.PropertyChangeListener;
051    import java.util.ArrayList;
052    import java.util.EventListener;
053    
054    import javax.accessibility.Accessible;
055    import javax.accessibility.AccessibleContext;
056    import javax.accessibility.AccessibleRole;
057    import javax.swing.event.MenuKeyListener;
058    import javax.swing.event.PopupMenuEvent;
059    import javax.swing.event.PopupMenuListener;
060    import javax.swing.plaf.PopupMenuUI;
061    
062    /**
063     * JPopupMenu is a container that is used to display popup menu's menu
064     * items. By default JPopupMenu is a lightweight container, however if it
065     * is the case that JPopupMenu's bounds are outside of main window, then
066     * heawyweight container will be used to display menu items. It is also
067     * possible to change JPopupMenu's default  behavior and set JPopupMenu
068     * to always use heavyweight container.
069     *
070     * JPopupMenu can be displayed anywhere; it is a floating free popup menu.
071     * However before JPopupMenu is diplayed, its invoker property should be set.
072     * JPopupMenu's invoker is a component relative to which popup menu is
073     * displayed.
074     *
075     * JPopupMenu fires PopupMenuEvents to its registered listeners. Whenever
076     * JPopupMenu becomes visible on the screen then PopupMenuEvent indicating
077     * that popup menu became visible will be fired. In the case when
078     * JPopupMenu becomes invisible or cancelled without selection, then
079     * popupMenuBecomeInvisible() or popupMenuCancelled() methods of
080     * PopupMenuListeners will be invoked.
081     *
082     * JPopupMenu also fires PropertyChangeEvents when its bound properties 
083     * change.In addittion to inheritted bound properties, JPopupMenu has 
084     * 'visible' bound property. When JPopupMenu becomes visible/invisible on
085     * the screen it fires PropertyChangeEvents to its registered 
086     * PropertyChangeListeners.
087     */
088    public class JPopupMenu extends JComponent implements Accessible, MenuElement
089    {
090      private static final long serialVersionUID = -8336996630009646009L;
091    
092      /* indicates if popup's menu border should be painted*/
093      private boolean borderPainted = true;
094    
095      /** Flag indicating whether lightweight, mediumweight or heavyweight popup
096         is used to display menu items.
097    
098         These are the possible cases:
099    
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       */
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       */
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      */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
364      public boolean isLightWeightPopupEnabled()
365      {
366        return lightWeightPopupEnabled;
367      }
368    
369      /**
370       * DOCUMENT ME!
371       *
372       * @param enabled DOCUMENT ME!
373       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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       */
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      */
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       */
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       */
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       */
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       */
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       */
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       */
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      {
896        public Separator()
897        {
898          super();
899        }
900    
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       */
916      boolean onTop()
917      {
918        return true;
919      }
920    
921      protected class AccessibleJPopupMenu extends AccessibleJComponent
922      {
923        private static final long serialVersionUID = 7423261328879849768L;
924    
925        protected AccessibleJPopupMenu()
926        {
927          // Nothing to do here.
928        }
929    
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      {
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    }