68 |
|
|
69 |
|
|
70 |
/** |
/** |
71 |
* DOCUMENT ME! |
* JPopupMenu is a container that is used to display popup menu's menu |
72 |
|
* items. By default JPopupMenu is a lightweight container, however if it |
73 |
|
* is the case that JPopupMenu's bounds are outside of main window, then |
74 |
|
* heawyweight container will be used to display menu items. It is also |
75 |
|
* possible to change JPopupMenu's default behavior and set JPopupMenu |
76 |
|
* to always use heavyweight container. |
77 |
|
* |
78 |
|
* JPopupMenu can be displayed anywhere; it is a floating free popup menu. |
79 |
|
* However before JPopupMenu is diplayed, its invoker property should be set. |
80 |
|
* JPopupMenu's invoker is a component relative to which popup menu is |
81 |
|
* displayed. |
82 |
|
* |
83 |
|
* JPopupMenu fires PopupMenuEvents to its registered listeners. Whenever |
84 |
|
* JPopupMenu becomes visible on the screen then PopupMenuEvent indicating |
85 |
|
* that popup menu became visible will be fired. In the case when |
86 |
|
* JPopupMenu becomes invisible or cancelled without selection, then |
87 |
|
* popupMenuBecomeInvisible() or popupMenuCancelled() methods of |
88 |
|
* PopupMenuListeners will be invoked. |
89 |
|
* |
90 |
|
* JPopupMenu also fires PropertyChangeEvents when its bound properties |
91 |
|
* change.In addittion to inheritted bound properties, JPopupMenu has |
92 |
|
* 'visible' bound property. When JPopupMenu becomes visible/invisible on |
93 |
|
* the screen it fires PropertyChangeEvents to its registered |
94 |
|
* PropertyChangeListeners. |
95 |
*/ |
*/ |
96 |
public class JPopupMenu extends JComponent implements Accessible, MenuElement |
public class JPopupMenu extends JComponent implements Accessible, MenuElement |
97 |
{ |
{ |
100 |
/** name for the UI delegate for this menuItem. */ |
/** name for the UI delegate for this menuItem. */ |
101 |
private static final String uiClassID = "PopupMenuUI"; |
private static final String uiClassID = "PopupMenuUI"; |
102 |
|
|
103 |
|
/** Fire a PropertyChangeEvent when the "borderPainted" property changes. */ |
104 |
|
public static final String LABEL_CHANGED_PROPERTY = "label"; |
105 |
|
|
106 |
/* indicates if popup's menu border should be painted*/ |
/* indicates if popup's menu border should be painted*/ |
107 |
private boolean borderPainted = true; |
private boolean borderPainted = true; |
108 |
|
|
124 |
/* Component that invokes popup menu. */ |
/* Component that invokes popup menu. */ |
125 |
transient Component invoker; |
transient Component invoker; |
126 |
|
|
127 |
/* Label for this popup menu */ |
/* Label for this popup menu. It is not used in most of the look and feel themes. */ |
128 |
private String label; |
private String label; |
129 |
|
|
130 |
/*Amount of space between menuItem's in JPopupMenu and JPopupMenu's border */ |
/*Amount of space between menuItem's in JPopupMenu and JPopupMenu's border */ |
156 |
|
|
157 |
lightWeightPopupEnabled = DefaultLightWeightPopupEnabled; |
lightWeightPopupEnabled = DefaultLightWeightPopupEnabled; |
158 |
selectionModel = new DefaultSingleSelectionModel(); |
selectionModel = new DefaultSingleSelectionModel(); |
|
|
|
159 |
super.setVisible(false); |
super.setVisible(false); |
160 |
} |
} |
161 |
|
|
166 |
*/ |
*/ |
167 |
public JPopupMenu(String label) |
public JPopupMenu(String label) |
168 |
{ |
{ |
169 |
this.label = label; |
setLabel(label); |
170 |
} |
} |
171 |
|
|
|
/** |
|
|
* DOCUMENT ME! |
|
|
* |
|
|
* @param stream DOCUMENT ME! |
|
|
* |
|
|
* @throws IOException DOCUMENT ME! |
|
|
* @throws ClassNotFoundException DOCUMENT ME! |
|
|
*/ |
|
172 |
private void readObject(ObjectInputStream stream) |
private void readObject(ObjectInputStream stream) |
173 |
throws IOException, ClassNotFoundException |
throws IOException, ClassNotFoundException |
174 |
{ |
{ |
175 |
} |
} |
176 |
|
|
|
/** |
|
|
* DOCUMENT ME! |
|
|
* |
|
|
* @param stream DOCUMENT ME! |
|
|
* |
|
|
* @throws IOException DOCUMENT ME! |
|
|
*/ |
|
177 |
private void writeObject(ObjectOutputStream stream) throws IOException |
private void writeObject(ObjectOutputStream stream) throws IOException |
178 |
{ |
{ |
179 |
} |
} |
215 |
*/ |
*/ |
216 |
public JMenuItem add(Action action) |
public JMenuItem add(Action action) |
217 |
{ |
{ |
218 |
JMenuItem item = new JMenuItem(action); |
JMenuItem item = createActionComponent(action); |
219 |
|
|
220 |
if (action != null) |
if (action != null) |
221 |
action.addPropertyChangeListener(createActionChangeListener(item)); |
action.addPropertyChangeListener(createActionChangeListener(item)); |
233 |
super.remove(index); |
super.remove(index); |
234 |
|
|
235 |
GridBagConstraints constraints = new GridBagConstraints(); |
GridBagConstraints constraints = new GridBagConstraints(); |
236 |
constraints.fill = GridBagConstraints.HORIZONTAL; |
constraints.fill = GridBagConstraints.BOTH; |
237 |
constraints.weightx = 100.0; |
constraints.weightx = 100.0; |
238 |
constraints.weighty = 100.0; |
constraints.weighty = 100.0; |
239 |
|
|
268 |
public void insert(Component component, int index) |
public void insert(Component component, int index) |
269 |
{ |
{ |
270 |
GridBagConstraints constraints = new GridBagConstraints(); |
GridBagConstraints constraints = new GridBagConstraints(); |
271 |
constraints.fill = GridBagConstraints.HORIZONTAL; |
constraints.fill = GridBagConstraints.BOTH; |
272 |
constraints.weightx = 100.0; |
constraints.weightx = 100.0; |
273 |
constraints.weighty = 100.0; |
constraints.weighty = 100.0; |
274 |
|
|
395 |
} |
} |
396 |
|
|
397 |
/** |
/** |
398 |
* DOCUMENT ME! |
* Creates new menu item associated with a given action. |
399 |
* |
* |
400 |
* @param action DOCUMENT ME! |
* @param action Action used to create new menu item |
401 |
* |
* |
402 |
* @return DOCUMENT ME! |
* @return new created menu item associated with a given action. |
403 |
*/ |
*/ |
404 |
protected JMenuItem createActionComponent(Action action) |
protected JMenuItem createActionComponent(Action action) |
405 |
{ |
{ |
406 |
return null; |
return new JMenuItem(action); |
407 |
} |
} |
408 |
|
|
409 |
/** |
/** |
410 |
* DOCUMENT ME! |
* Creates PropertyChangeListener that listens to PropertyChangeEvents |
411 |
|
* occuring in the Action associated with given menu item in this popup menu. |
412 |
* |
* |
413 |
* @param item DOCUMENT ME! |
* @param item MenuItem |
414 |
* |
* |
415 |
* @return DOCUMENT ME! |
* @return The PropertyChangeListener |
416 |
*/ |
*/ |
417 |
protected PropertyChangeListener createActionChangeListener(JMenuItem item) |
protected PropertyChangeListener createActionChangeListener(JMenuItem item) |
418 |
{ |
{ |
419 |
return null; |
return new ActionChangeListener(); |
420 |
} |
} |
421 |
|
|
422 |
/** |
/** |
452 |
} |
} |
453 |
|
|
454 |
/** |
/** |
455 |
* Sets label for this popup menu |
* Sets label for this popup menu. This method fires PropertyChangeEvent |
456 |
|
* when the label property is changed. Please note that most |
457 |
|
* of the Look & Feel will ignore this property. |
458 |
* |
* |
459 |
* @param label label for this popup menu |
* @param label label for this popup menu |
460 |
*/ |
*/ |
461 |
public void setLabel(String label) |
public void setLabel(String label) |
462 |
{ |
{ |
463 |
|
if (label != this.label) |
464 |
|
{ |
465 |
|
String oldLabel = this.label; |
466 |
this.label = label; |
this.label = label; |
467 |
|
firePropertyChange(LABEL_CHANGED_PROPERTY, oldLabel, label); |
468 |
|
} |
469 |
} |
} |
470 |
|
|
471 |
/** |
/** |
594 |
size = this.getPreferredSize(); |
size = this.getPreferredSize(); |
595 |
else |
else |
596 |
size = this.getSize(); |
size = this.getSize(); |
597 |
|
|
598 |
if ((size.width > (rootContainer.getWidth() - popupLocation.x)) |
if ((size.width > (rootContainer.getWidth() - popupLocation.x)) |
599 |
|| (size.height > (rootContainer.getHeight() - popupLocation.y))) |
|| (size.height > (rootContainer.getHeight() - popupLocation.y))) |
600 |
fit = false; |
fit = false; |
621 |
{ |
{ |
622 |
// Subtract insets of the top-level container if popup menu's |
// Subtract insets of the top-level container if popup menu's |
623 |
// top-left corner is inside it. |
// top-left corner is inside it. |
|
if (rootContainer.contains(popupLocation)) |
|
|
{ |
|
624 |
Insets insets = rootContainer.getInsets(); |
Insets insets = rootContainer.getInsets(); |
625 |
popup.show(popupLocation.x - insets.left, |
popup.show(popupLocation.x - insets.left, |
626 |
popupLocation.y - insets.top, size.width, |
popupLocation.y - insets.top, size.width, |
627 |
size.height); |
size.height); |
628 |
} |
} |
|
|
|
|
else |
|
|
popup.show(popupLocation.x, popupLocation.y, size.width, |
|
|
size.height); |
|
|
} |
|
629 |
} |
} |
630 |
else |
else |
631 |
{ |
{ |
|
// popup menu was cancelled without selection |
|
|
if (! getSelectionModel().isSelected()) |
|
|
firePopupMenuCanceled(); |
|
|
|
|
632 |
firePopupMenuWillBecomeInvisible(); |
firePopupMenuWillBecomeInvisible(); |
|
|
|
633 |
popup.hide(); |
popup.hide(); |
634 |
} |
} |
635 |
} |
} |
797 |
} |
} |
798 |
|
|
799 |
/** |
/** |
800 |
* Process mouse events forwarded from MenuSelectionManager. |
* Process mouse events forwarded from MenuSelectionManager. This method |
801 |
|
* doesn't do anything. It is here to conform to the MenuElement interface. |
802 |
* |
* |
803 |
* @param event event forwarded from MenuSelectionManager |
* @param event event forwarded from MenuSelectionManager |
804 |
* @param path path to the menu element from which event was generated |
* @param path path to the menu element from which event was generated |
807 |
public void processMouseEvent(MouseEvent event, MenuElement[] path, |
public void processMouseEvent(MouseEvent event, MenuElement[] path, |
808 |
MenuSelectionManager manager) |
MenuSelectionManager manager) |
809 |
{ |
{ |
810 |
|
// Empty Implementation. This method is needed for the implementation |
811 |
|
// of MenuElement interface |
812 |
} |
} |
813 |
|
|
814 |
/** |
/** |
815 |
* DOCUMENT ME! |
* Process key events forwarded from MenuSelectionManager. This method |
816 |
|
* doesn't do anything. It is here to conform to the MenuElement interface. |
817 |
|
* |
818 |
|
* @param event event forwarded from MenuSelectionManager |
819 |
|
* @param path path to the menu element from which event was generated |
820 |
|
* @param manager MenuSelectionManager for the current menu hierarchy |
821 |
* |
* |
|
* @param event DOCUMENT ME! |
|
|
* @param path DOCUMENT ME! |
|
|
* @param manager DOCUMENT ME! |
|
822 |
*/ |
*/ |
823 |
public void processKeyEvent(KeyEvent event, MenuElement[] path, |
public void processKeyEvent(KeyEvent event, MenuElement[] path, |
824 |
MenuSelectionManager manager) |
MenuSelectionManager manager) |
825 |
{ |
{ |
826 |
|
// Empty Implementation. This method is needed for the implementation |
827 |
|
// of MenuElement interface |
828 |
} |
} |
829 |
|
|
830 |
/** |
/** |
836 |
*/ |
*/ |
837 |
public void menuSelectionChanged(boolean changed) |
public void menuSelectionChanged(boolean changed) |
838 |
{ |
{ |
839 |
|
if (! changed) |
840 |
|
setVisible(false); |
841 |
} |
} |
842 |
|
|
843 |
/** |
/** |
954 |
*/ |
*/ |
955 |
public void hide() |
public void hide() |
956 |
{ |
{ |
957 |
|
// FIXME: Right now the lightweight container is removed from JLayered |
958 |
|
// pane. It is probably would be better in order to improve performance |
959 |
|
// to make the container invisible instead of removing it everytime. |
960 |
JLayeredPane layeredPane; |
JLayeredPane layeredPane; |
961 |
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
962 |
int index = layeredPane.getIndexOf(c); |
int index = layeredPane.getIndexOf(c); |
1001 |
*/ |
*/ |
1002 |
public void hide() |
public void hide() |
1003 |
{ |
{ |
1004 |
|
// FIXME: Right now the lightweight container is removed from JLayered |
1005 |
|
// pane. It is probably would be better in order to improve performance |
1006 |
|
// to make the container invisible instead of removing it everytime. |
1007 |
JLayeredPane layeredPane; |
JLayeredPane layeredPane; |
1008 |
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
1009 |
int index = layeredPane.getIndexOf(this); |
int index = layeredPane.getIndexOf(this); |
1050 |
} |
} |
1051 |
} |
} |
1052 |
|
|
1053 |
|
/** |
1054 |
|
* This is the separator that can be used in popup menu. |
1055 |
|
*/ |
1056 |
public static class Separator extends JSeparator |
public static class Separator extends JSeparator |
1057 |
{ |
{ |
1058 |
public Separator() |
public Separator() |
1078 |
return AccessibleRole.POPUP_MENU; |
return AccessibleRole.POPUP_MENU; |
1079 |
} |
} |
1080 |
} |
} |
1081 |
|
|
1082 |
|
/* This class resizes popup menu and repaints popup menu appropriately if one |
1083 |
|
of item's action has changed */ |
1084 |
|
protected class ActionChangeListener implements PropertyChangeListener |
1085 |
|
{ |
1086 |
|
public void propertyChange(PropertyChangeEvent evt) |
1087 |
|
{ |
1088 |
|
JPopupMenu.this.revalidate(); |
1089 |
|
JPopupMenu.this.repaint(); |
1090 |
|
} |
1091 |
|
} |
1092 |
} |
} |