OSDN Git Service

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