0001: package abbot.util;
0002:
0003: import java.applet.Applet;
0004: import java.awt.*;
0005: import java.awt.event.*;
0006: import java.beans.PropertyChangeEvent;
0007: import java.beans.PropertyChangeListener;
0008: import java.lang.reflect.*;
0009: import java.util.*;
0010: import java.util.List;
0011:
0012: import javax.swing.*;
0013: import javax.swing.text.View;
0014:
0015: import sun.awt.AppContext;
0016: import abbot.Log;
0017: import abbot.Platform;
0018: import abbot.finder.*;
0019: import abbot.finder.matchers.ClassMatcher;
0020: import abbot.tester.*;
0021: import abbot.tester.Robot;
0022:
0023: /** Various AWT utilities to facilitate component-oriented operations. */
0024:
0025: public class AWT {
0026:
0027: public static int POPUP_TIMEOUT = 5000;
0028:
0029: private static Hierarchy hierarchy = new AWTHierarchy();
0030:
0031: static {
0032: String to = System.getProperty("abbot.finder.popup_timeout");
0033: if (to != null) {
0034: try {
0035: POPUP_TIMEOUT = Integer.parseInt(to);
0036: } catch (Exception e) {
0037: }
0038: }
0039: }
0040:
0041: private static final Point RELATIVE_OFFSET = new Point(10, 10);
0042:
0043: /** Set this client property on components which contain a heavyweight
0044: * component. Use {@link Boolean#TRUE} as the value.
0045: */
0046: public final static String CONTAINS_HEAVYWEIGHT_COMPONENT = "containsHeavyweightComponent";
0047: /** Offset from the position of the currently active window to the
0048: * position of a new window.
0049: */
0050: public static final Point DEFAULT_CASCADE = new Point(15, 15);
0051:
0052: /** Return whether the given {@link Point} is visible on any screen. */
0053: public static boolean onScreen(Point p) {
0054: GraphicsEnvironment env = GraphicsEnvironment
0055: .getLocalGraphicsEnvironment();
0056: GraphicsDevice[] gs = env.getScreenDevices();
0057: for (int i = 0; i < gs.length; i++) {
0058: GraphicsConfiguration[] gc = gs[i].getConfigurations();
0059: for (int j = 0; j < gc.length; j++) {
0060: Rectangle r = getVisibleBounds(gc[j]);
0061: if (r.contains(p))
0062: return true;
0063: }
0064: }
0065: return false;
0066: }
0067:
0068: /** Returns whether one of the upper corners of the given window is
0069: * accessible.
0070: */
0071: public static boolean onScreen(Window w) {
0072: return onScreen(w.getLocation())
0073: || onScreen(new Point(w.getX() + w.getWidth() - 1, w
0074: .getY()));
0075: }
0076:
0077: /** Returns the GraphicsConfiguration which contains the given point,
0078: * or null if none.
0079: */
0080: public static GraphicsConfiguration getGraphicsConfiguration(Point p) {
0081: GraphicsEnvironment env = GraphicsEnvironment
0082: .getLocalGraphicsEnvironment();
0083: GraphicsDevice[] gs = env.getScreenDevices();
0084: for (int i = 0; i < gs.length; i++) {
0085: GraphicsConfiguration[] gc = gs[i].getConfigurations();
0086: Rectangle bounds = getVisibleBounds(gc[i]);
0087: if (bounds.contains(p)) {
0088: return gc[i];
0089: }
0090: }
0091: return null;
0092: }
0093:
0094: /** Returns a Rectangle spanning all screens. Note that not all pixels
0095: * within the rectangle are necessarily on a display.<p>
0096: * Includes any toolbar/dashboard regions.
0097: */
0098: public static Rectangle getVirtualDisplayBounds(
0099: boolean includeInsets) {
0100: Rectangle bounds = null;
0101: GraphicsEnvironment env = GraphicsEnvironment
0102: .getLocalGraphicsEnvironment();
0103: GraphicsDevice[] gs = env.getScreenDevices();
0104: for (int i = 0; i < gs.length; i++) {
0105: GraphicsConfiguration[] gc = gs[i].getConfigurations();
0106: for (int j = 0; j < gc.length; j++) {
0107: Rectangle r = includeInsets ? gc[j].getBounds()
0108: : getVisibleBounds(gc[j]);
0109: if (bounds == null)
0110: bounds = r;
0111: else
0112: bounds = bounds.union(r);
0113: }
0114: }
0115: return bounds;
0116: }
0117:
0118: /** Return the visible bounds for the graphics configuration. This will
0119: * exclude any permanent menu bar or dashboard decorations.
0120: */
0121: public static Rectangle getVisibleBounds(GraphicsConfiguration gc) {
0122: Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
0123: Rectangle r = gc.getBounds();
0124: r.x += insets.left;
0125: r.y += insets.top;
0126: r.width -= insets.left + insets.right;
0127: r.height -= insets.top + insets.bottom;
0128: return r;
0129: }
0130:
0131: private static final int SCREEN_MARGIN = 10;
0132:
0133: /** Ensure the given window is visible on screen. */
0134: public static void ensureOnScreen(Window w) {
0135: // One of the upper corners of the window needs to be on screen
0136: if (!onScreen(w)) {
0137: Rectangle bounds = getVirtualDisplayBounds(false);
0138: int x = w.getX();
0139: int y = w.getY();
0140: if (w.getX() + w.getWidth() < bounds.x + SCREEN_MARGIN) {
0141: x = bounds.x + SCREEN_MARGIN - w.getWidth();
0142: }
0143: if (w.getX() > bounds.x + bounds.width + SCREEN_MARGIN) {
0144: x = bounds.x + bounds.width - SCREEN_MARGIN;
0145: }
0146: if (w.getY() < bounds.y + SCREEN_MARGIN) {
0147: y = bounds.y + SCREEN_MARGIN;
0148: }
0149: if (w.getY() > bounds.y + bounds.height + SCREEN_MARGIN) {
0150: y = bounds.y + bounds.height - SCREEN_MARGIN;
0151: }
0152: w.setLocation(x, y);
0153: if (!onScreen(w)) {
0154: // If still not on screen, just center it on the default screen
0155: centerOnScreen(w);
0156: }
0157: }
0158: }
0159:
0160: /** Set the position of the window in a platform-specific manner.
0161: * Uses Window.setLocationByPlatform if available, otherwise
0162: * centers on screen.
0163: */
0164: public static void setLocationByPlatform(Window w) {
0165: try {
0166: Method m = Window.class.getDeclaredMethod(
0167: "setLocationByPlatform",
0168: new Class[] { boolean.class });
0169: m.invoke(w, new Object[] { Boolean.TRUE });
0170: } catch (Exception e) {
0171: centerOnScreen(w);
0172: }
0173: }
0174:
0175: /** Ensure the given component renders its initial HTML wrapped at the
0176: * given preferred width.
0177: */
0178: public static void setHTMLPreferredWidth(JComponent c, int width) {
0179: // Something of a hack. This property gets set prior to setting
0180: // the component's initial size, so we tweak the view to have
0181: // a preferred x-axis span to what we want, restoring it after
0182: // the initial size has been set.
0183: c.addPropertyChangeListener("ancestor",
0184: new PropertyChangeListener() {
0185: final int PREF_WIDTH = 200;
0186:
0187: public void propertyChange(PropertyChangeEvent e) {
0188: JComponent c = (JComponent) e.getSource();
0189: c
0190: .removePropertyChangeListener(
0191: "ancestor", this );
0192: final View view = (View) c
0193: .getClientProperty("html");
0194: if (view != null) {
0195: final float prefx = view
0196: .getPreferredSpan(View.X_AXIS);
0197: final float prefy = view
0198: .getPreferredSpan(View.Y_AXIS);
0199: view.setSize(Math.min(PREF_WIDTH, prefx),
0200: prefy);
0201: SwingUtilities.invokeLater(new Runnable() {
0202: public void run() {
0203: view.setSize(prefx, prefy);
0204: }
0205: });
0206: }
0207: }
0208: });
0209: }
0210:
0211: /** Combine the two colors with equal weight. */
0212: public static Color combine(Color c1, Color c2) {
0213: return combine(c1, c2, 0.5f);
0214: }
0215:
0216: /** Combine the two colors, giving the requested weight to the first.
0217: */
0218: public static Color combine(Color c1, Color c2, float weight) {
0219: float w1 = (float) Math.max(Math.min(weight, 1.0), 0);
0220: float w2 = 1.0f - w1;
0221: return new Color((int) (c1.getRed() * w1 + c2.getRed() * w2),
0222: (int) (c1.getGreen() * w1 + c2.getGreen() * w2),
0223: (int) (c1.getBlue() * w1 + c2.getBlue() * w2),
0224: (int) (c1.getAlpha() * w1 + c2.getAlpha() * w2));
0225: }
0226:
0227: /** Returns true if there is an active menu on the JFrame (if any)
0228: containing the given component. */
0229: public static boolean isMenuActive(Component c) {
0230: Frame f = getFrame(c);
0231: if (f instanceof JFrame) {
0232: JFrame frame = (JFrame) f;
0233: JMenuBar mb = frame.getJMenuBar();
0234: if (mb != null) {
0235: for (int i = 0; i < mb.getMenuCount(); i++) {
0236: JMenu menu = mb.getMenu(i);
0237: if (menu == null)
0238: continue;
0239: if (menu.isSelected() || menu.isPopupMenuVisible())
0240: return true;
0241: }
0242: }
0243: }
0244:
0245: return false;
0246: }
0247:
0248: /**
0249: * Display a frame relative to the given component.
0250: */
0251: public static void showFrameRelative(Frame frame,
0252: Component relativeTo) {
0253: moveFrameRelativeTo(frame, relativeTo);
0254: if (frame.getState() == Frame.ICONIFIED) {
0255: frame.setState(Frame.NORMAL);
0256: }
0257: frame.show();
0258: }
0259:
0260: /** Center the given {@link Window} on the default screen. */
0261: public static void centerOnScreen(Window window) {
0262: Point center = GraphicsEnvironment
0263: .getLocalGraphicsEnvironment().getCenterPoint();
0264: Rectangle max = GraphicsEnvironment
0265: .getLocalGraphicsEnvironment().getMaximumWindowBounds();
0266: int x = Math.max(center.x - Math.round(window.getWidth() / 2f),
0267: max.x);
0268: int y = Math.max(
0269: center.y - Math.round(window.getHeight() / 2f), max.y);
0270: window.setLocation(new Point(x, y));
0271: }
0272:
0273: /** Center on the specified frame. */
0274: public static void centerOnFrame(Window window, Frame frame) {
0275: int ww = window.getWidth();
0276: int wh = window.getHeight();
0277:
0278: int fw = frame.getWidth();
0279: int fh = frame.getHeight();
0280:
0281: int x = (int) Math.round((double) (fw - ww) / 2);
0282: int y = (int) Math.round((double) (fh - wh) / 2);
0283:
0284: Point location = frame.getLocationOnScreen();
0285: location.translate(x, y);
0286: window.setLocation(location);
0287: ensureOnScreen(window);
0288: }
0289:
0290: public static void moveFrameRelativeTo(Frame frame,
0291: Component relativeTo) {
0292: Point location = RELATIVE_OFFSET;
0293: Window reference = null;
0294: if (relativeTo != null) {
0295: reference = getWindow(relativeTo);
0296: }
0297: if (reference != null) {
0298: location = reference.getLocationOnScreen();
0299: location.translate(RELATIVE_OFFSET.x, RELATIVE_OFFSET.y);
0300: }
0301: frame.setLocation(location);
0302: ensureOnScreen(frame);
0303: }
0304:
0305: /** Return whether the given component either has focus or is the ancestor
0306: * of the focused component.
0307: */
0308: public static boolean containsFocus(Component c) {
0309: KeyboardFocusManager mgr = KeyboardFocusManager
0310: .getCurrentKeyboardFocusManager();
0311: Component owner = mgr.getFocusOwner();
0312: return owner != null
0313: && SwingUtilities.isDescendingFrom(owner, c);
0314: }
0315:
0316: /** NOTE: on pointer-focused systems, the frontmost window is not
0317: * necessarily the one with focus.
0318: */
0319: public static Window getFocusedWindow() {
0320: KeyboardFocusManager mgr = KeyboardFocusManager
0321: .getCurrentKeyboardFocusManager();
0322: return mgr.getFocusedWindow();
0323: }
0324:
0325: /** NOTE: NOT necessarily the same thing as the focused window. */
0326: public static Window getActiveWindow() {
0327: KeyboardFocusManager mgr = KeyboardFocusManager
0328: .getCurrentKeyboardFocusManager();
0329: return mgr.getActiveWindow();
0330: }
0331:
0332: private static boolean containsHeavyweightComponent(Component root) {
0333: if (root instanceof Container) {
0334: if (root instanceof JComponent
0335: && Boolean.TRUE
0336: .equals(((JComponent) root)
0337: .getClientProperty(CONTAINS_HEAVYWEIGHT_COMPONENT))) {
0338: return true;
0339: }
0340: Container c = (Container) root;
0341: for (int i = 0; i < c.getComponentCount(); i++) {
0342: if (containsHeavyweightComponent(c.getComponents()[i])) {
0343: return true;
0344: }
0345: }
0346: }
0347: return false;
0348: }
0349:
0350: /** @return whether the hierarchy within which the given Component sits
0351: * contains a heavyweight component.
0352: */
0353: public static boolean hierarchyHasHeavyweightComponent(
0354: Component base) {
0355: Window w = getWindow(base);
0356: return containsHeavyweightComponent(w);
0357: }
0358:
0359: /** Return the {@link Frame} corresponding to the given object. */
0360: public static Frame getFrame(Object o) {
0361: Window w = getWindow(o);
0362: while (!(w instanceof Frame) && w != null) {
0363: w = (Window) w.getParent();
0364: }
0365: return w instanceof Frame ? (Frame) w : JOptionPane
0366: .getRootFrame();
0367: }
0368:
0369: /** Return the window corresponding to the given object. */
0370: public static Window getWindow(Object o) {
0371: if (o instanceof Component) {
0372: Component c = (Component) o;
0373: while (c instanceof JMenuItem) {
0374: c = c.getParent();
0375: }
0376: if (c instanceof JPopupMenu) {
0377: return getWindow(((JPopupMenu) c).getInvoker());
0378: }
0379: return c instanceof Window ? (Window) c : SwingUtilities
0380: .getWindowAncestor(c);
0381: }
0382: return JOptionPane.getRootFrame();
0383: }
0384:
0385: /** Return a copy of the given color with a new alpha component. */
0386: public static Color alpha(Color c, int alpha) {
0387: return new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha);
0388: }
0389:
0390: /** Find the first instance of the given class under the given component,
0391: * or null if none found.
0392: */
0393: public static Component find(Component root, final Class type) {
0394: return find(root, new ComponentPredicate() {
0395: public boolean evaluate(Component o) {
0396: return o != null && type.isAssignableFrom(o.getClass());
0397: }
0398: });
0399: }
0400:
0401: /** Cascade the given window based on the currently active {@link Frame}. */
0402: public static void cascade(Window w) {
0403: cascade(w, DEFAULT_CASCADE.x, DEFAULT_CASCADE.y);
0404: }
0405:
0406: /** Cascade the given window based on the currently active {@link Frame}. */
0407: public static void cascade(Window w, int xoff, int yoff) {
0408: // Make sure we get a frame, not a dialog
0409: Frame f = getFrame(getActiveWindow());
0410: if (f != null && f.isShowing()) {
0411: w.setLocation(f.getX() + xoff, f.getY() + yoff);
0412: ensureOnScreen(w);
0413: } else {
0414: centerOnScreen(w);
0415: }
0416: }
0417:
0418: public static interface ComponentPredicate {
0419: /** Return whether the given component is the desired one. */
0420: boolean evaluate(Component c);
0421: }
0422:
0423: /** Find the first component matching the given predicate,
0424: * or null if none found.
0425: */
0426: public static Component find(Component root, ComponentPredicate test) {
0427: if (test.evaluate(root))
0428: return root;
0429: if (root instanceof Container) {
0430: Component[] kids = ((Container) root).getComponents();
0431: for (int i = 0; i < kids.length; i++) {
0432: Component c = find(kids[i], test);
0433: if (c != null)
0434: return c;
0435: }
0436: }
0437: return null;
0438: }
0439:
0440: /** Find the first instance of {@link RootPaneContainer} in the given
0441: * container. Basically finds applets.
0442: */
0443: public static RootPaneContainer findRootPaneContainer(Container c) {
0444: if (c instanceof RootPaneContainer) {
0445: return (RootPaneContainer) c;
0446: }
0447: Component[] kids = c.getComponents();
0448: for (int i = 0; i < kids.length; i++) {
0449: if (kids[i] instanceof RootPaneContainer)
0450: return (RootPaneContainer) kids[i];
0451: if (kids[i] instanceof Container) {
0452: RootPaneContainer rcp = findRootPaneContainer((Container) kids[i]);
0453: if (rcp != null)
0454: return rcp;
0455: }
0456: }
0457: return null;
0458: }
0459:
0460: private AWT() {
0461: }
0462:
0463: /** Return whether the given Component has only its default name set. */
0464: public static boolean hasDefaultName(Component c) {
0465: String name = getName(c);
0466: if (name == null)
0467: return true;
0468:
0469: if (c instanceof JComponent) {
0470: return (c instanceof JLayeredPane && "null.layeredPane"
0471: .equals(name))
0472: || (c instanceof JPanel && ("null.glassPane"
0473: .equals(name) || "null.contentPane"
0474: .equals(name)));
0475: }
0476:
0477: return (c instanceof Button && Regexp.stringMatch(
0478: "button[0-9]+", name))
0479: || (c instanceof Canvas && Regexp.stringMatch(
0480: "canvas[0-9]+", name))
0481: || (c instanceof Checkbox && Regexp.stringMatch(
0482: "checkbox[0-9]+", name))
0483: || (c instanceof Choice && Regexp.stringMatch(
0484: "choice[0-9]+", name))
0485: || (c instanceof Dialog && Regexp.stringMatch(
0486: "dialog[0-9]+", name))
0487: || (c instanceof FileDialog && Regexp.stringMatch(
0488: "filedlg[0-9]+", name))
0489: || (c instanceof Frame && Regexp.stringMatch(
0490: "frame[0-9]+", name))
0491: || (c instanceof java.awt.List && Regexp.stringMatch(
0492: "list[0-9]+", name))
0493: || (c instanceof Label && Regexp.stringMatch(
0494: "label[0-9]+", name))
0495: || (c instanceof Panel && Regexp.stringMatch(
0496: "panel[0-9]+", name))
0497: || (c instanceof Scrollbar && Regexp.stringMatch(
0498: "scrollbar[0-9]+", name))
0499: || (c instanceof ScrollPane && Regexp.stringMatch(
0500: "scrollpane[0-9]+", name))
0501: || (c instanceof TextArea && Regexp.stringMatch(
0502: "text[0-9]+", name))
0503: || (c instanceof TextField && Regexp.stringMatch(
0504: "textfield[0-9]+", name))
0505: || (c instanceof Window && Regexp.stringMatch(
0506: "win[0-9]+", name));
0507: }
0508:
0509: /** Ensure the given action happens on the event dispatch thread. Any
0510: * component modifications must be invoked this way.
0511: */
0512: public static void invokeAndWait(Runnable action) {
0513: if (EventQueue.isDispatchThread()) {
0514: action.run();
0515: } else {
0516: try {
0517: EventQueue.invokeAndWait(action);
0518: } catch (InterruptedException ie) {
0519: Log.warn(ie);
0520: } catch (java.lang.reflect.InvocationTargetException ite) {
0521: Log.warn(ite);
0522: }
0523: }
0524: }
0525:
0526: /** Ensure the given action happens on the event dispatch thread. Any
0527: * component modifications must be invoked this way. Note that this is
0528: * <b>not</b> the same as EventQueue.invokeLater, since if the current
0529: * thread is the dispatch thread, the action is invoked immediately.
0530: */
0531: public static void invokeAction(Runnable action) {
0532: if (EventQueue.isDispatchThread()) {
0533: action.run();
0534: } else {
0535: EventQueue.invokeLater(action);
0536: }
0537: }
0538:
0539: /** Returns whether the menu component is on a MenuBar. */
0540: public static boolean isOnMenuBar(MenuComponent mc) {
0541: if (mc instanceof MenuBar)
0542: return true;
0543: return mc.getParent() instanceof MenuComponent
0544: && isOnMenuBar((MenuComponent) mc.getParent());
0545: }
0546:
0547: /** Returns the invoker, if any, of the given AWT menu component. Returns
0548: null if the menu component is not attached to anything, or if it is
0549: within a MenuBar hierarchy.
0550: */
0551: public static Component getInvoker(MenuComponent mc) {
0552: if (isOnMenuBar(mc))
0553: return null;
0554: MenuContainer parent = mc.getParent();
0555: while (parent instanceof MenuComponent) {
0556: parent = ((MenuComponent) parent).getParent();
0557: }
0558: return parent instanceof Component ? (Component) parent : null;
0559: }
0560:
0561: /** Returns the invoker, if any, of the given component. Returns null if
0562: * the component is not on a popup of any sort.
0563: */
0564: public static Component getInvoker(Component comp) {
0565: if (comp instanceof JPopupMenu)
0566: return ((JPopupMenu) comp).getInvoker();
0567: comp = comp.getParent();
0568: return comp != null ? getInvoker(comp) : null;
0569: }
0570:
0571: /** Similar to SwingUtilities.getWindowAncestor(), but returns the
0572: * component itself if it is a Window, or the invoker's window if on a
0573: * popup.
0574: */
0575: public static Window getWindow(Component comp) {
0576: if (comp == null)
0577: return null;
0578: if (comp instanceof Window)
0579: return (Window) comp;
0580: if (comp instanceof MenuElement) {
0581: Component invoker = getInvoker(comp);
0582: if (invoker != null)
0583: return getWindow(invoker);
0584: }
0585: return getWindow(hierarchy.getParent(comp));
0586: }
0587:
0588: /** Returns whether there is an AWT popup menu currently showing. */
0589: public static boolean isAWTPopupMenuBlocking() {
0590: // For now, just do a quick check to see if a PopupMenu is active on
0591: // w32. Extend it if we find other common situations that might block
0592: // the EDT, but for now, keep it simple and restricted to what we've
0593: // run into.
0594: // NOTE: technically, the popup menu blocks the toolkit, not the EDT,
0595: // but in practice it doesn't make much difference since the EDT
0596: // depends heavily on the toolkit.
0597: return Bugs.showAWTPopupMenuBlocks() && isAWTTreeLockHeld();
0598: }
0599:
0600: /** Returns whether the AWT Tree Lock is currently held. */
0601: private static boolean isAWTTreeLockHeld() {
0602: return isAWTTreeLockHeld(Toolkit.getDefaultToolkit()
0603: .getSystemEventQueue());
0604: }
0605:
0606: /** Returns whether the AWT Tree Lock is currently held. */
0607: public static boolean isAWTTreeLockHeld(EventQueue eq) {
0608: Frame[] frames = Frame.getFrames();
0609: if (frames.length == 0)
0610: return false;
0611:
0612: // hack based on 1.4.2 java.awt.PopupMenu implementation,
0613: // which blocks the event dispatch thread while the popup is visible,
0614: // while holding the AWT tree lock
0615:
0616: // Start another thread which attempts to get the tree lock
0617: // If it can't get the tree lock, then there is a popup active in the
0618: // current tree.
0619: // Any component can provide the tree lock
0620: ThreadStateChecker checker = new ThreadStateChecker(frames[0]
0621: .getTreeLock());
0622: try {
0623: checker.start();
0624: // Wait a little bit for the checker to finish
0625: int delay = Properties.getProperty("abbot.treelock_wait",
0626: 100, 0, 60000);
0627: if (checker.isAlive())
0628: checker.join(delay);
0629: return checker.isAlive();
0630: } catch (InterruptedException e) {
0631: return false;
0632: }
0633: }
0634:
0635: /** Ensure any extant AWT popup is dismissed. This should only be called
0636: * from off the EDT, since (at least on w32) the EDT is blocked while
0637: * an AWT popup is showing.
0638: */
0639: // FIXME this sometimes causes the windows menu to display on w32
0640: public static void dismissAWTPopup() {
0641: // If we're on the EDT, we know a priori there is no AWT popup
0642: if (SwingUtilities.isEventDispatchThread())
0643: return;
0644: java.awt.Robot robot = Robot.getRobot();
0645: if (robot != null) {
0646: Component c = getFocusOwner();
0647: if (c != null) {
0648: Window w = getWindow(c);
0649: if (w != null && w.isShowing()) {
0650: robot.keyPress(KeyEvent.VK_ESCAPE);
0651: robot.keyRelease(KeyEvent.VK_ESCAPE);
0652: }
0653: }
0654: } else {
0655: Log
0656: .warn("The current system configuation can not automatically dismiss an AWT popup");
0657: }
0658: }
0659:
0660: /** Returns whether the given MenuComponent is on a top-level AWT popup
0661: (that is, <i>not</i> under a MenuBar.
0662: */
0663: public static boolean isOnPopup(MenuComponent mc) {
0664: MenuContainer parent = mc.getParent();
0665: while (parent instanceof MenuComponent) {
0666: if (parent instanceof MenuBar)
0667: return false;
0668: parent = ((MenuComponent) parent).getParent();
0669: }
0670: return true;
0671: }
0672:
0673: /** Returns whether the given component is on a top-level popup. A
0674: * top-level popup is one generated by a popup trigger, which means popups
0675: * generated from a JMenu are not included.
0676: */
0677: public static boolean isOnPopup(Component comp) {
0678: boolean isWrapper = isTransientPopup(comp);
0679: Component invoker = getInvoker(comp);
0680: boolean isOnJMenu = invoker instanceof JMenu
0681: && invoker.getParent() instanceof JMenuBar;
0682: return isWrapper || (invoker != null && !isOnJMenu);
0683: }
0684:
0685: /** Returns whether the given component is a heavyweight popup, that is, a
0686: container for a JPopupMenu that is implemented with a heavyweight
0687: component (usually a Window).
0688: */
0689: public static boolean isHeavyweightPopup(Component c) {
0690: if (c instanceof Window && !(c instanceof Dialog)
0691: && !(c instanceof Frame)) {
0692: String name = getName(c);
0693: String cname = c.getClass().getName();
0694: return ("###overrideRedirect###".equals(name)
0695: || "###focusableSwingPopup###".equals(name)
0696: // These classes are known to be heavyweight popups
0697: // javax.swing.DefaultPopupFactory$WindowPopup (1.3)
0698: || cname.indexOf("PopupFactory$WindowPopup") != -1
0699: // javax.swing.Popup.HeavyWeightWindow (1.4)
0700: || cname.indexOf("HeavyWeightWindow") != -1);
0701: }
0702: return false;
0703: }
0704:
0705: // Work around some components throwing exceptions if getName is
0706: // called prematurely
0707: private static String getName(Component c) {
0708: try {
0709: return c.getName();
0710: } catch (Throwable e) {
0711: Log.warn(e);
0712: return null;
0713: }
0714: }
0715:
0716: /** Returns whether the given component is a lightweight popup, that is, a
0717: container for a JPopupMenu that is implemented with a lightweight
0718: component (usually JPanel).
0719: */
0720: public static boolean isLightweightPopup(Component c) {
0721: if (c instanceof JPanel) {
0722: Window w = SwingUtilities.getWindowAncestor(c);
0723: if (w != null && isHeavyweightPopup(w))
0724: return false;
0725: JPanel panel = (JPanel) c;
0726: Container parent = panel.getParent();
0727: if (parent != null) {
0728: if (parent instanceof JLayeredPane) {
0729: int layer = JLayeredPane.POPUP_LAYER.intValue();
0730: if (JLayeredPane.getLayer(panel) == layer)
0731: return true;
0732: }
0733: }
0734: return panel.getComponentCount() == 1
0735: && panel.getComponents()[0] instanceof JPopupMenu;
0736: }
0737: return false;
0738: }
0739:
0740: /** Returns whether the given Component is the content pane for a
0741: {@link RootPaneContainer}.
0742: @see javax.swing.RootPaneContainer#getContentPane
0743: */
0744: public static boolean isContentPane(Component c) {
0745: if (c.getParent() instanceof JLayeredPane) {
0746: JLayeredPane p = (JLayeredPane) c.getParent();
0747: if (p.getParent() instanceof JRootPane) {
0748: return ((JRootPane) p.getParent()).getContentPane() == c;
0749: }
0750: int layer = JLayeredPane.FRAME_CONTENT_LAYER.intValue();
0751: return p.getLayer(c) == layer && !(c instanceof JMenuBar);
0752: }
0753: return false;
0754: }
0755:
0756: /** Returns whether the given Component is the Glass Pane for a
0757: {@link JRootPane}.
0758: @see javax.swing.JRootPane#getGlassPane
0759: */
0760: public static boolean isGlassPane(Component c) {
0761: if (c.getParent() instanceof JRootPane) {
0762: JRootPane p = (JRootPane) c.getParent();
0763: return p.getGlassPane() == c;
0764: }
0765: return false;
0766: }
0767:
0768: /** Return whether the given component is part of the transient wrapper
0769: * around a popup.
0770: */
0771: public static boolean isTransientPopup(Component c) {
0772: return isLightweightPopup(c) || isHeavyweightPopup(c);
0773: }
0774:
0775: private static boolean containsToolTip(Component c) {
0776: if (c instanceof JToolTip)
0777: return true;
0778: if (c instanceof Container) {
0779: Component[] kids = ((Container) c).getComponents();
0780: for (int i = 0; i < kids.length; i++) {
0781: if (containsToolTip(kids[i]))
0782: return true;
0783: }
0784: }
0785: return false;
0786: }
0787:
0788: /** Return whether the given component is part of the transient wrapper
0789: around a tooltip.
0790: */
0791: public static boolean isToolTip(Component c) {
0792: return isTransientPopup(c) && containsToolTip(c);
0793: }
0794:
0795: /** Return whether the given component is part of an internal frame's LAF
0796: decoration.
0797: */
0798: public static boolean isInternalFrameDecoration(Component c) {
0799: Component parent = c.getParent();
0800: return (parent instanceof JInternalFrame && !(c instanceof JRootPane))
0801: || (parent != null
0802: && (parent.getParent() instanceof JInternalFrame) && (!(parent instanceof JRootPane)));
0803: }
0804:
0805: // Macintosh *used* to map button2 to the popup trigger (circa 1.3)
0806: // Not clear when this changed
0807: private static final boolean POPUP_ON_BUTTON2 = false;
0808:
0809: /** Returns the InputEvent mask for the popup trigger button. */
0810: public static int getPopupMask() {
0811: return POPUP_ON_BUTTON2 ? InputEvent.BUTTON2_MASK
0812: : InputEvent.BUTTON3_MASK;
0813: }
0814:
0815: /** Returns the InputEvent mask for the tertiary button. */
0816: public static int getTertiaryMask() {
0817: return POPUP_ON_BUTTON2 ? InputEvent.BUTTON3_MASK
0818: : InputEvent.BUTTON2_MASK;
0819: }
0820:
0821: /** Returns whether the platform registers a popup on mouse press. */
0822: public static boolean getPopupOnPress() {
0823: // Only w32 is popup on release
0824: return !Platform.isWindows();
0825: }
0826:
0827: private static final PopupMenu[] NO_POPUPS = new PopupMenu[0];
0828:
0829: /** Return all AWT popup menus associated with the given component. */
0830: public static PopupMenu[] getPopupMenus(Component c) {
0831: // Here's a nice little hack to get access to the popup list on the
0832: // given invoker...
0833: try {
0834: Field field = Component.class.getDeclaredField("popups");
0835: boolean accessible = field.isAccessible();
0836: field.setAccessible(true);
0837: Vector popups = (Vector) field.get(c);
0838: field.setAccessible(accessible);
0839: if (popups != null)
0840: return (PopupMenu[]) popups
0841: .toArray(new PopupMenu[popups.size()]);
0842: return NO_POPUPS;
0843: } catch (NoSuchFieldException e) {
0844: // not gonna happen
0845: throw new Error(
0846: "No field named 'popups' in class Component");
0847: } catch (IllegalAccessException e) {
0848: // neither should this
0849: throw new Error("Can't access popup for component " + c);
0850: }
0851: }
0852:
0853: /** Returns all MenuItems matching the given label or path which are on
0854: PopupMenus on the given Component. */
0855: public static MenuItem[] findAWTPopupMenuItems(Component parent,
0856: String path) {
0857: PopupMenu[] popups = getPopupMenus(parent);
0858: ArrayList list = new ArrayList();
0859: for (int i = 0; i < popups.length; i++) {
0860: list.addAll(findMenuItems(popups[i], path, true));
0861: }
0862: return (MenuItem[]) list.toArray(new MenuItem[list.size()]);
0863: }
0864:
0865: /** Returns all MenuItems matching the given label or path which are found
0866: in the given Frame's MenuBar. */
0867: public static MenuItem[] findAWTMenuItems(Frame frame, String path) {
0868: MenuBar mb = frame.getMenuBar();
0869: if (mb != null) {
0870: Collection items = findMenuItems(mb, path, true);
0871: return (MenuItem[]) items
0872: .toArray(new MenuItem[items.size()]);
0873: }
0874: return new MenuItem[0];
0875: }
0876:
0877: /** Returns a unique path to the given MenuItem. */
0878: public static String getPath(MenuItem item) {
0879: String path = getPath(item, false);
0880: if (isOnPopup(item)
0881: && findAWTPopupMenuItems(getInvoker(item), path).length > 1) {
0882: path = getPath(item, true);
0883: }
0884: return path;
0885: }
0886:
0887: /** Returns a unique path to the given MenuItem. If on a PopupMenu,
0888: optionally include the PopupMenu name. */
0889: private static String getPath(MenuItem item,
0890: boolean includePopupName) {
0891: MenuContainer invoker = getInvoker(item);
0892: MenuContainer top;
0893: if (invoker == null) {
0894: // Find the top-most Menu above this MenuItem
0895: top = item.getParent();
0896: while (top instanceof Menu
0897: && !(((Menu) top).getParent() instanceof MenuBar)) {
0898: top = ((Menu) top).getParent();
0899: }
0900: if (top == null)
0901: throw new RuntimeException(
0902: "MenuItem is not attached to the hierarchy");
0903: } else {
0904: // Find the containing PopupMenu
0905: top = item.getParent();
0906: while (top instanceof Menu
0907: && !(((Menu) top).getParent() instanceof Component)) {
0908: top = ((Menu) top).getParent();
0909: }
0910: }
0911:
0912: // Return a path to the item, starting at the first top level Menu
0913: String path = item.getLabel();
0914: MenuItem mi = item;
0915: while (mi.getParent() != top) {
0916: mi = (MenuItem) mi.getParent();
0917: path = mi.getLabel() + "|" + path;
0918: }
0919: if (top instanceof PopupMenu) {
0920: if (includePopupName) {
0921: // If the popup has the default name, use its index
0922: // on the invoker instead.
0923: String name = ((PopupMenu) top).getName();
0924: if (Regexp.stringMatch("popup[0-9]+", name)) {
0925: PopupMenu[] all = getPopupMenus((Component) invoker);
0926: for (int i = 0; i < all.length; i++) {
0927: if (all[i] == top) {
0928: // Make it different from the default name
0929: name = "popup#" + i;
0930: break;
0931: }
0932: }
0933: }
0934: path = name + "|" + path;
0935: }
0936: } else {
0937: path = ((Menu) top).getLabel() + "|" + path;
0938: }
0939: Log.debug("Path for " + item + " is " + path);
0940: return path;
0941: }
0942:
0943: /** Returns all AWT menu items found with the given label; if matchPath is
0944: set then the MenuItem path is examined as well as the label.
0945: */
0946: private static Collection findMenuItems(MenuContainer mc,
0947: String path, boolean matchPath) {
0948: if (matchPath)
0949: Log.debug("Searching for '" + path + "' on '" + mc);
0950: ArrayList list = new ArrayList();
0951: if (mc instanceof MenuBar) {
0952: for (int i = 0; i < ((MenuBar) mc).getMenuCount(); i++) {
0953: Menu menu = ((MenuBar) mc).getMenu(i);
0954: Log.debug("Scanning '" + menu + "'");
0955: list.addAll(findMenuItems(menu, path, matchPath));
0956: }
0957: } else if (mc instanceof Menu) {
0958: for (int i = 0; i < ((Menu) mc).getItemCount(); i++) {
0959: MenuItem mi = ((Menu) mc).getItem(i);
0960: if (mi instanceof MenuContainer) {
0961: Log.debug("Scanning '" + mi + "'");
0962: list.addAll(findMenuItems((MenuContainer) mi, path,
0963: matchPath));
0964: } else if (path.equals(mi.getLabel())) {
0965: Log.debug("Found '" + mi + "'");
0966: list.add(mi);
0967: } else if (matchPath) {
0968: if (ExtendedComparator.stringsMatch(path, getPath(
0969: mi, false))
0970: || ExtendedComparator.stringsMatch(path,
0971: getPath(mi, true))) {
0972: Log.debug("Found (path) '" + mi + "'");
0973: list.add(mi);
0974: }
0975: // TODO: fuzzy matching on the unique id (i.e. drop off or
0976: // add the popup menu name.
0977: }
0978: }
0979: }
0980: return list;
0981: }
0982:
0983: /** Return the focus owner under the given Window.
0984: As of 1.4.x, components will report that they do not have focus
0985: if asked from a different AppContext than their own. Account
0986: for that here.
0987: */
0988: public static Component getFocusOwner() {
0989: try {
0990: Class cls = Class.forName("java.awt.KeyboardFocusManager");
0991: Field field = cls.getDeclaredField("focusOwner");
0992: boolean accessible = field.isAccessible();
0993: field.setAccessible(true);
0994: Component c = (Component) field.get(null);
0995: field.setAccessible(accessible);
0996: return c;
0997: } catch (Exception e) {
0998: if (!(e instanceof ClassNotFoundException))
0999: Log.log(e);
1000: // FIXME this lookup doesn't seem to work on 1.3!
1001: Iterator iter = new AWTHierarchy().getRoots().iterator();
1002: Component focus = null;
1003: while (iter.hasNext()) {
1004: Window w = (Window) iter.next();
1005: if (w.isShowing() && (focus = getFocusOwner(w)) != null)
1006: break;
1007: }
1008: return focus;
1009: }
1010: }
1011:
1012: private static Component getFocusOwner(Window w) {
1013: Component focus = w.getFocusOwner();
1014: if (focus == null) {
1015: Window[] owned = w.getOwnedWindows();
1016: for (int i = 0; i < owned.length; i++) {
1017: if ((focus = owned[i].getFocusOwner()) != null)
1018: return focus;
1019: }
1020: }
1021: return focus;
1022: }
1023:
1024: /** For debugging purposes only. */
1025: public static AppContext getAppContext(Component c) {
1026: try {
1027: Field field = Component.class
1028: .getDeclaredField("appContext");
1029: boolean accessible = field.isAccessible();
1030: field.setAccessible(true);
1031: AppContext appContext = (AppContext) field.get(c);
1032: field.setAccessible(accessible);
1033: return appContext;
1034: } catch (Exception e) {
1035: Log.warn(e);
1036: return null;
1037: }
1038: }
1039:
1040: /** WARNING: This uses 1.3/1.4 implementation details. */
1041: public static boolean eventTypeEnabled(Component c, int id) {
1042: // certain AWT components should have events enabled, even if they
1043: // claim not to.
1044: // NOTE: Checkbox could be included here, obviating the need for
1045: // CheckboxTester's AWT-mode function.
1046: if (c instanceof Choice)
1047: return true;
1048: try {
1049: AWTEvent ev = new AWTEvent(c, id) {
1050: };
1051: Method m = Component.class.getDeclaredMethod(
1052: "eventEnabled", new Class[] { AWTEvent.class });
1053: m.setAccessible(true);
1054: Boolean b = (Boolean) m.invoke(c, new Object[] { ev });
1055: return b.booleanValue();
1056: } catch (Exception e) {
1057: Log.warn(e);
1058: return true;
1059: }
1060: }
1061:
1062: // Don't use the full classname, since anonymous inner classnames
1063: // are dependent on order of appearance in the source
1064: static final String ROOT_FRAME_CLASSNAME = SwingUtilities.class
1065: .getName()
1066: + "$";
1067:
1068: /** Is the given component the default Swing hidden frame? */
1069: public static boolean isSharedInvisibleFrame(Component c) {
1070: // Must perform an additional check, since applets may
1071: // have their own version in their AppContext
1072: return c instanceof Frame
1073: && (c == JOptionPane.getRootFrame() || c.getClass()
1074: .getName().startsWith(ROOT_FRAME_CLASSNAME));
1075: }
1076:
1077: public static boolean isAppletViewerFrame(Component c) {
1078: return c.getClass().getName().equals("sun.applet.AppletViewer");
1079: }
1080:
1081: private static final Matcher POPUP_MATCHER = new ClassMatcher(
1082: JPopupMenu.class, true);
1083:
1084: /** Returns the currently active popup menu, if any. If no popup is
1085: currently showing, returns null.
1086: */
1087: public static JPopupMenu getActivePopupMenu() {
1088: try {
1089: return (JPopupMenu) BasicFinder.getDefault().find(
1090: POPUP_MATCHER);
1091: } catch (ComponentSearchException e) {
1092: return null;
1093: }
1094: }
1095:
1096: /** Find the currently active Swing popup menu, if any, waiting up to
1097: POPUP_TIMEOUT ms. Returns null if no popup found.
1098: */
1099: public static JPopupMenu findActivePopupMenu() {
1100: JPopupMenu popup = getActivePopupMenu();
1101: if (popup == null && !SwingUtilities.isEventDispatchThread()) {
1102: long now = System.currentTimeMillis();
1103: while ((popup = getActivePopupMenu()) == null) {
1104: if (System.currentTimeMillis() - now > POPUP_TIMEOUT) {
1105: break;
1106: }
1107: try {
1108: Thread.sleep(100);
1109: } catch (Exception e) {
1110: }
1111: }
1112: }
1113: return popup;
1114: }
1115:
1116: /** Safe version of {@link Component#getLocationOnScreen}, which
1117: * avoids lockup if an AWT popup menu is showing. The AWT popup
1118: * holds the AWT tree lock when showing, which lock is required by
1119: * {@link Component#getLocationOnScreen}.
1120: */
1121: public static Point getLocationOnScreen(Component c) {
1122: if (isAWTTreeLockHeld()) {
1123: if (!c.isShowing())
1124: throw new IllegalComponentStateException(
1125: "component must be showing on the screen to determine its location");
1126: Point loc = new Point(c.getLocation());
1127: if (!(c instanceof Window)) {
1128: Container parent = c.getParent();
1129: if (parent == null)
1130: throw new IllegalComponentStateException(
1131: "component must be showing on the screen to determine its location");
1132: Point ploc = getLocationOnScreen(parent);
1133: loc.translate(ploc.x, ploc.y);
1134: }
1135: return loc;
1136: }
1137: return new Point(c.getLocationOnScreen());
1138: }
1139:
1140: /** Return whether the given component is part of a transient dialog.
1141: * This includes dialogs generated by JFileChooser, JOptionPane,
1142: * JColorChooser, and ProgressMonitor.<p>
1143: * Note that it is possible to use JOptionPane.createDialog to create a
1144: * reusable dialog, so just because it's transient doesn't mean it will be
1145: * disposed of when it is hidden.<p>
1146: * Note that this won't detect transient Dialogs after their components
1147: * have been reassigned to a new transient Dialog.
1148: */
1149: public static boolean isTransientDialog(Component c) {
1150: if (c instanceof Window) {
1151: if (c instanceof JDialog) {
1152: Container contentPane = ((JDialog) c).getContentPane();
1153: Component[] kids = contentPane.getComponents();
1154: if (kids.length == 1) {
1155: return kids[0] instanceof JOptionPane
1156: || kids[0] instanceof JFileChooser
1157: || kids[0] instanceof JColorChooser;
1158: }
1159: }
1160: } else if (!(c instanceof JOptionPane // also covers ProgressMonitor
1161: || c instanceof JFileChooser || c instanceof JColorChooser)) {
1162: Container parent = c.getParent();
1163: return parent != null && isTransientDialog(parent);
1164: }
1165: return false;
1166: }
1167:
1168: /** Returns the Applet descendent of the given Container, if any. */
1169: public static Applet findAppletDescendent(Container c) {
1170: try {
1171: return (Applet) BasicFinder.getDefault().find(c,
1172: new ClassMatcher(Applet.class));
1173: } catch (ComponentSearchException e) {
1174: return null;
1175: }
1176: }
1177:
1178: /** Return whether this is the tertiary button, considering primary to be
1179: * button1 and secondary to be the popup trigger button.
1180: */
1181: public static boolean isTertiaryButton(int mods) {
1182: return ((mods & AWTConstants.BUTTON_MASK) != InputEvent.BUTTON1_MASK)
1183: && ((mods & AWTConstants.POPUP_MASK) == 0);
1184: }
1185:
1186: /** Convert the string representation into the actual modifier mask. */
1187: public static int getModifiers(String mods) {
1188: int value = 0;
1189: if (mods != null && !mods.equals("")) {
1190: StringTokenizer st = new StringTokenizer(mods, "| ");
1191: while (st.hasMoreTokens()) {
1192: String flag = st.nextToken();
1193: // Allow short-form modifiers
1194: if (!flag.endsWith("_MASK"))
1195: flag = flag + "_MASK";
1196: if (AWTConstants.POPUP_MODIFIER.equals(flag))
1197: value |= AWTConstants.POPUP_MASK;
1198: else if (AWTConstants.TERTIARY_MODIFIER.equals(flag))
1199: value |= AWTConstants.TERTIARY_MASK;
1200: else if (!flag.equals("0"))
1201: value |= Reflector.getFieldValue(InputEvent.class,
1202: flag);
1203: }
1204: }
1205: return value;
1206: }
1207:
1208: private static String getModifiers(int flags, boolean isMouse) {
1209: // Historical note:
1210: // On a mac, ALT+BUTTON1 means BUTTON2; META+BUTTON1 means BUTTON3
1211: int macModifiers = InputEvent.CTRL_MASK | InputEvent.ALT_MASK
1212: | InputEvent.META_MASK;
1213: boolean isMacButton = isMouse && Platform.isMacintosh()
1214: && (flags & macModifiers) != 0;
1215: String mods = "";
1216: String or = "";
1217: if ((flags & InputEvent.ALT_GRAPH_MASK) != 0) {
1218: mods += or + "ALT_GRAPH_MASK";
1219: or = "|";
1220: flags &= ~InputEvent.ALT_GRAPH_MASK;
1221: }
1222: if ((flags & InputEvent.BUTTON1_MASK) != 0 && !isMacButton) {
1223: mods += or + "BUTTON1_MASK";
1224: or = "|";
1225: flags &= ~InputEvent.BUTTON1_MASK;
1226: }
1227: // Mask for ALT is the same as MB2
1228: if ((flags & InputEvent.ALT_MASK) != 0 && !isMacButton
1229: && !isMouse) {
1230: mods += or + "ALT_MASK";
1231: or = "|";
1232: flags &= ~InputEvent.ALT_MASK;
1233: }
1234: // Mac uses ctrl modifier to get MB2
1235: if ((flags & InputEvent.CTRL_MASK) != 0 && !isMacButton) {
1236: mods += or + "CTRL_MASK";
1237: or = "|";
1238: flags &= ~InputEvent.CTRL_MASK;
1239: }
1240: // Mask for META is the same as MB3
1241: if ((flags & InputEvent.META_MASK) != 0 && !isMacButton
1242: && !isMouse) {
1243: mods += or + "META_MASK";
1244: or = "|";
1245: flags &= ~InputEvent.META_MASK;
1246: }
1247: if ((flags & AWTConstants.POPUP_MASK) != 0) {
1248: mods += or + "POPUP_MASK";
1249: or = "|";
1250: flags &= ~AWTConstants.POPUP_MASK;
1251: }
1252: if ((flags & AWTConstants.TERTIARY_MASK) != 0) {
1253: mods += or + "TERTIARY_MASK";
1254: or = "|";
1255: flags &= ~AWTConstants.TERTIARY_MASK;
1256: }
1257: if ((flags & InputEvent.SHIFT_MASK) != 0) {
1258: mods += or + "SHIFT_MASK";
1259: or = "|";
1260: flags &= ~InputEvent.SHIFT_MASK;
1261: }
1262: // Empty strings are confusing and invisible; make it explicit
1263: if ("".equals(mods))
1264: mods = "0";
1265: return mods;
1266: }
1267:
1268: public static String getKeyModifiers(int flags) {
1269: return getModifiers(flags, false);
1270: }
1271:
1272: public static String getMouseModifiers(int flags) {
1273: return getModifiers(flags, true);
1274: }
1275:
1276: /** Convert the integer modifier flags into a string representation. */
1277: public static String getModifiers(InputEvent event) {
1278: return getModifiers(event.getModifiers(),
1279: event instanceof MouseEvent);
1280: }
1281:
1282: public static String getKeyCode(int keycode) {
1283: return Reflector.getFieldName(KeyEvent.class, keycode, "VK_");
1284: }
1285:
1286: public static int getKeyCode(String code) {
1287: return Reflector.getFieldValue(KeyEvent.class, code);
1288: }
1289:
1290: public static boolean isModifier(int keycode) {
1291: switch (keycode) {
1292: case KeyEvent.VK_META:
1293: case KeyEvent.VK_ALT:
1294: case KeyEvent.VK_ALT_GRAPH:
1295: case KeyEvent.VK_CONTROL:
1296: case KeyEvent.VK_SHIFT:
1297: return true;
1298: default:
1299: return false;
1300: }
1301: }
1302:
1303: public static int keyCodeToMask(int code) {
1304: switch (code) {
1305: case KeyEvent.VK_META:
1306: return InputEvent.META_MASK;
1307: case KeyEvent.VK_ALT:
1308: return InputEvent.ALT_MASK;
1309: case KeyEvent.VK_ALT_GRAPH:
1310: return InputEvent.ALT_GRAPH_MASK;
1311: case KeyEvent.VK_CONTROL:
1312: return InputEvent.CTRL_MASK;
1313: case KeyEvent.VK_SHIFT:
1314: return InputEvent.SHIFT_MASK;
1315: default:
1316: throw new IllegalArgumentException(
1317: "Keycode is not a modifier: " + code);
1318: }
1319: }
1320:
1321: /** Convert the given modifier event mask to the equivalent key code. */
1322: public static int maskToKeyCode(int mask) {
1323: switch (mask) {
1324: case InputEvent.META_MASK:
1325: return KeyEvent.VK_META;
1326: case InputEvent.ALT_MASK:
1327: return KeyEvent.VK_ALT;
1328: case InputEvent.ALT_GRAPH_MASK:
1329: return KeyEvent.VK_ALT_GRAPH;
1330: case InputEvent.CTRL_MASK:
1331: return KeyEvent.VK_CONTROL;
1332: case InputEvent.SHIFT_MASK:
1333: return KeyEvent.VK_SHIFT;
1334: default:
1335: throw new IllegalArgumentException("Unrecognized mask '"
1336: + mask + "'");
1337: }
1338: }
1339:
1340: /** If a component does not have mouse events enabled, use the
1341: first ancestor which does.
1342: */
1343: public static Component retargetMouseEvent(Component comp, int id,
1344: Point pt) {
1345: Point where = pt;
1346: while (!(comp instanceof Window) && !eventTypeEnabled(comp, id)) {
1347: Log.debug("Retargeting event, " + Robot.toString(comp)
1348: + " not interested");
1349: where = SwingUtilities.convertPoint(comp, where.x, where.y,
1350: comp.getParent());
1351: comp = comp.getParent();
1352: }
1353: pt.setLocation(where);
1354: return comp;
1355: }
1356:
1357: public static Insets getInsets(Container c) {
1358: try {
1359: Insets insets = c.getInsets();
1360: if (insets != null)
1361: return insets;
1362: } catch (NullPointerException e) {
1363: // FileDialog.getInsets() throws (1.4.2_07)
1364: }
1365: return new Insets(0, 0, 0, 0);
1366: }
1367:
1368: // Try to lock the AWT tree lock; returns immediately if it can
1369: private static class ThreadStateChecker extends Thread {
1370: public boolean started;
1371: private Object lock;
1372:
1373: public ThreadStateChecker(Object lock) {
1374: super ("thread state checker");
1375: setDaemon(true);
1376: this .lock = lock;
1377: }
1378:
1379: public synchronized void start() {
1380: super .start();
1381: try {
1382: wait(30000);
1383: } catch (InterruptedException e) {
1384: }
1385: }
1386:
1387: public void run() {
1388: synchronized (this ) {
1389: started = true;
1390: notifyAll();
1391: }
1392: synchronized (lock) {
1393: // dummy operation
1394: setName(super.getName());
1395: }
1396: }
1397: }
1398: }
|