1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/* Glazed Lists (c) 2003-2006 */
/* http://publicobject.com/glazedlists/ publicobject.com,*/
/* O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.impl.swing;
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
/**
* Fix a problem where the JComboBox's popup obscures its editor in the Mac OS X
* Aqua look and feel.
*
* <p>Installing this fix will resolve the problem for Aqua without having
* side-effects for other look-and-feels. It also supports dynamically changed
* look and feels.
*
* @see <a href="https://glazedlists.dev.java.net/issues/show_bug.cgi?id=332">bug 332</a>
*
* @author <a href="mailto:jesse@swank.ca">Jesse Wilson</a>
*/
public final class ComboBoxPopupLocationFix {
/** the components being fixed */
private final JComboBox comboBox;
private final JPopupMenu popupMenu;
/** the listener provides callbacks as necessary */
private final Listener listener = new Listener();
/**
* Private constructor so users use the more action-oriented
* {@link #install} method.
*/
private ComboBoxPopupLocationFix(JComboBox comboBox) {
this.comboBox = comboBox;
this.popupMenu = (JPopupMenu)comboBox.getUI().getAccessibleChild(comboBox, 0);
popupMenu.addPopupMenuListener(listener);
}
/**
* Install the fix for the specified combo box.
*/
public static ComboBoxPopupLocationFix install(JComboBox comboBox) {
if(comboBox == null) throw new IllegalArgumentException();
return new ComboBoxPopupLocationFix(comboBox);
}
/**
* Uninstall the fix. Usually this is unnecessary since letting the combo
* box go out of scope is sufficient.
*/
public void uninstall() {
popupMenu.removePopupMenuListener(listener);
}
/**
* Reposition the popup immediately before it is shown.
*/
private class Listener implements PopupMenuListener {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
final JComponent popupComponent = (JComponent) e.getSource();
fixPopupLocation(popupComponent);
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
// do nothing
}
public void popupMenuCanceled(PopupMenuEvent e) {
// do nothing
}
}
/**
* Do the adjustment on the specified popupComponent immediately before
* it is displayed.
*/
private void fixPopupLocation(JComponent popupComponent) {
// we only need to fix Apple's aqua look and feel
if(popupComponent.getClass().getName().indexOf("apple.laf") != 0) {
return;
}
// put the popup right under the combo box so it looks like a
// normal Aqua combo box
Point comboLocationOnScreen = comboBox.getLocationOnScreen();
int comboHeight = comboBox.getHeight();
int popupY = comboLocationOnScreen.y + comboHeight;
// ...unless the popup overflows the screen, in which case we put it
// above the combobox
Rectangle screenBounds = new ScreenGeometry(comboBox).getScreenBounds();
int popupHeight = popupComponent.getPreferredSize().height;
if(comboLocationOnScreen.y + comboHeight + popupHeight > screenBounds.x + screenBounds.height) {
popupY = comboLocationOnScreen.y - popupHeight;
}
popupComponent.setLocation(comboLocationOnScreen.x, popupY);
}
}
|