39 |
package javax.swing; |
package javax.swing; |
40 |
|
|
41 |
import java.awt.Component; |
import java.awt.Component; |
|
import java.awt.Container; |
|
42 |
import java.awt.Dimension; |
import java.awt.Dimension; |
|
import java.awt.GridBagConstraints; |
|
43 |
import java.awt.Insets; |
import java.awt.Insets; |
|
import java.awt.Panel; |
|
44 |
import java.awt.Point; |
import java.awt.Point; |
45 |
import java.awt.event.KeyEvent; |
import java.awt.event.KeyEvent; |
46 |
import java.awt.event.MouseEvent; |
import java.awt.event.MouseEvent; |
124 |
/* Popup that is used to display JPopupMenu */ |
/* Popup that is used to display JPopupMenu */ |
125 |
private transient Popup popup; |
private transient Popup popup; |
126 |
|
|
127 |
/* Location of the popup */ |
/** |
128 |
private Point popupLocation; |
* Location of the popup, X coordinate. |
129 |
|
*/ |
130 |
|
private int popupLocationX; |
131 |
|
|
132 |
|
/** |
133 |
|
* Location of the popup, Y coordinate. |
134 |
|
*/ |
135 |
|
private int popupLocationY; |
136 |
|
|
137 |
/* Field indicating if popup menu is visible or not */ |
/* Field indicating if popup menu is visible or not */ |
138 |
private boolean visible = false; |
private boolean visible = false; |
212 |
public void remove(int index) |
public void remove(int index) |
213 |
{ |
{ |
214 |
super.remove(index); |
super.remove(index); |
215 |
|
revalidate(); |
|
GridBagConstraints constraints = new GridBagConstraints(); |
|
|
constraints.fill = GridBagConstraints.BOTH; |
|
|
constraints.weightx = 100.0; |
|
|
constraints.weighty = 100.0; |
|
|
|
|
|
Component[] items = getComponents(); |
|
|
for (int i = index; i < items.length; i++) |
|
|
{ |
|
|
constraints.gridy = i; |
|
|
super.add(items[i], constraints, i); |
|
|
} |
|
|
this.setSize(this.getPreferredSize()); |
|
216 |
} |
} |
217 |
|
|
218 |
/** |
/** |
237 |
*/ |
*/ |
238 |
public void insert(Component component, int index) |
public void insert(Component component, int index) |
239 |
{ |
{ |
240 |
GridBagConstraints constraints = new GridBagConstraints(); |
super.add(component, index); |
|
constraints.fill = GridBagConstraints.BOTH; |
|
|
constraints.weightx = 100.0; |
|
|
constraints.weighty = 100.0; |
|
|
|
|
|
constraints.gridy = index; |
|
|
super.add(component, constraints, index); |
|
|
|
|
|
// need to change constraints for the components that were moved by 1 |
|
|
// due to the insertion |
|
|
if (index != -1) |
|
|
{ |
|
|
Component[] items = getComponents(); |
|
|
|
|
|
for (int i = index + 1; i < items.length; i++) |
|
|
{ |
|
|
constraints.gridy = i; |
|
|
super.add(items[i], constraints, i); |
|
|
} |
|
|
} |
|
|
this.setSize(this.getPreferredSize()); |
|
241 |
} |
} |
242 |
|
|
243 |
/** |
/** |
487 |
*/ |
*/ |
488 |
public void pack() |
public void pack() |
489 |
{ |
{ |
490 |
super.setSize(null); |
// Hook up this call so that it gets executed on the event thread in order |
491 |
|
// to avoid synchronization problems when calling the layout manager. |
492 |
|
if (! SwingUtilities.isEventDispatchThread()) |
493 |
|
{ |
494 |
|
SwingUtilities.invokeLater(new Runnable() |
495 |
|
{ |
496 |
|
public void run() |
497 |
|
{ |
498 |
|
show(); |
499 |
|
} |
500 |
|
}); |
501 |
|
} |
502 |
|
|
503 |
|
setSize(getPreferredSize()); |
504 |
} |
} |
505 |
|
|
506 |
/** |
/** |
520 |
* |
* |
521 |
* @param visible true if popup menu will become visible and false otherwise. |
* @param visible true if popup menu will become visible and false otherwise. |
522 |
*/ |
*/ |
523 |
public void setVisible(boolean visible) |
public void setVisible(final boolean visible) |
524 |
{ |
{ |
525 |
|
// Hook up this call so that it gets executed on the event thread in order |
526 |
|
// to avoid synchronization problems when calling the layout manager. |
527 |
|
if (! SwingUtilities.isEventDispatchThread()) |
528 |
|
{ |
529 |
|
SwingUtilities.invokeLater(new Runnable() |
530 |
|
{ |
531 |
|
public void run() |
532 |
|
{ |
533 |
|
setVisible(visible); |
534 |
|
} |
535 |
|
}); |
536 |
|
} |
537 |
|
|
538 |
if (visible == isVisible()) |
if (visible == isVisible()) |
539 |
return; |
return; |
540 |
|
|
546 |
if (visible) |
if (visible) |
547 |
{ |
{ |
548 |
firePopupMenuWillBecomeVisible(); |
firePopupMenuWillBecomeVisible(); |
549 |
Container rootContainer = (Container) SwingUtilities.getRoot(invoker); |
|
550 |
Dimension screenSize = getToolkit().getScreenSize(); |
PopupFactory pf = PopupFactory.getSharedInstance(); |
551 |
|
popup = pf.getPopup(invoker, this, popupLocationX, popupLocationY); |
552 |
boolean fit = true; |
pack(); |
553 |
Dimension size = getSize(); |
popup.show(); |
|
if (size.width == 0 && size.height == 0) |
|
|
{ |
|
|
size = getPreferredSize(); |
|
|
setSize(size); |
|
|
} |
|
|
if ((size.width > (rootContainer.getWidth() - popupLocation.x)) |
|
|
|| (size.height > (rootContainer.getHeight() - popupLocation.y))) |
|
|
fit = false; |
|
|
if (lightWeightPopupEnabled && fit) |
|
|
popup = new LightWeightPopup(this); |
|
|
else |
|
|
{ |
|
|
if (fit) |
|
|
popup = new MediumWeightPopup(this); |
|
|
else |
|
|
{ |
|
|
popup = new HeavyWeightPopup(this); |
|
|
setLightWeightPopupEnabled(false); |
|
|
} |
|
|
} |
|
|
if (popup instanceof LightWeightPopup |
|
|
|| popup instanceof MediumWeightPopup) |
|
|
{ |
|
|
JLayeredPane layeredPane; |
|
|
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
|
|
Point p = new Point(popupLocation.x, popupLocation.y); |
|
|
|
|
|
if (layeredPane.isShowing()) |
|
|
SwingUtilities.convertPointFromScreen(p, layeredPane); |
|
|
|
|
|
if (size.width + popupLocation.x > screenSize.width) |
|
|
popupLocation.x -= size.width; |
|
|
if (size.height + popupLocation.y > screenSize.height) |
|
|
popupLocation.y -= size.height; |
|
|
|
|
|
popup.show(p.x, p.y, size.width, size.height); |
|
|
} |
|
|
else |
|
|
{ |
|
|
// Subtract insets of the top-level container if popup menu's |
|
|
// top-left corner is inside it. |
|
|
Insets insets = rootContainer.getInsets(); |
|
|
|
|
|
if (size.width + popupLocation.x > screenSize.width) |
|
|
popupLocation.x -= size.width; |
|
|
if (size.height + popupLocation.y > screenSize.height) |
|
|
popupLocation.y -= size.height; |
|
|
|
|
|
popup.show(popupLocation.x - insets.left, |
|
|
popupLocation.y - insets.top, |
|
|
size.width, size.height); |
|
|
} |
|
554 |
} |
} |
555 |
else |
else |
556 |
{ |
{ |
568 |
*/ |
*/ |
569 |
public void setLocation(int x, int y) |
public void setLocation(int x, int y) |
570 |
{ |
{ |
571 |
if (popupLocation == null) |
popupLocationX = x; |
572 |
popupLocation = new Point(); |
popupLocationY = y; |
573 |
|
// Handle the case when the popup is already showing. In this case we need |
574 |
popupLocation.x = x; |
// to fetch a new popup from PopupFactory and use this. See the general |
575 |
popupLocation.y = y; |
// contract of the PopupFactory. |
576 |
} |
} |
577 |
|
|
578 |
/** |
/** |
834 |
} |
} |
835 |
|
|
836 |
/** |
/** |
|
* This interface is used to display menu items of the JPopupMenu |
|
|
*/ |
|
|
private interface Popup |
|
|
{ |
|
|
/** |
|
|
* Displays container on the screen |
|
|
* |
|
|
* @param x x-coordinate of popup menu's location on the screen |
|
|
* @param y y-coordinate of popup menu's location on the screen |
|
|
* @param width width of the container that is used to display menu |
|
|
* item's for popup menu |
|
|
* @param height height of the container that is used to display menu |
|
|
* item's for popup menu |
|
|
*/ |
|
|
void show(int x, int y, int width, int height); |
|
|
|
|
|
/** |
|
|
* Hides container used to display popup menu item's from the screen |
|
|
*/ |
|
|
void hide(); |
|
|
} |
|
|
|
|
|
/** |
|
|
* This class represents Popup menu that uses light weight container |
|
|
* to display its contents. |
|
|
*/ |
|
|
private class LightWeightPopup extends Container implements Popup |
|
|
{ |
|
|
private Component c; |
|
|
|
|
|
/** |
|
|
* Creates a new LightWeightPopup menu |
|
|
* |
|
|
* @param c Container containing menu items |
|
|
*/ |
|
|
public LightWeightPopup(Container c) |
|
|
{ |
|
|
this.c = c; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Displayes lightweight container with menu items to the screen |
|
|
* |
|
|
* @param x x-coordinate of lightweight container on the screen |
|
|
* @param y y-coordinate of lightweight container on the screen |
|
|
* @param width width of the lightweight container |
|
|
* @param height height of the lightweight container |
|
|
*/ |
|
|
public void show(int x, int y, int width, int height) |
|
|
{ |
|
|
JLayeredPane layeredPane; |
|
|
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
|
|
c.setBounds(x, y, width, height); |
|
|
layeredPane.add(c, JLayeredPane.POPUP_LAYER, 0); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Hides lightweight container from the screen |
|
|
*/ |
|
|
public void hide() |
|
|
{ |
|
|
// FIXME: Right now the lightweight container is removed from JLayered |
|
|
// pane. It is probably would be better in order to improve performance |
|
|
// to make the container invisible instead of removing it everytime. |
|
|
JLayeredPane layeredPane; |
|
|
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
|
|
int index = layeredPane.getIndexOf(c); |
|
|
layeredPane.remove(index); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* MediumWeightPopup is an AWT Panel with JPopupMenu's menu items. |
|
|
* It is used to display JPopupMenu's menu items on the screen |
|
|
*/ |
|
|
private class MediumWeightPopup extends Panel implements Popup |
|
|
{ |
|
|
/** |
|
|
* Creates a new MediumWeightPopup object. |
|
|
* |
|
|
* @param c Container with JPopupMenu's menu items |
|
|
*/ |
|
|
public MediumWeightPopup(Container c) |
|
|
{ |
|
|
this.add(c); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Displays AWT Panel with its components on the screen |
|
|
* |
|
|
* @param x x-coordinate of the upper-left corner of the panel's |
|
|
* @param y y-coordinate of the upper-left corner of the panel's |
|
|
* @param width width of the panel |
|
|
* @param height height of the panel |
|
|
*/ |
|
|
public void show(int x, int y, int width, int height) |
|
|
{ |
|
|
JLayeredPane layeredPane; |
|
|
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
|
|
layeredPane.add(this, JLayeredPane.POPUP_LAYER, 0); |
|
|
this.setBounds(x, y, width, height); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Hides This panel from the screen |
|
|
*/ |
|
|
public void hide() |
|
|
{ |
|
|
// FIXME: Right now the lightweight container is removed from JLayered |
|
|
// pane. It is probably would be better in order to improve performance |
|
|
// to make the container invisible instead of removing it everytime. |
|
|
JLayeredPane layeredPane; |
|
|
layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); |
|
|
int index = layeredPane.getIndexOf(this); |
|
|
layeredPane.remove(index); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
|
* HeavyWeightPopup is JDialog that is used to display JPopupMenu menu item's |
|
|
* on the screen |
|
|
*/ |
|
|
private class HeavyWeightPopup extends JDialog implements Popup |
|
|
{ |
|
|
/** |
|
|
* Creates a new HeavyWeightPopup object. |
|
|
* |
|
|
* @param c Container containing menu items |
|
|
*/ |
|
|
public HeavyWeightPopup(Container c) |
|
|
{ |
|
|
this.setContentPane(c); |
|
|
this.setUndecorated(true); |
|
|
this.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Displays JDialog container JPopupMenu's menu items to the screen |
|
|
* |
|
|
* @param x x-coordinate of JDialog containing menu items |
|
|
* @param y y-coordinate of JDialog containing menu items |
|
|
* @param width width of the JDialog |
|
|
* @param height height of the JDialog |
|
|
*/ |
|
|
public void show(int x, int y, int width, int height) |
|
|
{ |
|
|
this.setBounds(x, y, width, height); |
|
|
this.show(); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
837 |
* This is the separator that can be used in popup menu. |
* This is the separator that can be used in popup menu. |
838 |
*/ |
*/ |
839 |
public static class Separator extends JSeparator |
public static class Separator extends JSeparator |
870 |
{ |
{ |
871 |
public void propertyChange(PropertyChangeEvent evt) |
public void propertyChange(PropertyChangeEvent evt) |
872 |
{ |
{ |
873 |
JPopupMenu.this.revalidate(); |
// We used to have a revalidate() and repaint() call here. However I think |
874 |
JPopupMenu.this.repaint(); |
// this is not needed. Instead, a new Popup has to be fetched from the |
875 |
|
// PopupFactory and used here. |
876 |
} |
} |
877 |
} |
} |
878 |
} |
} |