com.jidesoft.popup.JidePopup Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jide-oss Show documentation
Show all versions of jide-oss Show documentation
JIDE Common Layer (Professional Swing Components)
/*
* @(#)JidePopup.java 2/24/2005
*
* Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
*/
package com.jidesoft.popup;
import com.jidesoft.plaf.LookAndFeelFactory;
import com.jidesoft.plaf.PopupUI;
import com.jidesoft.plaf.UIDefaultsLookup;
import com.jidesoft.swing.*;
import com.jidesoft.utils.PortingUtils;
import com.jidesoft.utils.SecurityUtils;
import com.jidesoft.utils.SystemInfo;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.accessibility.AccessibleValue;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
/**
* JidePopup
is a popup window which can be resized, dragged and autohide if time out.
*
* JidePopup uses JWindow as the container in order to show itself. By default, JidePopup is not focusable which means
* no component in the JidePopup will get focus. For example, if you put a JTextField in JidePopup and the JTextField
* becomes not editable, this is a result of non-focusable JWindow. So if you want components in JidePopup to be able to
* receive focus, you can either call setFocusable(true) or you can call {@link #setDefaultFocusComponent(java.awt.Component)}
* to set a child component as the default focus component.
*/
@SuppressWarnings({"UnusedDeclaration"})
public class JidePopup extends JComponent implements Accessible, WindowConstants {
/**
* You can set client property to JidePopup control the window opacity (only when heavyweight popup is in use). The
* value of the client property should be a float.
*/
public static final String CLIENT_PROPERTY_WINDOW_OPACITY = "windowOpacity";
/**
* You can set client property to JidePopup control the window opaque (only when heavyweight popup is in use) The
* value of the client property should be a boolean.
*/
public static final String CLIENT_PROPERTY_WINDOW_OPAQUE = "windowOpaque";
/**
* You can set client property to JidePopup control the window shape (only when heavyweight popup is in use) The
* value of the client property should be a Shape.
*/
public static final String CLIENT_PROPERTY_WINDOW_SHAPE = "windowShape";
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "JidePopupUI";
/**
* The JRootPane
instance that manages the content pane and optional menu bar for this Popup, as well
* as the glass pane.
*
* @see javax.swing.JRootPane
* @see javax.swing.RootPaneContainer
*/
private JRootPane rootPane;
/**
* If true
then calls to add
and setLayout
cause an exception to be thrown.
*/
private boolean rootPaneCheckingEnabled = false;
/**
* Bound property name.
*/
public static final String CONTENT_PANE_PROPERTY = "contentPane";
/**
* Bound property name.
*/
public static final String MENU_BAR_PROPERTY = "JMenuBar";
/**
* Bound property name.
*/
public static final String LAYERED_PANE_PROPERTY = "layeredPane";
/**
* Bound property name.
*/
public static final String ROOT_PANE_PROPERTY = "rootPane";
/**
* Bound property name.
*/
public static final String GLASS_PANE_PROPERTY = "glassPane";
/**
* Bound property name.
*/
public static final String VISIBLE_PROPERTY = "visible";
public static final String TRANSIENT_PROPERTY = "transient";
/**
* Constrained property name indicated that this frame has
* selected status.
*/
/**
* Constrained property name indicating that the popup is attachable.
*/
public static final String ATTACHABLE_PROPERTY = "attachable";
private boolean _attachable = true;
/**
* Bound property name for gripper.
*/
public static final String MOVABLE_PROPERTY = "movable";
/**
* If the gripper should be shown. Gripper is something on divider to indicate it can be dragged.
*/
private boolean _movable = false;
private boolean _ensureInOneScreen = true;
private boolean _returnFocusToOwner = true;
/**
* Bound property name for if the popup is detached.
*/
public static final String DETACHED_PROPERTY = "detached";
public static final String CLIENT_PROPERTY_POPUP_TYPE = "popupType";
public static final String CLIENT_PROPERTY_VALUE_POPUP_TYPE_COMBOBOX = "comboBox";
protected boolean _detached;
protected ResizableWindow _window;
protected ResizablePanel _panel;
protected ResizableSupport _resizableSupport;
private ComponentAdapter _componentListener;
private WindowAdapter _windowListener;
private ComponentAdapter _ownerComponentListener;
private HierarchyListener _hierarchyListener;
private Point _displayStartLocation;
/**
* If the popup shows a dialog and you don't want the popup to be hidden when the dialog is shown, you can use this
* special client property to do it. Here is the code, assuming the dialog is shown from your popup.
*
* JComponent c = JideSwingUtilities.getFirstJComponent(dialog);
* if(c != null) {
* c.putClientProperty(JidePopup.CLIENT_PROPERTY_POPUP_ACTUAL_OWNER, component);
* }
*
*/
public static final String CLIENT_PROPERTY_POPUP_ACTUAL_OWNER = "JidePopup.actualOwner";
/**
* Bound property name for resizable.
*/
public static final String RESIZABLE_PROPERTY = "resizable";
private boolean _resizable = true;
private boolean _keepPreviousSize = true;
// /**
// * Bound property name for movable.
// */
// public static final String MOVABLE_PROPERTY = "movable";
//
// private boolean _movable;
/**
* Bound property name for owner.
*/
public static final String OWNER_PROPERTY = "owner";
private Component _owner;
private Border _popupBorder;
private boolean _transient = true;
private int _timeout = 0;
private Timer _timer;
private Component _defaultFocusComponent;
/**
* Hides the popup when the owner is moved.
*/
public static final int DO_NOTHING_ON_MOVED = -1;
/**
* Hides the popup when the owner is moved.
*/
public static final int HIDE_ON_MOVED = 0;
/**
* Moves the popup along with owner when the owner is moved.
*/
public static final int MOVE_ON_MOVED = 1;
private int _defaultMoveOperation = HIDE_ON_MOVED;
/**
* The distance between alert and screen border.
*/
public int DISTANCE_TO_SCREEN_BORDER = 10;
private List _excludedComponents;
private int _gripperLocation = SwingConstants.NORTH;
public static final String PROPERTY_GRIPPER_LOCATION = "gripperLocation";
private ComponentAdapter _popupResizeListener;
protected Dimension _previousSize;
protected Component _actualOwner;
protected Point _actualOwnerLocation;
/**
* Key used to indicate a light weight popup should be used.
*/
public static final int LIGHT_WEIGHT_POPUP = 0;
/*
* Key used to indicate a heavy weight Popup should be used.
*/
public static final int HEAVY_WEIGHT_POPUP = 2;
private int _popupType = HEAVY_WEIGHT_POPUP;
private ActionListener _escapeActionListener;
private Object HIDE_POPUP_KEY = null;
/**
* Creates a Popup.
*/
public JidePopup() {
_excludedComponents = new ArrayList();
setRootPane(createRootPane());
setLayout(new BorderLayout());
setRootPaneCheckingEnabled(true);
setFocusable(false);
updateUI();
initHidePopupProperty();
}
private void initHidePopupProperty() {
JComboBox comboBox = new JComboBox();
comboBox.setEnabled(isEnabled());
comboBox.setEditable(true);
comboBox.doLayout();
Component[] components = comboBox.getComponents();
for (Component component : components) {
if (component instanceof AbstractButton) {
HIDE_POPUP_KEY = ((AbstractButton) component).getClientProperty("doNotCancelPopup");
break;
}
}
}
/**
* Called by the constructor to set up the JRootPane
.
*
* @return a new JRootPane
* @see javax.swing.JRootPane
*/
protected JRootPane createRootPane() {
JRootPane pane = new JRootPane();
// by default, the subclass BorderLayout cause memory leak if isPopupVolatile in AbstractComboBox.
pane.getContentPane().setLayout(new BorderLayout());
pane.setOpaque(false); // on Nimbus L&F, JRootPane is opaque by default. So we have to set it to false explicitly.
return pane;
}
/**
* Returns the look-and-feel object that renders this component.
*
* @return the PopupUI
object that renders this component
*/
public PopupUI getUI() {
return (PopupUI) ui;
}
/**
* Sets the UI delegate for this Popup
.
*
* @param ui the UI delegate
*/
public void setUI(PopupUI ui) {
boolean checkingEnabled = isRootPaneCheckingEnabled();
try {
setRootPaneCheckingEnabled(false);
super.setUI(ui);
}
finally {
setRootPaneCheckingEnabled(checkingEnabled);
}
}
/**
* Notification from the UIManager
that the look and feel has changed. Replaces the current UI object
* with the latest version from the UIManager
.
*
* @see javax.swing.JComponent#updateUI
*/
@Override
public void updateUI() {
if (UIDefaultsLookup.get(uiClassID) == null) {
LookAndFeelFactory.installJideExtension();
}
setUI((PopupUI) UIManager.getUI(this));
invalidate();
}
/**
* Returns the name of the look-and-feel class that renders this component.
*
* @return the string "PopupUI"
* @see javax.swing.JComponent#getUIClassID
* @see javax.swing.UIDefaults#getUI
*/
@Override
public String getUIClassID() {
return uiClassID;
}
/**
* Returns whether calls to add
and setLayout
cause an exception to be thrown.
*
* @return true
if add
and setLayout
are checked
* @see #addImpl
* @see #setLayout
* @see #setRootPaneCheckingEnabled
*/
protected boolean isRootPaneCheckingEnabled() {
return rootPaneCheckingEnabled;
}
/**
* Determines whether calls to add
and setLayout
cause an exception to be thrown.
*
* @param enabled a boolean value, true
if checking is to be enabled, which cause the exceptions to be
* thrown
* @see #addImpl
* @see #setLayout
* @see #isRootPaneCheckingEnabled
*/
protected void setRootPaneCheckingEnabled(boolean enabled) {
rootPaneCheckingEnabled = enabled;
}
/**
* Ensures that, by default, children cannot be added directly to this component. Instead, children must be added to
* its content pane. For example:
*
* thisComponent.getContentPane().add(child)
*
* An attempt to add to directly to this component will cause a runtime exception to be thrown. Subclasses can
* disable this behavior.
*
* @param comp the Component
to be added
* @param constraints the object containing the constraints, if any
* @param index the index
* @throws Error if called with isRootPaneChecking
true
* @see #setRootPaneCheckingEnabled
*/
@Override
protected void addImpl(Component comp, Object constraints, int index) {
if (isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else {
super.addImpl(comp, constraints, index);
}
}
/**
* Removes the specified component from this container.
*
* @param comp the component to be removed
* @see #add
*/
@Override
public void remove(Component comp) {
int oldCount = getComponentCount();
super.remove(comp);
if (oldCount == getComponentCount()) {
// Client mistake, but we need to handle it to avoid a
// common object leak in client applications.
getContentPane().remove(comp);
}
}
/**
* Ensures that, by default, the layout of this component cannot be set. Instead, the layout of its content pane
* should be set. For example:
*
* thisComponent.getContentPane().setLayout(new GridLayout(1,2))
*
* An attempt to set the layout of this component will cause an runtime exception to be thrown. Subclasses can
* disable this behavior.
*
* @param manager the LayoutManager
* @throws Error if called with isRootPaneChecking
true
* @see #setRootPaneCheckingEnabled
*/
@Override
public void setLayout(LayoutManager manager) {
if (isRootPaneCheckingEnabled()) {
getContentPane().setLayout(manager);
}
else {
super.setLayout(manager);
}
}
//////////////////////////////////////////////////////////////////////////
/// Property Methods
//////////////////////////////////////////////////////////////////////////
/**
* Returns the current JMenuBar
for this Popup
, or null
if no menu bar has
* been set.
*
* @return the JMenuBar
used by this Popup.
* @see #setJMenuBar
*/
public JMenuBar getJMenuBar() {
return getRootPane().getJMenuBar();
}
/**
* Sets the menuBar
property for this Popup
.
*
* @param m the JMenuBar
to use in this Popup.
* @see #getJMenuBar
*/
public void setJMenuBar(JMenuBar m) {
JMenuBar oldValue = getJMenuBar();
getRootPane().setJMenuBar(m);
firePropertyChange(MENU_BAR_PROPERTY, oldValue, m);
}
// implements javax.swing.RootPaneContainer
/**
* Returns the content pane for this Popup.
*
* @return the content pane
*/
public Container getContentPane() {
return getRootPane().getContentPane();
}
/**
* Sets this Popup
's contentPane
property.
*
* @param c the content pane for this popup.
* @throws java.awt.IllegalComponentStateException (a runtime exception) if the content pane parameter is
* null
* @see javax.swing.RootPaneContainer#getContentPane
*/
public void setContentPane(Container c) {
Container oldValue = getContentPane();
getRootPane().setContentPane(c);
firePropertyChange(CONTENT_PANE_PROPERTY, oldValue, c);
}
/**
* Returns the layered pane for this popup.
*
* @return a JLayeredPane
object
* @see javax.swing.RootPaneContainer#setLayeredPane
* @see javax.swing.RootPaneContainer#getLayeredPane
*/
public JLayeredPane getLayeredPane() {
return getRootPane().getLayeredPane();
}
/**
* Sets this Popup
's layeredPane
property.
*
* @param layered the JLayeredPane
for this popup
* @throws java.awt.IllegalComponentStateException (a runtime exception) if the layered pane parameter is
* null
* @see javax.swing.RootPaneContainer#setLayeredPane
*/
public void setLayeredPane(JLayeredPane layered) {
JLayeredPane oldValue = getLayeredPane();
getRootPane().setLayeredPane(layered);
firePropertyChange(LAYERED_PANE_PROPERTY, oldValue, layered);
}
/**
* Returns the glass pane for this popup.
*
* @return the glass pane
* @see javax.swing.RootPaneContainer#setGlassPane
*/
public Component getGlassPane() {
return getRootPane().getGlassPane();
}
/**
* Sets this Popup
's glassPane
property.
*
* @param glass the glass pane for this popup
* @see javax.swing.RootPaneContainer#getGlassPane
*/
public void setGlassPane(Component glass) {
Component oldValue = getGlassPane();
getRootPane().setGlassPane(glass);
firePropertyChange(GLASS_PANE_PROPERTY, oldValue, glass);
}
/**
* Returns the rootPane
object for this popup.
*
* @return the rootPane
property
* @see javax.swing.RootPaneContainer#getRootPane
*/
@Override
public JRootPane getRootPane() {
return rootPane;
}
/**
* Sets the rootPane
property for this Popup
. This method is called by the constructor.
*
* @param root the new JRootPane
object
*/
protected void setRootPane(JRootPane root) {
if (rootPane != null) {
rootPane.removeAll();
remove(rootPane);
}
JRootPane oldValue = getRootPane();
rootPane = root;
if (rootPane != null) {
boolean checkingEnabled = isRootPaneCheckingEnabled();
try {
setRootPaneCheckingEnabled(false);
add(rootPane, BorderLayout.CENTER);
}
finally {
setRootPaneCheckingEnabled(checkingEnabled);
}
}
firePropertyChange(ROOT_PANE_PROPERTY, oldValue, root);
}
/**
* Makes the component visible or invisible. Overrides Component.setVisible
.
*
* @param visible true to make the component visible; false to make it invisible
*/
@Override
public void setVisible(boolean visible) {
boolean old = isVisible();
if (visible != old) {
super.setVisible(visible);
firePropertyChange(VISIBLE_PROPERTY, old, visible);
}
}
/**
* Gets the AccessibleContext
associated with this Popup
. For popups, the
* AccessibleContext
takes the form of an AccessiblePopup
object. A new
* AccessiblePopup
instance is created if necessary.
*
* @return an AccessiblePopup
that serves as the AccessibleContext
of this
* Popup
* @see com.jidesoft.popup.JidePopup.AccessiblePopup
*/
@Override
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessiblePopup();
}
return accessibleContext;
}
/**
* Get the flag indicating if JidePopup should keep the size last time it was popped up.
*
* The default value of this flag is true. If you want the popup to resize based on the changing contents like in
* IntelliHints, you need set this flag to false.
*
* @return the flag.
*/
public boolean isKeepPreviousSize() {
return _keepPreviousSize;
}
/**
* Set the flag indicating if JidePopup should keep the size last time it was popped up.
*
* @param keepPreviousSize the flag.
*/
public void setKeepPreviousSize(boolean keepPreviousSize) {
_keepPreviousSize = keepPreviousSize;
}
/**
* Get the insets so that when the JidePopup is dragged back to this area, the JidePopup will jump to its original
* position automatically.
*
* By default, the value is {10, 10, 10, 10}. You can disable the jump functionality by setting the insets to {0, 0,
* 0, 0}.
*
* @return the insets.
*/
public Insets getBackToOriginalInsets() {
return _backToOriginalInsets;
}
/**
* Set the insets so that when the JidePopup is dragged back to this area, the JidePopup will jump to its original
* position automatically.
*
* @param backToOriginalInsets the insets
*/
public void setBackToOriginalInsets(Insets backToOriginalInsets) {
_backToOriginalInsets = backToOriginalInsets;
}
/**
* This class implements accessibility support for the Popup
class. It provides an implementation of
* the Java Accessibility API appropriate to popup user-interface elements.
*/
protected class AccessiblePopup extends AccessibleJComponent
implements AccessibleValue {
private static final long serialVersionUID = -1095213042773793649L;
/**
* Get the accessible name of this object.
*
* @return the localized name of the object -- can be null
if this object does not have a name
* @see #setAccessibleName
*/
@Override
public String getAccessibleName() {
if (accessibleName != null) {
return accessibleName;
}
else {
return getName();
}
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the object
* @see javax.accessibility.AccessibleRole
*/
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.SWING_COMPONENT; // use a generic one since there is no specific one to choose
}
/**
* Gets the AccessibleValue associated with this object. In the implementation of the Java Accessibility API
* for this class, returns this object, which is responsible for implementing the AccessibleValue
* interface on behalf of itself.
*
* @return this object
*/
@Override
public AccessibleValue getAccessibleValue() {
return this;
}
//
// AccessibleValue methods
//
/**
* Get the value of this object as a Number.
*
* @return value of the object -- can be null
if this object does not have a value
*/
public Number getCurrentAccessibleValue() {
if (isVisible()) {
return 1;
}
else {
return 0;
}
}
/**
* Set the value of this object as a Number.
*
* @return true
if the value was set
*/
public boolean setCurrentAccessibleValue(Number n) {
if (n instanceof Integer) {
if (n.intValue() == 0)
setVisible(true);
else
setVisible(false);
return true;
}
else {
return false;
}
}
/**
* Get the minimum value of this object as a Number.
*
* @return Minimum value of the object; null
if this object does not have a minimum value
*/
public Number getMinimumAccessibleValue() {
return Integer.MIN_VALUE;
}
/**
* Get the maximum value of this object as a Number.
*
* @return Maximum value of the object; null
if this object does not have a maximum value
*/
public Number getMaximumAccessibleValue() {
return Integer.MAX_VALUE;
}
}
/**
* Shows the popup. By default, it will show right below the owner.
*/
public void showPopup() {
//David: To account for a popup within a popup, let the caller specify an owner
// different from the RootPaneContainer(Applet) or ContentContainer.
// showPopup(new Insets(0, 0, 0, 0));
showPopup(new Insets(0, 0, 0, 0), null);
}
/**
* Shows the popup. By default, it will show right below the owner after considering the insets. This call is almost
* the same as setOwner followed by showPopup() except in this case, the owner is only temporarily used to create
* the popup. It will not be added to excludedComponent list as setOwner would do.
*
* @param owner the popup window's owner; if unspecified, it will default to the RootPaneContainer(Applet) or
* ContentContainer
*/
public void showPopup(Component owner) {
showPopup(new Insets(0, 0, 0, 0), owner);
}
/**
* Shows the popup. By default, it will show right below the owner after considering the insets.
*
* @param insets the popup's insets RootPaneContainer(Applet) or ContentContainer
*/
public void showPopup(Insets insets) {
showPopup(insets, null);
}
protected Insets _insets = null;
/**
* Shows the popup. By default, it will show right below the owner after considering the insets. Please note, if the
* owner is not displayed (isShowing returns false), the popup will not be displayed either.
*
* @param insets the popup's insets
* @param owner the popup window's owner; if unspecified, it will default to the RootPaneContainer(Applet) or
* ContentContainer
*/
public void showPopup(Insets insets, Component owner) {
_insets = insets;
Component actualOwner = (owner != null) ? owner : getOwner();
if (actualOwner != null && actualOwner.isShowing()) {
Point point = actualOwner.getLocationOnScreen();
internalShowPopup(point.x, point.y, actualOwner);
}
else {
showPopup(SwingConstants.CENTER);
}
}
/**
* Calculates the popup location.
*
* @param point owner is top-left coordinate relative to screen.
* @param size the size of the popup window.
* @param owner the owner
* @return new popup location. By default, it will return the coordinate of the bottom-left corner of owner.
*/
protected Point getPopupLocation(Point point, Dimension size, Component owner) {
Component actualOwner = (owner != null) ? owner : getOwner();
Dimension ownerSize = actualOwner != null ? actualOwner.getSize() : new Dimension(0, 0);
if (size.width == 0) {
size = this.getPreferredSize();
}
Point p = new Point(point.x + _insets.left, point.y + ownerSize.height - _insets.bottom);
int left = p.x + size.width;
int bottom = p.y + size.height;
Rectangle screenBounds = PortingUtils.getContainingScreenBounds(new Rectangle(p, size), true);
if (bottom > screenBounds.y + screenBounds.height) {
p.y = point.y + _insets.top - size.height; // flip to upward
if (p.y < screenBounds.y) {
p.y = screenBounds.y;
}
if (isResizable()) {
setupResizeCorner(Resizable.UPPER_RIGHT);
}
}
else {
if (isResizable()) {
setupResizeCorner(Resizable.LOWER_RIGHT);
}
}
Rectangle bounds = PortingUtils.containsInScreenBounds(actualOwner, new Rectangle(p, size), isEnsureInOneScreen());
p.x = bounds.x;
p.y = bounds.y;
return p;
}
/**
* Setup Resizable's ResizeCorner.
*
* @param corner the corner.
*/
public void setupResizeCorner(int corner) {
switch (corner) {
case Resizable.UPPER_RIGHT:
if (_resizableSupport != null) {
_resizableSupport.getResizable().setResizableCorners(Resizable.UPPER_RIGHT);
JideSwingUtilities.setRecursively(this, new JideSwingUtilities.Handler() {
public boolean condition(Component c) {
return c instanceof JideScrollPane;
}
public void action(Component c) {
Resizable.ResizeCorner corner = new Resizable.ResizeCorner(Resizable.UPPER_RIGHT);
corner.addMouseListener(_resizableSupport.getResizable().getMouseInputAdapter());
corner.addMouseMotionListener(_resizableSupport.getResizable().getMouseInputAdapter());
((JideScrollPane) c).setScrollBarCorner(JideScrollPane.VERTICAL_TOP, corner);
((JideScrollPane) c).setScrollBarCorner(JideScrollPane.VERTICAL_BOTTOM, null);
}
public void postAction(Component c) {
}
});
}
break;
case Resizable.LOWER_RIGHT:
if (_resizableSupport != null) {
_resizableSupport.getResizable().setResizableCorners(Resizable.LOWER_RIGHT);
JideSwingUtilities.setRecursively(this, new JideSwingUtilities.Handler() {
public boolean condition(Component c) {
return c instanceof JideScrollPane;
}
public void action(Component c) {
Resizable.ResizeCorner corner = new Resizable.ResizeCorner(Resizable.LOWER_RIGHT);
corner.addMouseListener(_resizableSupport.getResizable().getMouseInputAdapter());
corner.addMouseMotionListener(_resizableSupport.getResizable().getMouseInputAdapter());
((JideScrollPane) c).setScrollBarCorner(JideScrollPane.VERTICAL_BOTTOM, corner);
((JideScrollPane) c).setScrollBarCorner(JideScrollPane.VERTICAL_TOP, null);
}
public void postAction(Component c) {
}
});
}
break;
default:
if (_resizableSupport != null) {
_resizableSupport.getResizable().setResizableCorners(corner);
}
break;
}
}
public static Component getTopLevelAncestor(Component component) {
if (component == null) {
return null;
}
for (Component p = component; p != null; p = p.getParent()) {
if (p instanceof Window || p instanceof Applet) {
return p;
}
}
return null;
}
/**
* Shows the popup at the specified location relative to the screen. The valid locations are: - {@link
* SwingConstants#CENTER}
- {@link SwingConstants#SOUTH}
- {@link SwingConstants#NORTH}
- {@link
* SwingConstants#WEST}
- {@link SwingConstants#EAST}
- {@link SwingConstants#NORTH_EAST}
- {@link
* SwingConstants#NORTH_WEST}
- {@link SwingConstants#SOUTH_EAST}
- {@link SwingConstants#SOUTH_WEST}
The
* actual location will be based on the main screen bounds. Say if the location is SwingConstants.SOUTH_EAST, the
* popup will appear at the south west corner of main screen with 10 pixels to the border. The 10 pixel is the
* default value. You can change it by setting {@link #DISTANCE_TO_SCREEN_BORDER}.
*
* @param location the new location.
*/
public void showPopup(int location) {
showPopup(location, null);
}
/**
* Shows the popup at the specified location relative to the owner. The valid locations are: - {@link
* SwingConstants#CENTER}
- {@link SwingConstants#SOUTH}
- {@link SwingConstants#NORTH}
- {@link
* SwingConstants#WEST}
- {@link SwingConstants#EAST}
- {@link SwingConstants#NORTH_EAST}
- {@link
* SwingConstants#NORTH_WEST}
- {@link SwingConstants#SOUTH_EAST}
- {@link SwingConstants#SOUTH_WEST}
The
* actual location will be based on the owner's bounds. Say if the location is SwingConstants.SOUTH_EAST, the popup
* will appear at the south west corner of owner with 10 pixels to the border. The 10 pixel is the default value.
* You can change it by setting {@link #DISTANCE_TO_SCREEN_BORDER}.
*
* @param location the new location
* @param owner the popup window's owner; if unspecified, it will default to the RootPaneContainer(Applet) or
* ContentContainer
*/
public void showPopup(int location, Component owner) {
setDetached(true);
Rectangle screenDim = getDisplayScreenBounds(owner);
// Get the bounds of the splash window
Dimension actualSize = getSize();
Dimension size = actualSize.width == 0 ? getPreferredSize() : actualSize;
Point displayLocation = getDisplayStartLocation(screenDim, size, location);
internalShowPopup(displayLocation.x, displayLocation.y, owner);
}
/**
* Set the display start location of the popup.
*
* @param startLocation the display start location.
* @see #getDisplayStartLocation(java.awt.Rectangle, java.awt.Dimension, int)
*/
public void setDisplayStartLocation(Point startLocation) {
_displayStartLocation = startLocation;
}
/**
* Get the display start location of the popup. It will automatically calculate a point if the customer didn't
* invoke {@link #setDisplayStartLocation(java.awt.Point)} explicitly. It will just return the location if the
* customer already set it.
*
* @param screenDim the dimension of the screen
* @param size the size of the popup
* @param location the direction to show the popup
* @return the display start location.
*/
protected Point getDisplayStartLocation(Rectangle screenDim, Dimension size, int location) {
if (_displayStartLocation != null) {
return _displayStartLocation;
}
switch (location) {
case SwingConstants.CENTER:
return new Point(screenDim.x + (screenDim.width - size.width) / 2,
screenDim.y + (screenDim.height - size.height) / 2);
case SwingConstants.SOUTH:
return new Point(screenDim.x + (screenDim.width - size.width) / 2,
screenDim.y + screenDim.height - size.height - DISTANCE_TO_SCREEN_BORDER);
case SwingConstants.NORTH:
return new Point(screenDim.x + (screenDim.width - size.width) / 2,
screenDim.y + DISTANCE_TO_SCREEN_BORDER);
case SwingConstants.EAST:
return new Point(screenDim.x + screenDim.width - size.width - DISTANCE_TO_SCREEN_BORDER,
screenDim.y + (screenDim.height - size.height) / 2);
case SwingConstants.WEST:
return new Point(screenDim.x + DISTANCE_TO_SCREEN_BORDER,
screenDim.y + (screenDim.height - size.height) / 2);
case SwingConstants.SOUTH_WEST:
return new Point(screenDim.x + DISTANCE_TO_SCREEN_BORDER,
screenDim.y + screenDim.height - size.height - DISTANCE_TO_SCREEN_BORDER);
case SwingConstants.NORTH_EAST:
return new Point(screenDim.x + screenDim.width - size.width - DISTANCE_TO_SCREEN_BORDER,
screenDim.y + DISTANCE_TO_SCREEN_BORDER);
case SwingConstants.NORTH_WEST:
return new Point(screenDim.x + DISTANCE_TO_SCREEN_BORDER,
screenDim.y + DISTANCE_TO_SCREEN_BORDER);
case SwingConstants.SOUTH_EAST:
default:
return new Point(screenDim.x + screenDim.width - size.width - DISTANCE_TO_SCREEN_BORDER,
screenDim.y + screenDim.height - size.height - DISTANCE_TO_SCREEN_BORDER);
}
}
protected Rectangle getDisplayScreenBounds(Component owner) {
Rectangle screenDim;
if (owner != null && owner.isShowing()) {
screenDim = owner.getBounds();
Point p = owner.getLocationOnScreen();
screenDim.x = p.x;
screenDim.y = p.y;
}
else {
screenDim = getOwner() == null ? PortingUtils.getLocalScreenBounds() : PortingUtils.getScreenBounds(getOwner(), true);
}
return screenDim;
}
/**
* Packs the popup. Setting size only if it's a light weight popup. Otherwise do pack.
*/
public void packPopup() {
if (_popupType == LIGHT_WEIGHT_POPUP) {
if (_panel == null) {
return;
}
_panel.setSize(_panel.getPreferredSize());
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if (_window == null) {
return;
}
_window.pack();
}
}
//David: To account for a popup within a popup, let the caller specify an owner
// different from the RootPaneContainer(Applet) or ContentContainer.
protected void internalShowPopup(int x, int y) {
internalShowPopup(x, y, null);
}
protected void internalShowPopup(int x, int y, Component owner) {
_actualOwner = owner != null ? owner : getOwner();
if (_actualOwner != null) {
try {
_actualOwnerLocation = _actualOwner.getLocationOnScreen();
}
catch (IllegalComponentStateException e) {
return;
}
}
createWindow(_actualOwner, x, y);
showPopupImmediately();
}
/**
* Gets the rectangle adjusted by preferred size and the monitor device settings. The client property
* "useAllMonitorDevices" could be registered in any ancestor component of the owner component to take effect.
*
* @param x the original x
* @param y the original y
* @param owner the owner component
* @return the adjusted rectangle according to the preferred size and monitor devie settings.
* @since 3.4.1
*/
protected Rectangle getAdjustedRectangle(int x, int y, Component owner) {
boolean useAllDevices = false;
if (owner instanceof JComponent) {
JComponent comp = (JComponent) owner;
while (comp != null) {
Object property = comp.getClientProperty("useAllMonitorDevices");
if (property instanceof Boolean) {
useAllDevices = (Boolean) property;
break;
}
if (!(comp.getParent() instanceof JComponent)) {
break;
}
comp = (JComponent) comp.getParent();
}
}
Dimension size = getSize();
return PortingUtils.containsInScreenBounds(owner, new Rectangle(x, y, size.width, size.height), !useAllDevices);
}
protected void createWindow(Component owner, int x, int y) {
if (_popupType == LIGHT_WEIGHT_POPUP) {
if (_panel == null) {
_panel = createLightweightPopupContainer(owner);
_resizableSupport = _panel;
installListeners();
installBorder();
}
if (_previousSize != null && isKeepPreviousSize()) {
setPreferredSize(null);
if (_previousSize.width < 0) {
_previousSize.width = getPreferredSize().width;
}
if (_previousSize.height < 0) {
_previousSize.height = getPreferredSize().height;
}
setPreferredSize(_previousSize);
}
_previousSize = null;
packPopup();
if (_insets != null) {
Point p = getPopupLocation(new Point(x, y), _panel.getSize(), owner);
x = p.x;
y = p.y;
}
JRootPane rootPane = JideSwingUtilities.getOutermostRootPane(owner);
JLayeredPane layeredPane;
if (rootPane != null)
layeredPane = rootPane.getLayeredPane();
else {
return; // has to have layer pane
}
Point p = new Point(x, y);
SwingUtilities.convertPointFromScreen(p, layeredPane);
layeredPane.add(_panel, JLayeredPane.PALETTE_LAYER);
if (SystemInfo.isJdk15Above()) {
layeredPane.setComponentZOrder(_panel, 0);
}
_panel.setLocation(p.x, p.y);
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if (_window == null) {
_window = createHeavyweightPopupContainer(owner);
_resizableSupport = _window;
installListeners();
installBorder();
}
if (_previousSize != null && isKeepPreviousSize()) {
setPreferredSize(null);
if (_previousSize.width < 0) {
_previousSize.width = getPreferredSize().width;
}
if (_previousSize.height < 0) {
_previousSize.height = getPreferredSize().height;
}
setPreferredSize(_previousSize);
}
_previousSize = null;
packPopup();
if (_insets != null) {
Point p = getPopupLocation(new Point(x, y), _window.getSize(), owner);
x = p.x;
y = p.y;
}
_window.setLocation(x, y);
}
}
/**
* Shows the popup at the specified x and y coordinates.
*
* @param x the x position. It is screen position.
* @param y the y position. It is screen position.
*/
public void showPopup(int x, int y) {
showPopup(x, y, null);
}
/**
* Shows the popup at the specified x and y coordinates.
*
* @param x the x position. It is screen position.
* @param y the y position. It is screen position.
* @param owner the popup window's owner; if unspecified, it will default to the RootPaneContainer(Applet) or
* ContentContainer
*/
public void showPopup(int x, int y, Component owner) {
internalShowPopup(x, y, owner);
}
protected static Frame getFrame(Component c) {
Component w = c;
while (!(w instanceof Frame) && (w != null)) {
w = w.getParent();
}
return (Frame) w;
}
/**
* @param owner the owner for this popup container. It will be used to find the top level ancestor and use it as the
* parent for this popup window.
* @return a ResizableWindow.
*/
protected ResizableWindow createHeavyweightPopupContainer(Component owner) {
ResizableWindow container;
Component topLevelAncestor = getTopLevelAncestor(owner);
if (topLevelAncestor instanceof Frame) {
container = new ResizableWindow((Frame) topLevelAncestor);
}
else if (topLevelAncestor instanceof Window) {
container = new ResizableWindow((Window) topLevelAncestor);
}
else {
Frame frame = getFrame(owner);
container = new ResizableWindow(frame);
}
container.setName("JidePopup");
container.getContentPane().add(this);
Object opaque = getClientProperty(CLIENT_PROPERTY_WINDOW_OPAQUE);
if (opaque instanceof Boolean) {
JideSwingUtilities.setWindowOpaque(container, (Boolean) opaque);
}
Object opacity = getClientProperty(CLIENT_PROPERTY_WINDOW_OPACITY);
if (opacity instanceof Float) {
JideSwingUtilities.setWindowOpacity(container, (Float) opacity);
}
Object shape = getClientProperty(CLIENT_PROPERTY_WINDOW_SHAPE);
if (shape instanceof Shape) {
JideSwingUtilities.setWindowShape(container, (Shape) shape);
}
return container;
}
/**
* Creates lightweight container for the popup.
*
* @param owner the owner for this popup container. This parameter is not used in this method. It was there mainly
* because the corresponding {@link #createHeavyweightPopupContainer(java.awt.Component)} has this
* parameter.
* @return a ResizablePanel
*/
@SuppressWarnings({"UnusedDeclaration"})
protected ResizablePanel createLightweightPopupContainer(Component owner) {
ResizablePanel panel = new ResizablePanel() {
@Override
protected Resizable createResizable() {
return new Resizable(this) {
@Override
public void resizing(int resizeCorner, int newX, int newY, int newW, int newH) {
setBounds(newX, newY, newW, newH);
}
};
}
};
panel.setVisible(false);
panel.setOpaque(false);
panel.setLayout(new BorderLayout());
panel.add(this);
return panel;
}
protected void installListeners() {
//David: Adding the MouseEventHandler synchronously causes a strange
// initialization sequence if the popup owner is a tree/table editor:
//
// - The editor gets moved to its initial location based on the cell location,
// generating a COMPONENT_MOVED ComponentEvent.
// - You add the MouseEventHandler, which includes a ComponentEvent listener on
// the owner's hierarchy, including the editor.
// - ComponentEvent is asynchronous. The ComponentEvent generated from moving
// the editor to its initial position was placed on the event queue. So the
// ComponentEvent gets handled by the MouseEventHandler's ComponentEvent
// listener, even though it happened before the listener was added.
//
// I fixed it by calling addMouseEventHandler asynchronously, guaranteeing that
// any previously-generated event it may listen for has been removed from the
// event queue before the listener is added.
//
// This causes a couple of minor problems:
//
// - It is possible that hidePopupImmediately can be called synchronously before
// the asynchronous call to addMouseEventHandler is executed. This can cause
// NPEs because the listener handler methods dereference _window, which is set
// to null in hidePopupImmediately. So I added null checks on _window in the
// listener handler methods.
//
// - The removeMouseEventHandler method is called from hidePopupImmediately.
// That means it could be called before addMouseEventHandler is executed
// asynchronously; that would result in the listener not getting removed. So
// I changed the removeMouseEventHandler to an asynchronous call, as well.
//
// This issue appeared in the 1.8.3 release because you changed the
// COMPONENT_MOVED handler to hide the popup instead of moving it. Since you
// made this an option in the 1.8.4 release, all of this asynchronous code is
// needed.
//
// addMouseEventHandler()
SwingUtilities.invokeLater(new Runnable() {
public void run() {
addMouseEventHandler();
}
});
_componentListener = new ComponentAdapter() {
@Override
public void componentHidden(ComponentEvent e) {
hidePopup();
}
};
_escapeActionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
hidePopupImmediately(true);
}
};
registerKeyboardAction(_escapeActionListener, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
if (_popupType == HEAVY_WEIGHT_POPUP) {
_window.addComponentListener(_componentListener);
_windowListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
hidePopupImmediately(true);
}
};
_window.addWindowListener(_windowListener);
}
Component owner = getActualOwner();
if (owner != null) {
_ownerComponentListener = new ComponentAdapter() {
@Override
public void componentHidden(ComponentEvent e) {
ancestorHidden();
}
@Override
public void componentMoved(ComponentEvent e) {
try {
if (_actualOwnerLocation == null || _actualOwner == null || !_actualOwner.getLocationOnScreen().equals(_actualOwnerLocation)) {
ancestorMoved();
}
}
catch (Exception ex) {
// ignore in case IllegalComponentStateException happens in getLocationOnScreen
}
}
};
owner.addComponentListener(_ownerComponentListener);
_hierarchyListener = new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
ancestorHidden();
}
};
owner.addHierarchyListener(_hierarchyListener);
}
_popupResizeListener = new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
removeComponentListener(_popupResizeListener);
contentResized();
addComponentListener(_popupResizeListener);
}
};
addComponentListener(_popupResizeListener);
}
protected void contentResized() {
// pack is good enough to replace all code above
packPopup();
}
protected void installBorder() {
if (getPopupBorder() != null && (!(_resizableSupport instanceof Component) || getPopupBorder().getBorderInsets((Component) _resizableSupport) != null)) {
if (isResizable()) {
_resizableSupport.getResizable().setResizableCorners(Resizable.ALL);
}
else {
_resizableSupport.getResizable().setResizableCorners(Resizable.NONE);
}
_resizableSupport.setBorder(getPopupBorder());
}
else {
if (isDetached()) {
if (isResizable()) {
_resizableSupport.getResizable().setResizableCorners(Resizable.ALL);
}
else {
_resizableSupport.getResizable().setResizableCorners(Resizable.NONE);
}
_resizableSupport.setBorder(UIDefaultsLookup.getBorder("Resizable.resizeBorder"));
}
else {
if (isResizable()) {
_resizableSupport.getResizable().setResizableCorners(Resizable.RIGHT | Resizable.LOWER | Resizable.LOWER_RIGHT);
}
else {
_resizableSupport.getResizable().setResizableCorners(Resizable.NONE);
}
if (!CLIENT_PROPERTY_VALUE_POPUP_TYPE_COMBOBOX.equals(getClientProperty(CLIENT_PROPERTY_POPUP_TYPE))) {
Border border = UIDefaultsLookup.getBorder("PopupMenu.border");
if (border != null && (!(_resizableSupport instanceof Component) || border.getBorderInsets((Component) _resizableSupport) != null)) {
_resizableSupport.setBorder(border);
}
}
}
}
}
protected void showPopupImmediately() {
boolean needFireEvents = true;
if (_popupType == LIGHT_WEIGHT_POPUP) {
if (_panel == null) {
return;
}
_panel.applyComponentOrientation(getComponentOrientation());
if (_panel.isVisible()) {
needFireEvents = false;
}
if (needFireEvents) {
firePopupMenuWillBecomeVisible();
}
if (!_panel.isVisible()) {
packPopup();
_panel.setVisible(true);
}
if (needFireEvents) {
firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE);
}
if (isFocusable() || getDefaultFocusComponent() != null) {
// only allow window to have focus when there is a default focus component.
if (getDefaultFocusComponent() != null) {
Runnable runnable = new Runnable() {
public void run() {
Component c = getDefaultFocusComponent();
if (c instanceof JComponent) {
((JComponent) c).requestFocus(true);
}
}
};
SwingUtilities.invokeLater(runnable);
}
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if (_window == null) {
return;
}
if (_window.isVisible()) {
needFireEvents = false;
}
_window.applyComponentOrientation(getComponentOrientation());
if (needFireEvents) {
firePopupMenuWillBecomeVisible();
}
// only when the focus cycle root is true, the component in JidePopup won't request focus automatically.
if (!isFocusable() && getDefaultFocusComponent() == null) {
_window.setFocusableWindowState(false);
}
else {
setFocusCycleRoot(true);
}
if (!_window.isVisible()) {
_window.pack();
_window.setVisible(true);
Window owner = _window.getOwner();
if (owner == null || owner.getClass().getName().contains("LightweightFrame")) { // workaround for a JavaFX limitation when SwingNode is used, there is no way to set the JavaFX main window as the owner
_window.setAlwaysOnTop(true);
}
}
if (needFireEvents) {
firePropertyChange("visible", Boolean.FALSE, Boolean.TRUE);
}
if (isFocusable() || getDefaultFocusComponent() != null) {
// only allow window to have focus when there is a default focus component.
_window.setFocusable(true);
if (getDefaultFocusComponent() != null) {
Runnable runnable = new Runnable() {
public void run() {
Component c = getDefaultFocusComponent();
if (c instanceof JComponent) {
((JComponent) c).requestFocus(true);
}
}
};
SwingUtilities.invokeLater(runnable);
}
}
JButton defaultButton = getRootPane().getDefaultButton();
if (defaultButton != null) {
getRootPane().setDefaultButton(null);
getRootPane().setDefaultButton(defaultButton); // reset the default button after _window is created so that the KeyboardManager could register the resize window correctly to handle default button
}
}
if (getTimeout() != 0) {
startTimeoutTimer();
}
}
protected void movePopup() {
if (isPopupVisible()) {
if (!isDetached() && _actualOwner != null) {
if (_insets != null) {
showPopup(_insets, _actualOwner);
}
else if (_actualOwnerLocation != null) {
Point newLocation = _actualOwner.getLocationOnScreen();
Point p = null;
if (_popupType == LIGHT_WEIGHT_POPUP) {
p = _panel.getLocationOnScreen();
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
p = _window.getLocationOnScreen();
// light weight popup followed already but heavy weight popup didn't
if (p != null) {
p.x += newLocation.x - _actualOwnerLocation.x;
p.y += newLocation.y - _actualOwnerLocation.y;
}
}
if (p != null) {
showPopup(p.x, p.y, _actualOwner);
}
}
}
}
}
private boolean _isDragging = false;
/**
* Mouse location related the frame it drags.
*/
private double _relativeX,
_relativeY;
private Point _startPoint;
private Window _currentWindow;
private JPanel _currentPanel;
protected void endDragging() {
_isDragging = false;
if (_popupType == LIGHT_WEIGHT_POPUP) {
_currentPanel = null;
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if (_currentWindow instanceof JWindow && ((JWindow) _currentWindow).getGlassPane() != null) {
((JWindow) _currentWindow).getGlassPane().setVisible(false);
((JWindow) _currentWindow).getGlassPane().setCursor(Cursor.getDefaultCursor());
}
else if (_currentWindow instanceof JDialog && ((JDialog) _currentWindow).getGlassPane() != null) {
((JDialog) _currentWindow).getGlassPane().setVisible(false);
((JDialog) _currentWindow).getGlassPane().setCursor(Cursor.getDefaultCursor());
}
_currentWindow = null;
}
_relativeX = 0;
_relativeY = 0;
}
@SuppressWarnings({"UnusedDeclaration"})
protected void beginDragging(JComponent f, int mouseX, int mouseY, double relativeX, double relativeY) {
_relativeX = relativeX;
_relativeY = relativeY;
Component owner = getActualOwner();
if (_popupType == LIGHT_WEIGHT_POPUP) {
_currentPanel = _panel;
_isDragging = true;
if (isDetached() && owner != null) {
_startPoint = owner.getLocationOnScreen();
_startPoint.y += owner.getHeight();
}
else {
_startPoint = _currentPanel.getLocationOnScreen();
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if (f.getTopLevelAncestor() instanceof JWindow)
_currentWindow = (JWindow) f.getTopLevelAncestor();
if (f.getTopLevelAncestor() instanceof JDialog)
_currentWindow = (JDialog) f.getTopLevelAncestor();
if (_currentWindow instanceof JWindow && ((JWindow) _currentWindow).getGlassPane() != null) {
((JWindow) _currentWindow).getGlassPane().setVisible(true);
((JWindow) _currentWindow).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
else if (_currentWindow instanceof JDialog && ((JDialog) _currentWindow).getGlassPane() != null) {
((JDialog) _currentWindow).getGlassPane().setVisible(true);
((JDialog) _currentWindow).getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
_isDragging = true;
if (isDetached() && owner != null) {
_startPoint = owner.getLocationOnScreen();
_startPoint.y += owner.getHeight();
}
else {
_startPoint = _currentWindow.getLocationOnScreen();
}
}
}
protected boolean isDragging() {
return _isDragging;
}
static void convertPointToScreen(Point p, Component c, boolean startInFloat) {
int x, y;
do {
if (c instanceof JComponent) {
x = c.getX();
y = c.getY();
}
else if (c instanceof java.applet.Applet || (startInFloat ? c instanceof Window : c instanceof JFrame)) {
try {
Point pp = c.getLocationOnScreen();
x = pp.x;
y = pp.y;
}
catch (IllegalComponentStateException icse) {
x = c.getX();
y = c.getY();
}
}
else {
x = c.getX();
y = c.getY();
}
p.x += x;
p.y += y;
if ((startInFloat ? c instanceof Window : c instanceof JFrame) || c instanceof java.applet.Applet)
break;
c = c.getParent();
}
while (c != null);
}
@SuppressWarnings({"UnusedDeclaration"})
protected void drag(JComponent f, int newX, int newY, int mouseModifiers) {
if (_popupType == LIGHT_WEIGHT_POPUP) {
int x = newX - (int) (_currentPanel.getWidth() * _relativeX);
int y = newY - (int) (_currentPanel.getHeight() * _relativeY);
Rectangle bounds = new Rectangle(x, y, _currentPanel.getWidth(), _currentPanel.getHeight());
Rectangle screenBounds = PortingUtils.getScreenBounds(_currentPanel, true);
if (bounds.y + bounds.height > screenBounds.y + screenBounds.height) {
bounds.y = screenBounds.y + screenBounds.height - bounds.height;
}
if (bounds.y < screenBounds.y) {
bounds.y = screenBounds.y;
}
if (isAttachable() && isWithinAroundArea(new Point(x, y), _startPoint)) {
Point p = new Point(_startPoint);
SwingUtilities.convertPointFromScreen(p, _currentPanel.getParent());
_currentPanel.setLocation(p);
setDetached(false);
}
else {
Point p = new Point(x, y);
SwingUtilities.convertPointFromScreen(p, _currentPanel.getParent());
_currentPanel.setLocation(p);
setDetached(true);
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
int x = newX - (int) (_currentWindow.getWidth() * _relativeX);
int y = newY - (int) (_currentWindow.getHeight() * _relativeY);
Rectangle bounds = new Rectangle(x, y, _currentWindow.getWidth(), _currentWindow.getHeight());
Rectangle screenBounds = PortingUtils.getScreenBounds(_currentWindow, true);
if (bounds.y + bounds.height > screenBounds.y + screenBounds.height) {
bounds.y = screenBounds.y + screenBounds.height - bounds.height;
}
if (bounds.y < screenBounds.y) {
bounds.y = screenBounds.y;
}
if (isAttachable() && isWithinAroundArea(new Point(x, y), _startPoint)) {
_currentWindow.setLocation(_startPoint);
setDetached(false);
}
else {
_currentWindow.setLocation(x, y);
setDetached(true);
}
}
}
private Insets _backToOriginalInsets = new Insets(10, 10, 10, 10);
boolean isWithinAroundArea(Point p, Point newPoint) {
if (getBackToOriginalInsets().left == 0 && getBackToOriginalInsets().top == 0 && getBackToOriginalInsets().right == 0 && getBackToOriginalInsets().bottom == 0) {
return false;
}
Rectangle rect = new Rectangle(p.x - getBackToOriginalInsets().left, p.y - getBackToOriginalInsets().top, p.x + getBackToOriginalInsets().right, p.y + getBackToOriginalInsets().bottom);
return rect.contains(newPoint);
}
// private AWTEventListener _awtEventListener = new AWTEventListener() {
// public void eventDispatched(AWTEvent event) {
// if (event instanceof MouseEvent) {
// if (event.getID() == MouseEvent.MOUSE_PRESSED) {
// MouseEvent e = (MouseEvent) event;
// Object source = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY());
// if (!isAncestorOf((Container) source, JidePopup.this.getTopLevelAncestor())) { // todo: add a flag to not hidePopup in some cases
// hidePopup();
// }
// else {
// Point point = SwingUtilities.convertPoint((Component) e.getSource(), e.getPoint(), JidePopup.this);
//
// Rectangle startingBounds = JidePopup.this.getTopLevelAncestor().getBounds();
// _relativeX = (double) point.x / startingBounds.width;
// _relativeY = (double) point.y / startingBounds.height;
//
// Point screenPoint = new Point(e.getX(), e.getY());
// JidePopup.convertPointToScreen(screenPoint, (Component) e.getSource(), true);
//
// // drag on gripper
// if (source == JidePopup.this.getUI().getGripper()) {
// beginDragging(JidePopup.this, screenPoint.x, screenPoint.y, _relativeX, _relativeY);
// e.consume();
// }
// }
// }
// else if (event.getID() == MouseEvent.MOUSE_DRAGGED) {
// if (isDragging()) {
// MouseEvent e = (MouseEvent) event;
// Point screenPoint = e.getPoint();
// convertPointToScreen(screenPoint, ((Component) e.getSource()), true);
// drag(null, screenPoint.x, screenPoint.y, e.getModifiersEx());
// e.consume();
// }
// }
// else if (event.getID() == MouseEvent.MOUSE_RELEASED) {
// if (isDragging()) {
// MouseEvent e = (MouseEvent) event;
// endDragging();
// e.consume();
// }
// }
// else if (event.getID() == MouseEvent.MOUSE_ENTERED) {
// if (_window.isAncestorOf(((Component) event.getSource())) && getTimeout() != 0) {
// stopTimeoutTimer();
// }
// }
// else if (event.getID() == MouseEvent.MOUSE_EXITED) {
// if (_window.isAncestorOf(((Component) event.getSource())) && getTimeout() != 0) {
// startTimeoutTimer();
// }
// }
// }
// else if (event instanceof WindowEvent) {
// WindowEvent e = (WindowEvent) event;
// if (e.getSource() != JidePopup.this.getTopLevelAncestor() && isAncestorOf(getOwner(), e.getWindow())) {
// if (e.getID() == WindowEvent.WINDOW_CLOSING || e.getID() == WindowEvent.WINDOW_ICONIFIED) {
// hidePopup();
// }
// }
// }
// else if (event instanceof ComponentEvent) {
// ComponentEvent e = (ComponentEvent) event;
// if (e.getID() == ComponentEvent.COMPONENT_HIDDEN && isAncestorOf(getOwner(), e.getSource())) {
// hidePopup();
// }
// else if (e.getID() == ComponentEvent.COMPONENT_MOVED && isAncestorOf(getOwner(), e.getSource())) {
// movePopup();
// }
// }
// }
// };
private AWTEventListener _awtEventListener;
protected void handleMousePressed(MouseEvent e) {
Component c = e.getComponent();
if (c == null) {
return;
}
Component clickedComponent = (Component) e.getSource();
Object popupMenuToCancel = getClientProperty("popupMenuToCancel");
if (clickedComponent instanceof JComponent && HIDE_POPUP_KEY != null && popupMenuToCancel != null && ((JComponent) clickedComponent).getClientProperty("doNotCancelPopup") == HIDE_POPUP_KEY && this.isAncestorOf(clickedComponent)) {
MenuSelectionManager manager = MenuSelectionManager.defaultManager();
MenuElement[] menuElements = manager.getSelectedPath();
if (menuElements != null) {
for (MenuElement element : menuElements) {
if (element == popupMenuToCancel) {
manager.clearSelectedPath();
break;
}
}
}
}
Component component = SwingUtilities.getDeepestComponentAt(c, e.getX(), e.getY());
if (!isClickOnPopup(e)) {
if (isExcludedComponent(component)) {
return;
}
ancestorHidden();
}
else if (isPopupVisible()) {
Point point = SwingUtilities.convertPoint(component, e.getPoint(), this);
Rectangle startingBounds = null;
if (_popupType == LIGHT_WEIGHT_POPUP) {
startingBounds = _panel.getBounds();
Container parent = _panel.getParent();
if (SystemInfo.isJdk15Above()) {
if (isClickOnPopup(e) && parent.getComponentZOrder(_panel) != 0) {
parent.setComponentZOrder(_panel, 0);
parent.repaint();
}
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
final Window sourceWindow = SwingUtilities.getWindowAncestor(component);
if (sourceWindow == _window) {
startingBounds = _window.getBounds();
if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusedWindow() != _window) {
_window.toFront();
}
}
}
if (startingBounds != null) {
_relativeX = (double) point.x / startingBounds.width;
_relativeY = (double) point.y / startingBounds.height;
Point screenPoint = new Point(e.getX(), e.getY());
convertPointToScreen(screenPoint, component, true);
// drag on gripper
final Component gripper = getUI().getGripper();
if (gripper instanceof Container && (gripper == component || ((Container) gripper).isAncestorOf(component))) {
beginDragging(this, screenPoint.x, screenPoint.y, _relativeX, _relativeY);
e.consume();
}
}
}
}
protected void handleMouseReleased(MouseEvent e) {
if (isDragging()) {
endDragging();
e.consume();
}
}
protected void handleMouseDragged(MouseEvent e) {
if (isDragging()) {
Point screenPoint = e.getPoint();
if (e.getSource() instanceof Component) {
convertPointToScreen(screenPoint, ((Component) e.getSource()), true);
drag(null, screenPoint.x, screenPoint.y, e.getModifiersEx());
e.consume();
}
}
}
protected void handleMouseEntered(MouseEvent e) {
if (_popupType == LIGHT_WEIGHT_POPUP) {
if ((_panel != null) && e.getSource() instanceof Component &&
_panel.isAncestorOf(((Component) e.getSource())) && getTimeout() != 0) {
stopTimeoutTimer();
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if ((_window != null) && e.getSource() instanceof Component &&
_window.isAncestorOf(((Component) e.getSource())) && getTimeout() != 0) {
stopTimeoutTimer();
}
}
}
protected void handleMouseExited(MouseEvent e) {
if (_popupType == LIGHT_WEIGHT_POPUP) {
if ((_panel != null) && e.getSource() instanceof Component &&
_panel.isAncestorOf(((Component) e.getSource())) && getTimeout() != 0) {
startTimeoutTimer();
}
}
else if (_popupType == HEAVY_WEIGHT_POPUP) {
if ((_window != null) && e.getSource() instanceof Component &&
_window.isAncestorOf(((Component) e.getSource())) && getTimeout() != 0) {
startTimeoutTimer();
}
}
}
private static boolean checkedUnpostPopup;
private static boolean unpostPopup;
private static boolean doUnpostPopupOnDeactivation() {
if (!checkedUnpostPopup) {
unpostPopup = (Boolean) java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy