Source Code Cross Referenced for Robot.java in  » Testing » abbot-1.0.1 » abbot » tester » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » abbot 1.0.1 » abbot.tester 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package abbot.tester;
0002:
0003:        import java.awt.AWTEvent;
0004:        import java.awt.AWTException;
0005:        import java.awt.Button;
0006:        import java.awt.Checkbox;
0007:        import java.awt.Color;
0008:        import java.awt.Component;
0009:        import java.awt.Container;
0010:        import java.awt.Dialog;
0011:        import java.awt.Dimension;
0012:        import java.awt.EventQueue;
0013:        import java.awt.Frame;
0014:        import java.awt.Insets;
0015:        import java.awt.Label;
0016:        import java.awt.MenuBar;
0017:        import java.awt.MenuComponent;
0018:        import java.awt.MenuItem;
0019:        import java.awt.Point;
0020:        import java.awt.PopupMenu;
0021:        import java.awt.Rectangle;
0022:        import java.awt.Toolkit;
0023:        import java.awt.Window;
0024:        import java.awt.event.ActionEvent;
0025:        import java.awt.event.ComponentEvent;
0026:        import java.awt.event.FocusAdapter;
0027:        import java.awt.event.FocusEvent;
0028:        import java.awt.event.HierarchyEvent;
0029:        import java.awt.event.InputEvent;
0030:        import java.awt.event.InputMethodEvent;
0031:        import java.awt.event.InvocationEvent;
0032:        import java.awt.event.KeyEvent;
0033:        import java.awt.event.MouseEvent;
0034:        import java.awt.event.PaintEvent;
0035:        import java.awt.event.WindowEvent;
0036:        import java.awt.image.BufferedImage;
0037:        import java.util.Collection;
0038:        import java.util.Iterator;
0039:
0040:        import javax.accessibility.AccessibleAction;
0041:        import javax.accessibility.AccessibleContext;
0042:        import javax.accessibility.AccessibleIcon;
0043:        import javax.swing.AbstractButton;
0044:        import javax.swing.JComponent;
0045:        import javax.swing.JInternalFrame;
0046:        import javax.swing.JLabel;
0047:        import javax.swing.JLayeredPane;
0048:        import javax.swing.JMenu;
0049:        import javax.swing.JPanel;
0050:        import javax.swing.JPopupMenu;
0051:        import javax.swing.JRootPane;
0052:        import javax.swing.KeyStroke;
0053:        import javax.swing.SwingUtilities;
0054:        import javax.swing.border.Border;
0055:        import javax.swing.border.CompoundBorder;
0056:        import javax.swing.border.TitledBorder;
0057:
0058:        import abbot.Log;
0059:        import abbot.Platform;
0060:        import abbot.WaitTimedOutError;
0061:        import abbot.finder.BasicFinder;
0062:        import abbot.finder.ComponentNotFoundException;
0063:        import abbot.finder.Matcher;
0064:        import abbot.finder.MultipleComponentsFoundException;
0065:        import abbot.finder.matchers.JMenuItemMatcher;
0066:        import abbot.finder.matchers.JMenuMatcher;
0067:        import abbot.i18n.Strings;
0068:        import abbot.util.AWT;
0069:        import abbot.util.Bugs;
0070:        import abbot.util.Condition;
0071:        import abbot.util.Properties;
0072:        import abbot.util.Reflector;
0073:
0074:        /** Provide a higher level of abstraction for user input (A Better Robot).
0075:         The Robot's operation may be affected by the following properties:<br>
0076:         <pre><code>abbot.robot.auto_delay</code></pre><br>
0077:         Set this to a value representing the millisecond count in between
0078:         generated events.  Usually just set to 100-200 if you want to slow down
0079:         the playback to simulate actual user input.  The default is zero delay.<br>
0080:         <pre><code>abbot.robot.mode</code></pre><br>
0081:         Set this to either "robot" or "awt" to designate the desired mode of event
0082:         generation.  "robot" uses java.awt.Robot to generate events, while "awt"
0083:         stuffs events directly into the AWT event queue.<br>
0084:         <pre><code>abbot.robot.event_post_delay</code></pre><br>
0085:         This is the maximum number of ms it takes the system to post an AWT event
0086:         in response to a Robot-generated event.
0087:         <pre><code>abbot.robot.default_delay</code></pre><br>
0088:         Base delay setting, acts as default value for the next two.
0089:         <pre><code>abbot.robot.popup_delay</code></pre><br>
0090:         Set this to the maximum time to wait for a menu to appear or be generated.
0091:         <pre><code>abbot.robot.component_delay</code></pre><br>
0092:         Set this to the maximum time to wait for a Component to become available.
0093:         <p>
0094:         The Robot class provides a generic solution for dealing with asynchronous
0095:         updates to the UI with the {@link #wait(Condition,long, int)} method. 
0096:         This allows the testing thread to pause until a given component of data value
0097:         in a component is ready.
0098:         <p>
0099:         NOTE: Only use event queue synchronization (e.g.
0100:         {@link #invokeAndWait(Runnable)} or {@link #waitForIdle()} when a
0101:         subsequent robot-level action is being applied to the results of a prior
0102:         action (e.g. focus, deiconify, menu selection).  Otherwise, don't
0103:         introduce a mandatory delay (e.g. use {@link #invokeLater(Runnable)}).
0104:         <p>
0105:         NOTE: If a robot action isn't reproduced properly, you may need to
0106:         introduce either additional events or extra delay.  Adding enforced delay
0107:         for a given platform is usually preferable to generating additional events,
0108:         so always try that first, but be sure to restrict it to the platform in
0109:         question.
0110:         <p>
0111:         NOTE: Robot actions should <b>never</b> be invoked on the event dispatch
0112:         thread.
0113:         */
0114:
0115:        public class Robot implements  AWTConstants {
0116:            /** Use java.awt.Robot to generate events. */
0117:            public static int EM_ROBOT = 0;
0118:            /** Post events to the AWT event queue. */
0119:            public static int EM_AWT = 1;
0120:
0121:            private static final String LABELED_BY_PROPERTY = "labeledBy";
0122:            private static final Toolkit toolkit = Toolkit.getDefaultToolkit();
0123:            // Max robot delay, in ms
0124:            private static final int MAX_DELAY = 60000;
0125:            // TODO: verify this value for X11, etc.; ALT for w32, option for OSX
0126:            public static final int MOUSELESS_MODIFIER_MASK = InputEvent.ALT_MASK;
0127:            public static final String MOUSELESS_MODIFIER = AWT
0128:                    .getKeyModifiers(MOUSELESS_MODIFIER_MASK);
0129:
0130:            /** OS X using screenMenuBar actually uses an AWT menu as the live
0131:                component.  The JXXX components exist, but are not effectively
0132:                active. 
0133:             */
0134:            protected static final boolean useScreenMenuBar() {
0135:                // Ideally we'd install a menu and check where it ended up, since the
0136:                // property is read once at startup and ignored thereafter.
0137:                return Platform.isOSX()
0138:                        && (Boolean
0139:                                .getBoolean("com.apple.macos.useScreenMenuBar") || Boolean
0140:                                .getBoolean("apple.laf.useScreenMenuBar"));
0141:            }
0142:
0143:            /** Base delay setting. */
0144:            public static int defaultDelay = Properties.getProperty(
0145:                    "abbot.robot.default_delay", 30000, 0, 60000);
0146:
0147:            /** Delay before checking for idle.  This allows the system a little time
0148:                to put a native event onto the AWT event queue. */
0149:            private static int eventPostDelay = Properties.getProperty(
0150:                    "abbot.robot.event_post_delay", 100, 0, 1000);
0151:
0152:            protected static long IDLE_TIMEOUT = Integer.getInteger(
0153:                    "abbot.robot.idle_timeout", 10000).intValue();
0154:
0155:            /** Delay before failing to find a popup menu that should appear. */
0156:            protected static int popupDelay = Properties.getProperty(
0157:                    "abbot.robot.popup_delay", defaultDelay, 0, 60000);
0158:
0159:            /** Delay before failing to find a component that should be visible. */
0160:            public static int componentDelay = Properties.getProperty(
0161:                    "abbot.robot.component_delay", defaultDelay, 0, 60000);
0162:
0163:            /** With decreased robot auto delay, OSX popup menus don't activate
0164:             * properly.  Indicate the minimum delay for proper operation (determined
0165:             * experimentally). 
0166:             */
0167:            private static final int subMenuDelay = Platform.isOSX() ? 100 : 0;
0168:
0169:            /** How events are generated. */
0170:            private static int eventMode = EM_ROBOT;
0171:            private static boolean verified = false;
0172:            private static boolean serviceMode = false;
0173:
0174:            // FIXME add one per graphics device?
0175:            /** The robot used to generate events. */
0176:            private static java.awt.Robot robot;
0177:            private static WindowTracker tracker;
0178:            /** Current input state.  This will either be that of the AWT event queue
0179:             * or of the robot, depending on the dispatch mode. 
0180:             * Note that the robot state may be different from that seen by the AWT
0181:             * event queue, since robot events may be as yet unprocessed.
0182:             */
0183:            private static InputState state;
0184:
0185:            /** Suitable inter-event delay for most cases; tests have been run safely
0186:             * at this value.  Should definitely be less than the double-click
0187:             * threshold.<p>  
0188:             */
0189:            private static final int DEFAULT_DELAY = getPreferredRobotAutoDelay();
0190:            private static final int SLEEP_INTERVAL = 10;
0191:
0192:            private static int autoDelay = DEFAULT_DELAY;
0193:
0194:            public static int getAutoDelay() {
0195:                return autoDelay;
0196:            }
0197:
0198:            /** Returns a functioning instance of java.awt.Robot. If this method
0199:             * returns null, it should be assumed that java.awt.Robot is unavailable
0200:             * or non-functional on the current system.  
0201:             */
0202:            public static java.awt.Robot getRobot() {
0203:                initializeRobot();
0204:                return serviceMode ? null : robot;
0205:            }
0206:
0207:            /** Return a singleton InputState object. */
0208:            public static InputState getState() {
0209:                initializeRobot();
0210:                return state;
0211:            }
0212:
0213:            private static synchronized void initializeRobot() {
0214:                if (state == null) {
0215:                    robot = createRobot();
0216:                    tracker = WindowTracker.getTracker();
0217:                    state = new InputState();
0218:                }
0219:            }
0220:
0221:            private static java.awt.Robot createRobot() {
0222:                java.awt.Robot robot = null;
0223:                String mode = System.getProperty("abbot.robot.mode", "robot");
0224:                autoDelay = Properties.getProperty("abbot.robot.auto_delay",
0225:                        autoDelay, -1, 60000);
0226:                try {
0227:                    // Even if the robot doesn't work, we can still use it for some
0228:                    // things. 
0229:                    robot = new java.awt.Robot();
0230:                    if (autoDelay != -1) {
0231:                        robot.setAutoDelay(autoDelay);
0232:                    } else {
0233:                        autoDelay = robot.getAutoDelay();
0234:                    }
0235:                    if (!verified) {
0236:                        verified = true;
0237:                        boolean skip = !"false".equals(System
0238:                                .getProperty("abbot.robot.verify"));
0239:                        if (!skip && !RobotVerifier.verify(robot)) {
0240:                            // robot doesn't work (w32 service mode)
0241:                            serviceMode = true;
0242:                            System.err.println("Robot non-functional, "
0243:                                    + "falling back to AWT mode");
0244:                            mode = "awt";
0245:                        }
0246:                    }
0247:                } catch (AWTException e) {
0248:                    // no robot available, send AWT events
0249:                    System.err.println("Falling back to AWT mode: "
0250:                            + e.getMessage());
0251:                    mode = "awt";
0252:                }
0253:                if (mode.equals("awt")) {
0254:                    eventMode = EM_AWT;
0255:                }
0256:                return robot;
0257:            }
0258:
0259:            /** Returns the current event-generation mode. */
0260:            public static int getEventMode() {
0261:                initializeRobot();
0262:                return eventMode;
0263:            }
0264:
0265:            public static String getEventModeDescription() {
0266:                initializeRobot();
0267:                String desc = eventMode == EM_ROBOT ? "robot" : "awt";
0268:                if (serviceMode)
0269:                    desc += " (service)";
0270:                return desc;
0271:            }
0272:
0273:            /** Set the event-generation mode.
0274:                @throws IllegalStateException if the requested mode is EM_ROBOT and
0275:                java.awt.Robot is unavailable in the current environment.
0276:             */
0277:            public static void setEventMode(int mode) {
0278:                initializeRobot();
0279:                if (eventMode != mode) {
0280:                    if (mode == EM_ROBOT && (serviceMode || robot == null)) {
0281:                        String msg = Strings.get("tester.Robot.no_robot_mode");
0282:                        throw new IllegalStateException(msg);
0283:                    }
0284:                    eventMode = mode;
0285:                }
0286:            }
0287:
0288:            public static int getEventPostDelay() {
0289:                return eventPostDelay;
0290:            }
0291:
0292:            public static void setEventPostDelay(int delay) {
0293:                eventPostDelay = Math.min(1000, Math.max(0, delay));
0294:            }
0295:
0296:            /** Allow this to be adjusted, mostly for testing. */
0297:            public static void setAutoDelay(int ms) {
0298:                initializeRobot();
0299:                ms = Math.min(60000, Math.max(0, ms));
0300:                if (eventMode == EM_ROBOT)
0301:                    robot.setAutoDelay(ms);
0302:                autoDelay = ms;
0303:                Log.debug("Auto delay set to " + ms);
0304:            }
0305:
0306:            /** Default constructor. */
0307:            public Robot() {
0308:                initializeRobot();
0309:            }
0310:
0311:            /** 
0312:             * Move the mouse to the given location, in screen coordinates.  
0313:             * NOTE: in robot mode, you may need to invoke this with a little jitter.
0314:             * There are some conditions where a single mouse move will not
0315:             * generate the necessary enter event on a component (typically a
0316:             * dialog with an OK button) before a mousePress.  See also click().
0317:             * NOTE: does 1.4+ need jitter?
0318:             */
0319:            private void mouseMove(int x, int y) {
0320:                if (eventMode == EM_ROBOT) {
0321:                    Log.debug("ROBOT: Mouse move: (" + x + "," + y + ")");
0322:                    robot.mouseMove(x, y);
0323:                } else {
0324:                    // Can't stuff an AWT event for an arbitrary location
0325:                }
0326:            }
0327:
0328:            /** Send a button press event. */
0329:            public void mousePress(int buttons) {
0330:                if (eventMode == EM_ROBOT) {
0331:                    Log.debug("ROBOT: Mouse press: "
0332:                            + AWT.getMouseModifiers(buttons));
0333:                    // OSX 1.4.1 accidentally swaps mb2 and mb3; fix it here
0334:                    robot.mousePress(buttons);
0335:                } else {
0336:                    Component c = state.getMouseComponent();
0337:                    if (c == null) {
0338:                        Log.warn("No current mouse component for button press",
0339:                                4);
0340:                        return;
0341:                    }
0342:                    Point where = state.getMouseLocation();
0343:                    postMousePress(c, where.x, where.y, buttons);
0344:                }
0345:            }
0346:
0347:            /** Send a button release event for button 1. */
0348:            public void mouseRelease() {
0349:                mouseRelease(MouseEvent.BUTTON1_MASK);
0350:            }
0351:
0352:            /** Send a button release event. */
0353:            public void mouseRelease(int buttons) {
0354:                if (eventMode == EM_ROBOT) {
0355:                    Log.debug("ROBOT: Mouse release: "
0356:                            + AWT.getMouseModifiers(buttons));
0357:                    robot.mouseRelease(buttons);
0358:                } else {
0359:                    Component source = state.isDragging() ? state
0360:                            .getDragSource()
0361:                            : (lastMousePress != null ? lastMousePress
0362:                                    .getComponent() : state.getMouseComponent());
0363:                    Point where = state.getMouseLocation();
0364:                    if (source == null) {
0365:                        Log.warn("Mouse release outside of available frames");
0366:                        return;
0367:                    } else if (where == null) {
0368:                        if (lastMousePress == null) {
0369:                            Log.warn("No record of most recent mouse press");
0370:                            return;
0371:                        }
0372:                        where = lastMousePress.getPoint();
0373:                    }
0374:                    postMouseRelease(source, where.x, where.y, buttons);
0375:                }
0376:            }
0377:
0378:            /** Move keyboard focus to the given component.  Note that the component
0379:                may not yet have focus when this method returns.
0380:             */
0381:            public void focus(Component comp) {
0382:                focus(comp, false);
0383:            }
0384:
0385:            /** Use an explicit listener, since hasFocus is not always reliable. */
0386:            private class FocusWatcher extends FocusAdapter {
0387:                public volatile boolean focused = false;
0388:
0389:                public FocusWatcher(Component c) {
0390:                    c.addFocusListener(this );
0391:                    focused = AWT.getFocusOwner() == c;
0392:                }
0393:
0394:                public void focusGained(FocusEvent f) {
0395:                    focused = true;
0396:                }
0397:
0398:                public void focusLost(FocusEvent f) {
0399:                    focused = false;
0400:                }
0401:            }
0402:
0403:            /** Move keyboard focus to the given component. */
0404:            public void focus(final Component comp, boolean wait) {
0405:                Component currentOwner = AWT.getFocusOwner();
0406:                if (currentOwner == comp) {
0407:                    return;
0408:                }
0409:                Log.debug("Focus change");
0410:                FocusWatcher fw = new FocusWatcher(comp);
0411:                // for pointer focus
0412:                mouseMove(comp, comp.getWidth() / 2, comp.getHeight() / 2);
0413:                waitForIdle();
0414:                // Make sure the correct window is in front
0415:                Window w1 = currentOwner != null ? AWT.getWindow(currentOwner)
0416:                        : null;
0417:                Window w2 = AWT.getWindow(comp);
0418:                if (w1 != w2) {
0419:                    activate(w2);
0420:                    waitForIdle();
0421:                }
0422:                // NOTE: while it would be nice to have a robot method instead of
0423:                // requesting focus, clicking to change focus may have 
0424:                // side effects 
0425:                invokeAndWait(comp, new Runnable() {
0426:                    public void run() {
0427:                        comp.requestFocus();
0428:                    }
0429:                });
0430:                try {
0431:                    if (wait) {
0432:                        long start = System.currentTimeMillis();
0433:                        while (!fw.focused) {
0434:                            if (System.currentTimeMillis() - start > componentDelay) {
0435:                                String msg = Strings.get(
0436:                                        "tester.Robot.focus_failed",
0437:                                        new Object[] { toString(comp) });
0438:                                throw new ActionFailedException(msg);
0439:                            }
0440:                            sleep();
0441:                        }
0442:                    }
0443:                } finally {
0444:                    comp.removeFocusListener(fw);
0445:                }
0446:            }
0447:
0448:            /** Usually only needed when dealing with Applets. */
0449:            protected EventQueue getEventQueue(Component c) {
0450:                return c != null ? tracker.getQueue(c) : toolkit
0451:                        .getSystemEventQueue();
0452:            }
0453:
0454:            /** Post a runnable on the given component's event queue.  Useful when
0455:                driving multiple Applets, but is also useful to ensure an operation
0456:                happens on the event dispatch thread.
0457:             */
0458:            public void invokeLater(Component context, Runnable action) {
0459:                EventQueue queue = getEventQueue(context);
0460:                queue.postEvent(new InvocationEvent(toolkit, action));
0461:            }
0462:
0463:            /** Post a runnable on the given component's event queue and wait for it
0464:                to finish.  */
0465:            public void invokeAndWait(Component c, Runnable action) {
0466:                invokeLater(c, action);
0467:                waitForIdle();
0468:            }
0469:
0470:            /** @deprecated Method renamed to {@link #invokeLater(Runnable)}
0471:             * @param action
0472:             */
0473:            public void invokeAction(Runnable action) {
0474:                invokeLater(action);
0475:            }
0476:
0477:            /** @deprecated Method renamed to {@link #invokeLater(Component, Runnable)}
0478:             * @param c
0479:             * @param action
0480:             */
0481:            public void invokeAction(Component c, Runnable action) {
0482:                invokeLater(c, action);
0483:            }
0484:
0485:            /** Run the given action on the event dispatch thread.  This should be
0486:             * used for any non-read-only methods invoked directly on a GUI
0487:             * component. 
0488:             * NOTE: if you want to use the results of the action, use invokeAndWait
0489:             * instead. 
0490:             */
0491:            public void invokeLater(Runnable action) {
0492:                invokeLater(null, action);
0493:            }
0494:
0495:            /** Run the given action on the event dispatch thread, but don't return
0496:                until it's been run.
0497:             */
0498:            public void invokeAndWait(Runnable action) {
0499:                invokeAndWait(null, action);
0500:            }
0501:
0502:            public void keyPress(int keycode) {
0503:                keyPress(keycode, KeyEvent.CHAR_UNDEFINED);
0504:            }
0505:
0506:            /** Send a key press event. */
0507:            private void keyPress(int keycode, char keyChar) {
0508:                if (eventMode == EM_ROBOT) {
0509:                    Log.debug("ROBOT: key press " + AWT.getKeyCode(keycode));
0510:                    try {
0511:                        robot.keyPress(keycode);
0512:                    } catch (IllegalArgumentException e) {
0513:                        throw new IllegalArgumentException("invalid key code "
0514:                                + keycode + " (char " + keyChar + ")");
0515:                    }
0516:                } else {
0517:                    int mods = state.getModifiers();
0518:                    if (AWT.isModifier(keycode))
0519:                        mods |= AWT.keyCodeToMask(keycode);
0520:                    postKeyEvent(KeyEvent.KEY_PRESSED, mods, keycode,
0521:                            KeyEvent.CHAR_UNDEFINED);
0522:                    // Auto-generate KEY_TYPED events, as best we can
0523:                    int mask = state.getModifiers();
0524:                    if (keyChar == KeyEvent.CHAR_UNDEFINED) {
0525:                        KeyStroke ks = KeyStroke.getKeyStroke(keycode, mask);
0526:                        keyChar = KeyStrokeMap.getChar(ks);
0527:                    }
0528:                    if (keyChar != KeyEvent.CHAR_UNDEFINED) {
0529:                        postKeyEvent(KeyEvent.KEY_TYPED, mask,
0530:                                KeyEvent.VK_UNDEFINED, keyChar);
0531:                    }
0532:                }
0533:            }
0534:
0535:            /** Send a key release event. */
0536:            public void keyRelease(int keycode) {
0537:                if (eventMode == EM_ROBOT) {
0538:                    Log.debug("ROBOT: key release " + AWT.getKeyCode(keycode));
0539:                    robot.keyRelease(keycode);
0540:                    if (Bugs.hasKeyInputDelay()) {
0541:                        // OSX, empirical
0542:                        int KEY_INPUT_DELAY = 200;
0543:                        if (KEY_INPUT_DELAY > autoDelay) {
0544:                            delay(KEY_INPUT_DELAY - autoDelay);
0545:                        }
0546:                    }
0547:                } else {
0548:                    int mods = state.getModifiers();
0549:                    if (AWT.isModifier(keycode))
0550:                        mods &= ~AWT.keyCodeToMask(keycode);
0551:                    postKeyEvent(KeyEvent.KEY_RELEASED, mods, keycode,
0552:                            KeyEvent.CHAR_UNDEFINED);
0553:                }
0554:            }
0555:
0556:            private void postKeyEvent(int id, int modifiers, int keycode,
0557:                    char ch) {
0558:                Component c = findFocusOwner();
0559:                if (c != null) {
0560:                    postEvent(c, new KeyEvent(c, id,
0561:                            System.currentTimeMillis(), modifiers, keycode, ch));
0562:                } else {
0563:                    Log.warn("No component has focus, key press discarded");
0564:                }
0565:            }
0566:
0567:            /** Sleep for a little bit, measured in UI time. */
0568:            public void sleep() {
0569:                delay(SLEEP_INTERVAL);
0570:            }
0571:
0572:            /** Sleep the given duration of ms. */
0573:            public void delay(int ms) {
0574:                if (eventMode == EM_ROBOT) {
0575:                    while (ms > MAX_DELAY) {
0576:                        robot.delay(MAX_DELAY);
0577:                        ms -= MAX_DELAY;
0578:                    }
0579:                    robot.delay(ms);
0580:                } else {
0581:                    try {
0582:                        Thread.sleep(ms);
0583:                    } catch (InterruptedException ie) {
0584:                    }
0585:                }
0586:            }
0587:
0588:            private static final Runnable EMPTY_RUNNABLE = new Runnable() {
0589:                public void run() {
0590:                }
0591:            };
0592:
0593:            /** Check for a blocked event queue (symptomatic of an active w32 AWT
0594:             * popup menu). 
0595:             * @return whether the event queue is blocked.  
0596:             */
0597:            protected boolean queueBlocked() {
0598:                return postInvocationEvent(toolkit.getSystemEventQueue(),
0599:                        toolkit, 200);
0600:            }
0601:
0602:            /** @return whether we timed out waiting for the invocation to run */
0603:            protected boolean postInvocationEvent(EventQueue eq,
0604:                    Toolkit toolkit, long timeout) {
0605:                class RobotIdleLock {
0606:                }
0607:                Object lock = new RobotIdleLock();
0608:                synchronized (lock) {
0609:                    eq.postEvent(new InvocationEvent(toolkit, EMPTY_RUNNABLE,
0610:                            lock, true));
0611:                    long start = System.currentTimeMillis();
0612:                    try {
0613:                        // NOTE: on fast linux systems when showing a dialog, if we
0614:                        // don't provide a timeout, we're never notified, and the
0615:                        // test will wait forever (up through 1.5.0_05).
0616:                        lock.wait(timeout);
0617:                        return (System.currentTimeMillis() - start) >= IDLE_TIMEOUT;
0618:                    } catch (InterruptedException e) {
0619:                        Log.warn("Invocation lock interrupted");
0620:                    }
0621:                }
0622:                return false;
0623:            }
0624:
0625:            private void waitForIdle(EventQueue eq) {
0626:                if (EventQueue.isDispatchThread())
0627:                    throw new IllegalThreadStateException(
0628:                            "Cannot call method from the event dispatcher thread");
0629:
0630:                // NOTE: as of Java 1.3.1, robot.waitForIdle only waits for the
0631:                // last event on the queue at the time of this invocation to be
0632:                // processed.  We need better than that.  Make sure the given event
0633:                // queue is empty when this method returns
0634:
0635:                // We always post at least one idle event to allow any current event
0636:                // dispatch processing to finish.
0637:                long start = System.currentTimeMillis();
0638:                int count = 0;
0639:                do {
0640:
0641:                    if (postInvocationEvent(eq, toolkit, IDLE_TIMEOUT)) {
0642:                        Log.warn("Timed out waiting for idle"
0643:                                + " (posted invocation event): " + IDLE_TIMEOUT
0644:                                + "ms (after " + count + " events)"
0645:                                + " posted to " + eq, Log.FULL_STACK);
0646:                        break;
0647:                    }
0648:                    if (System.currentTimeMillis() - start > IDLE_TIMEOUT) {
0649:                        Log
0650:                                .warn("Timed out waiting for idle event queue after "
0651:                                        + count + " events");
0652:                        break;
0653:                    }
0654:                    ++count;
0655:                    // Force a yield
0656:                    sleep();
0657:
0658:                    // NOTE: this does not detect invocation events (i.e. what
0659:                    // gets posted with EventQueue.invokeLater), so if someone
0660:                    // is repeatedly posting one, we might get stuck.  Not too
0661:                    // worried, since if a Runnable keeps calling invokeLater
0662:                    // on itself, *nothing* else gets much chance to run, so it
0663:                    // seems to be a bad programming practice.
0664:                } while (eq.peekEvent() != null);
0665:            }
0666:
0667:            /**
0668:             * Wait for an idle AWT event queue.  Note that this is different from
0669:             * the implementation of <code>java.awt.Robot.waitForIdle()</code>, which
0670:             * may have events on the queue when it returns.  Do <b>NOT</b> use this
0671:             * method if there are animations or other continual refreshes happening,
0672:             * since in that case it may never return.<p>
0673:             */
0674:            public void waitForIdle() {
0675:                if (eventPostDelay > autoDelay) {
0676:                    delay(eventPostDelay - autoDelay);
0677:                }
0678:                Collection queues = tracker.getEventQueues();
0679:                if (queues.size() == 1) {
0680:                    waitForIdle(toolkit.getSystemEventQueue());
0681:                } else {
0682:                    // FIXME this resurrects dead event queues
0683:                    Iterator iter = queues.iterator();
0684:                    while (iter.hasNext()) {
0685:                        EventQueue eq = (EventQueue) iter.next();
0686:                        waitForIdle(eq);
0687:                    }
0688:                }
0689:            }
0690:
0691:            /** Sample the color at the given point on the screen. */
0692:            public Color sample(int x, int y) {
0693:                // Service mode always returns black when sampled
0694:                if (robot != null && !serviceMode) {
0695:                    return robot.getPixelColor(x, y);
0696:                }
0697:                String msg = Strings.get("tester.Robot.no_sample");
0698:                throw new UnsupportedOperationException(msg);
0699:            }
0700:
0701:            /** Sample the color at the given point on the component. */
0702:            public Color sample(Component c, int x, int y) {
0703:                return sample(c, new ComponentLocation(new Point(x, y)));
0704:            }
0705:
0706:            /** Sample the color at the given location on the component. */
0707:            public Color sample(Component c, ComponentLocation loc) {
0708:                Point p = loc.getPoint(c);
0709:                Point where = AWT.getLocationOnScreen(c);
0710:                where.translate(p.x, p.y);
0711:                return sample(where.x, where.y);
0712:            }
0713:
0714:            /** Capture the contents of the given rectangle. */
0715:            /* NOTE: Text components (and maybe others with a custom cursor) will
0716:             * capture the cursor.  May want to move the cursor out of the component
0717:             * bounds, although this might cause issues where the component is
0718:             * responding visually to mouse movement. 
0719:             * Is this an OSX bug?
0720:             */
0721:            public BufferedImage capture(final Rectangle bounds) {
0722:                Log.debug("Screen capture " + bounds);
0723:                BufferedImage image = null;
0724:                if (robot != null) {
0725:                    image = robot.createScreenCapture(bounds);
0726:                }
0727:                return image;
0728:            }
0729:
0730:            /** Capture the contents of the given component, sans any border or
0731:             * insets.  This should only be used on components that do not use a LAF
0732:             * UI, or the results will not be consistent across platforms.
0733:             */
0734:            public BufferedImage capture(Component comp) {
0735:                return capture(comp, true);
0736:            }
0737:
0738:            /** Capture the contents of the given component, optionally including the
0739:             * border and/or insets.  This should only be used on components that do
0740:             * not use a LAF UI, or the results will not be consistent across
0741:             * platforms. 
0742:             */
0743:            public BufferedImage capture(Component comp, boolean ignoreBorder) {
0744:                Rectangle bounds = new Rectangle(comp.getSize());
0745:                Point loc = AWT.getLocationOnScreen(comp);
0746:                bounds.setLocation(loc.x, loc.y);
0747:                Log.debug("Component bounds " + bounds);
0748:                if (ignoreBorder) {
0749:                    Insets insets = ((Container) comp).getInsets();
0750:                    if (insets != null) {
0751:                        bounds.x += insets.left;
0752:                        bounds.y += insets.top;
0753:                        bounds.width -= insets.left + insets.right;
0754:                        bounds.height -= insets.top + insets.bottom;
0755:                        Log.debug("Component insets " + insets);
0756:                    }
0757:                }
0758:                return capture(bounds);
0759:            }
0760:
0761:            // Bug workaround support
0762:            protected void jitter(Component comp, int x, int y) {
0763:                Log.debug("jitter");
0764:                mouseMove(comp, (x > 0 ? x - 1 : x + 1), y);
0765:            }
0766:
0767:            // Bug workaround support
0768:            protected void jitter(int x, int y) {
0769:                mouseMove((x > 0 ? x - 1 : x + 1), y);
0770:            }
0771:
0772:            /** Move the pointer to the center of the given component. */
0773:            public void mouseMove(Component comp) {
0774:                mouseMove(comp, comp.getWidth() / 2, comp.getHeight() / 2);
0775:            }
0776:
0777:            /** Wait the given number of ms for the component to be showing and
0778:                ready.  Returns false if the operation times out. */
0779:            private boolean waitForComponent(Component c, long delay) {
0780:                if (!isReadyForInput(c)) {
0781:                    Log.debug("Waiting for component to show: " + toString(c));
0782:                    long start = System.currentTimeMillis();
0783:                    while (!isReadyForInput(c)) {
0784:                        if (c instanceof  JPopupMenu) {
0785:                            // wiggle the mouse over the parent menu item to
0786:                            // ensure the submenu shows
0787:                            Component invoker = ((JPopupMenu) c).getInvoker();
0788:                            if (invoker instanceof  JMenu) {
0789:                                jitter(invoker, invoker.getWidth() / 2, invoker
0790:                                        .getHeight() / 2);
0791:                            }
0792:                        }
0793:                        if (System.currentTimeMillis() - start > delay) {
0794:                            Log.warn("Component " + toString(c) + " ("
0795:                                    + Integer.toHexString(c.hashCode()) + ")"
0796:                                    + " not ready after " + delay + "ms: "
0797:                                    + "showing=" + c.isShowing()
0798:                                    + " win ready="
0799:                                    + tracker.isWindowReady(AWT.getWindow(c)));
0800:                            return false;
0801:                        }
0802:                        sleep();
0803:                    }
0804:                }
0805:                return true;
0806:            }
0807:
0808:            /** Move the pointer to the given coordinates relative to the given
0809:             * component.
0810:             */
0811:            public void mouseMove(Component comp, int x, int y) {
0812:                if (!waitForComponent(comp, componentDelay)) {
0813:                    String msg = "Can't obtain position of component "
0814:                            + toString(comp);
0815:                    throw new ComponentNotShowingException(msg);
0816:                }
0817:                if (eventMode == EM_ROBOT) {
0818:                    try {
0819:                        Point point = AWT.getLocationOnScreen(comp);
0820:                        if (point != null) {
0821:                            point.translate(x, y);
0822:                            mouseMove(point.x, point.y);
0823:                        }
0824:                    } catch (java.awt.IllegalComponentStateException e) {
0825:                    }
0826:                } else {
0827:                    Component eventSource = comp;
0828:                    int id = MouseEvent.MOUSE_MOVED;
0829:                    boolean outside = false;
0830:
0831:                    // When dragging, the event source is always the target of the
0832:                    // original mouse press.
0833:                    if (state.isDragging()) {
0834:                        id = MouseEvent.MOUSE_DRAGGED;
0835:                        eventSource = state.getDragSource();
0836:                    } else {
0837:                        Point pt = new Point(x, y);
0838:                        eventSource = comp = AWT.retargetMouseEvent(comp, id,
0839:                                pt);
0840:                        x = pt.x;
0841:                        y = pt.y;
0842:                        outside = x < 0 || y < 0 || x >= comp.getWidth()
0843:                                || y >= comp.getHeight();
0844:                    }
0845:
0846:                    Component current = state.getMouseComponent();
0847:                    if (current != comp) {
0848:                        if (outside && current != null) {
0849:                            Point pt = SwingUtilities.convertPoint(comp, x, y,
0850:                                    current);
0851:                            postMouseMotion(current, MouseEvent.MOUSE_EXITED,
0852:                                    pt);
0853:                            return;
0854:                        }
0855:                        postMouseMotion(comp, MouseEvent.MOUSE_ENTERED,
0856:                                new Point(x, y));
0857:                    }
0858:                    Point pt = new Point(x, y);
0859:                    if (id == MouseEvent.MOUSE_DRAGGED) {
0860:                        // Drag coordinates are relative to drag source component
0861:                        pt = SwingUtilities.convertPoint(comp, pt, eventSource);
0862:                    }
0863:                    postMouseMotion(eventSource, id, pt);
0864:                    // Add an exit event if warranted
0865:                    if (outside) {
0866:                        postMouseMotion(comp, MouseEvent.MOUSE_EXITED,
0867:                                new Point(x, y));
0868:                    }
0869:                }
0870:            }
0871:
0872:            /** Move the mouse appropriately to get from the source to the
0873:                destination.  Enter/exit events will be generated where appropriate.
0874:             */
0875:            public void dragOver(Component dst, int x, int y) {
0876:                mouseMove(dst, x - 4, y);
0877:                mouseMove(dst, x, y);
0878:            }
0879:
0880:            /** Begin a drag operation using button 1.<p>
0881:                This method is tuned for native drag/drop operations, so if you get
0882:                odd behavior, you might try using a simple
0883:                {@link #mousePress(Component,int,int)} instead. 
0884:             */
0885:            public void drag(Component src, int sx, int sy) {
0886:                drag(src, sx, sy, InputEvent.BUTTON1_MASK);
0887:            }
0888:
0889:            /** Begin a drag operation using the given button mask.<p>
0890:                This method is tuned for native drag/drop operations, so if you get
0891:                odd behavior, you might try using a simple
0892:                {@link #mousePress(Component,int,int,int)} instead. 
0893:             */
0894:            // TODO: maybe auto-switch to robot mode if available?
0895:            public void drag(Component src, int sx, int sy, int buttons) {
0896:                if (Bugs.dragDropRequiresNativeEvents()
0897:                        && eventMode != EM_ROBOT
0898:                        && !Boolean.getBoolean("abbot.ignore_drag_error")) {
0899:                    String msg = Strings.get("abbot.Robot.no_drag_available");
0900:                    if (serviceMode) {
0901:                        // If we start a native drag in this mode, it'll pretty much
0902:                        // lock up the system, apparently with the native AWT libs
0903:                        // starting a thread invisible to the VM that chews up all CPU
0904:                        // time. 
0905:                        throw new ActionFailedException(msg);
0906:                    }
0907:                    Log.warn(msg);
0908:                }
0909:
0910:                Log.debug("drag");
0911:                // Some platforms require a pause between mouse down and mouse motion
0912:                int DRAG_DELAY = Properties.getProperty(
0913:                        "abbot.robot.drag_delay", Platform.isX11()
0914:                                || Platform.isOSX() ? 100 : 0, 0, 60000);
0915:                mousePress(src, sx, sy, buttons);
0916:                if (DRAG_DELAY > autoDelay) {
0917:                    delay(DRAG_DELAY);
0918:                }
0919:                if (Platform.isWindows() || Platform.isMacintosh()) {
0920:                    int dx = sx + AWTConstants.DRAG_THRESHOLD < src.getWidth() ? AWTConstants.DRAG_THRESHOLD
0921:                            : 0;
0922:                    int dy = sy + AWTConstants.DRAG_THRESHOLD < src.getHeight() ? AWTConstants.DRAG_THRESHOLD
0923:                            : 0;
0924:                    if (dx == 0 && dy == 0)
0925:                        dx = AWTConstants.DRAG_THRESHOLD;
0926:                    mouseMove(src, sx + dx / 4, sy + dy / 4);
0927:                    mouseMove(src, sx + dx / 2, sy + dy / 2);
0928:                    mouseMove(src, sx + dx, sy + dy);
0929:                    mouseMove(src, sx + dx + 1, sy + dy);
0930:                } else {
0931:                    mouseMove(src, sx + AWTConstants.DRAG_THRESHOLD / 2, sy
0932:                            + AWTConstants.DRAG_THRESHOLD / 2);
0933:                    mouseMove(src, sx + AWTConstants.DRAG_THRESHOLD, sy
0934:                            + AWTConstants.DRAG_THRESHOLD);
0935:                    mouseMove(src, sx + AWTConstants.DRAG_THRESHOLD / 2, sy
0936:                            + AWTConstants.DRAG_THRESHOLD / 2);
0937:                    mouseMove(src, sx, sy);
0938:                }
0939:                Log.debug("drag started");
0940:            }
0941:
0942:            /** End a drag operation, releasing the mouse button over the given target
0943:                location.<p>
0944:                This method is tuned for native drag/drop operations, so if you get
0945:                odd behavior, you might try using a simple
0946:                {@link #mouseMove(Component,int,int)}, {@link #mouseRelease()}
0947:                instead.  
0948:             */
0949:            public void drop(Component target, int x, int y) {
0950:                Log.debug("drop");
0951:                // Delay between final move and drop to ensure drop ends.
0952:                int DROP_DELAY = Properties.getProperty(
0953:                        "abbot.robot.drop_delay", Platform.isWindows() ? 200
0954:                                : 0, 0, 60000);
0955:
0956:                dragOver(target, x, y);
0957:                long start = System.currentTimeMillis();
0958:                while (!state.isDragging()) {
0959:                    if (System.currentTimeMillis() - start > eventPostDelay * 4) {
0960:                        String msg = Strings.get("Robot.no_current_drag");
0961:                        throw new ActionFailedException(msg);
0962:                    }
0963:                    sleep();
0964:                }
0965:                if (DROP_DELAY > autoDelay)
0966:                    delay(DROP_DELAY - autoDelay);
0967:
0968:                mouseRelease(state.getButtons());
0969:                Log.debug("dropped");
0970:            }
0971:
0972:            /** Generate a mouse enter/exit/move/drag for the destination component.
0973:             * NOTE: The VM automatically usually generates exit events; need a test
0974:             * to define the behavior, though.
0975:             */
0976:            private void postMouseMotion(Component dst, int id, Point to) {
0977:                // The VM auto-generates exit events as needed (1.3, 1.4)
0978:                if (id != MouseEvent.MOUSE_DRAGGED)
0979:                    dst = AWT.retargetMouseEvent(dst, id, to);
0980:                // Avoid multiple moves to the same location
0981:                if (state.getMouseComponent() != dst
0982:                        || !to.equals(state.getMouseLocation())) {
0983:                    postEvent(dst, new MouseEvent(dst, id, System
0984:                            .currentTimeMillis(), state.getModifiers(), to.x,
0985:                            to.y, state.getClickCount(), false));
0986:                }
0987:            }
0988:
0989:            /** Type the given keycode with no modifiers. */
0990:            public void key(int keycode) {
0991:                key(keycode, 0);
0992:            }
0993:
0994:            /** Press or release the appropriate modifiers corresponding to the given
0995:                mask.
0996:             */
0997:            public void setModifiers(int modifiers, boolean press) {
0998:                boolean altGraph = (modifiers & InputEvent.ALT_GRAPH_MASK) != 0;
0999:                boolean shift = (modifiers & InputEvent.SHIFT_MASK) != 0;
1000:                boolean alt = (modifiers & InputEvent.ALT_MASK) != 0;
1001:                boolean ctrl = (modifiers & InputEvent.CTRL_MASK) != 0;
1002:                boolean meta = (modifiers & InputEvent.META_MASK) != 0;
1003:                if (press) {
1004:                    if (altGraph)
1005:                        keyPress(KeyEvent.VK_ALT_GRAPH);
1006:                    if (alt)
1007:                        keyPress(KeyEvent.VK_ALT);
1008:                    if (shift)
1009:                        keyPress(KeyEvent.VK_SHIFT);
1010:                    if (ctrl)
1011:                        keyPress(KeyEvent.VK_CONTROL);
1012:                    if (meta)
1013:                        keyPress(KeyEvent.VK_META);
1014:                } else {
1015:                    // For consistency, release in the reverse order of press
1016:                    if (meta)
1017:                        keyRelease(KeyEvent.VK_META);
1018:                    if (ctrl)
1019:                        keyRelease(KeyEvent.VK_CONTROL);
1020:                    if (shift)
1021:                        keyRelease(KeyEvent.VK_SHIFT);
1022:                    if (alt)
1023:                        keyRelease(KeyEvent.VK_ALT);
1024:                    if (altGraph)
1025:                        keyRelease(KeyEvent.VK_ALT_GRAPH);
1026:                }
1027:            }
1028:
1029:            /** Type the given keycode with the given modifiers.  Modifiers is a mask
1030:             * from the available InputEvent masks.
1031:             */
1032:            public void key(int keycode, int modifiers) {
1033:                key(KeyEvent.CHAR_UNDEFINED, keycode, modifiers);
1034:            }
1035:
1036:            private void key(char ch, int keycode, int modifiers) {
1037:                Log.debug("key keycode=" + AWT.getKeyCode(keycode) + " mod="
1038:                        + AWT.getKeyModifiers(modifiers));
1039:                boolean isModifier = true;
1040:                switch (keycode) {
1041:                case KeyEvent.VK_ALT_GRAPH:
1042:                    modifiers |= InputEvent.ALT_GRAPH_MASK;
1043:                    break;
1044:                case KeyEvent.VK_ALT:
1045:                    modifiers |= InputEvent.ALT_MASK;
1046:                    break;
1047:                case KeyEvent.VK_SHIFT:
1048:                    modifiers |= InputEvent.SHIFT_MASK;
1049:                    break;
1050:                case KeyEvent.VK_CONTROL:
1051:                    modifiers |= InputEvent.CTRL_MASK;
1052:                    break;
1053:                case KeyEvent.VK_META:
1054:                    modifiers |= InputEvent.META_MASK;
1055:                    break;
1056:                default:
1057:                    isModifier = false;
1058:                    break;
1059:                }
1060:                setModifiers(modifiers, true);
1061:                if (!isModifier) {
1062:                    keyPress(keycode, ch);
1063:                    keyRelease(keycode);
1064:                }
1065:                setModifiers(modifiers, false);
1066:                if (Bugs.hasKeyStrokeGenerationBug())
1067:                    delay(100);
1068:            }
1069:
1070:            /**
1071:             * Type the given character.  Note that this sends the key to whatever
1072:             * component currently has the focus.
1073:             */
1074:            // FIXME should this be renamed to "key"?
1075:            public void keyStroke(char ch) {
1076:                KeyStroke ks = KeyStrokeMap.getKeyStroke(ch);
1077:                if (ks == null) {
1078:                    // If no mapping is available, we omit press/release events and
1079:                    // only generate a KEY_TYPED event
1080:                    Log.debug("No key mapping for '" + ch + "'");
1081:                    Component focus = findFocusOwner();
1082:                    if (focus == null) {
1083:                        Log.warn("No component has focus, keystroke discarded",
1084:                                Log.FULL_STACK);
1085:                        return;
1086:                    }
1087:                    KeyEvent ke = new KeyEvent(focus, KeyEvent.KEY_TYPED,
1088:                            System.currentTimeMillis(), 0,
1089:                            KeyEvent.VK_UNDEFINED, ch);
1090:                    // Allow any pending robot events to complete; otherwise we
1091:                    // might stuff the typed event before previous robot-generated
1092:                    // events are posted.
1093:                    if (eventMode == EM_ROBOT)
1094:                        waitForIdle();
1095:                    postEvent(focus, ke);
1096:                } else {
1097:                    int keycode = ks.getKeyCode();
1098:                    int mod = ks.getModifiers();
1099:                    Log.debug("Char '" + ch + "' generated by keycode="
1100:                            + keycode + " mod=" + mod);
1101:                    key(ch, keycode, mod);
1102:                }
1103:            }
1104:
1105:            /** Type the given string. */
1106:            public void keyString(String str) {
1107:                char[] ch = str.toCharArray();
1108:                for (int i = 0; i < ch.length; i++) {
1109:                    keyStroke(ch[i]);
1110:                }
1111:            }
1112:
1113:            public void mousePress(Component comp) {
1114:                mousePress(comp, InputEvent.BUTTON1_MASK);
1115:            }
1116:
1117:            public void mousePress(Component comp, int mask) {
1118:                mousePress(comp, comp.getWidth() / 2, comp.getHeight() / 2,
1119:                        mask);
1120:            }
1121:
1122:            public void mousePress(Component comp, int x, int y) {
1123:                mousePress(comp, x, y, InputEvent.BUTTON1_MASK);
1124:            }
1125:
1126:            /** Mouse down in the given part of the component.  All other mousePress
1127:                methods must eventually invoke this one.
1128:             */
1129:            public void mousePress(Component comp, int x, int y, int mask) {
1130:                if (eventMode == EM_ROBOT && Bugs.hasRobotMotionBug()) {
1131:                    jitter(comp, x, y);
1132:                }
1133:                mouseMove(comp, x, y);
1134:                if (eventMode == EM_ROBOT)
1135:                    mousePress(mask);
1136:                else {
1137:                    postMousePress(comp, x, y, mask);
1138:                }
1139:            }
1140:
1141:            /** Post a mouse press event to the AWT event queue for the given
1142:                component.
1143:             */
1144:            private void postMousePress(Component comp, int x, int y, int mask) {
1145:                long when = lastMousePress != null ? lastMousePress.getWhen()
1146:                        : 0;
1147:                long now = System.currentTimeMillis();
1148:                int count = 1;
1149:                Point where = new Point(x, y);
1150:                comp = AWT.retargetMouseEvent(comp, MouseEvent.MOUSE_PRESSED,
1151:                        where);
1152:                if (countingClicks && comp == lastMousePress.getComponent()) {
1153:                    long delta = now - when;
1154:                    if (delta < AWTConstants.MULTI_CLICK_INTERVAL) {
1155:                        count = state.getClickCount() + 1;
1156:                    }
1157:                }
1158:                postEvent(comp, new MouseEvent(comp, MouseEvent.MOUSE_PRESSED,
1159:                        now, state.getKeyModifiers() | mask, where.x, where.y,
1160:                        count, AWTConstants.POPUP_ON_PRESS
1161:                                && (mask & AWTConstants.POPUP_MASK) != 0));
1162:            }
1163:
1164:            /** Post a mouse release event to the AWT event queue for the given
1165:                component.
1166:             */
1167:            private void postMouseRelease(Component c, int x, int y, int mask) {
1168:                long now = System.currentTimeMillis();
1169:                int count = state.getClickCount();
1170:                Point where = new Point(x, y);
1171:                c = AWT.retargetMouseEvent(c, MouseEvent.MOUSE_PRESSED, where);
1172:                postEvent(c, new MouseEvent(c, MouseEvent.MOUSE_RELEASED, now,
1173:                        state.getKeyModifiers() | mask, where.x, where.y,
1174:                        count, !AWTConstants.POPUP_ON_PRESS
1175:                                && (mask & AWTConstants.POPUP_MASK) != 0));
1176:            }
1177:
1178:            /** Click in the center of the given component. */
1179:            final public void click(Component comp) {
1180:                click(comp, comp.getWidth() / 2, comp.getHeight() / 2);
1181:            }
1182:
1183:            /** Click in the center of the given component, specifying which button. */
1184:            final public void click(Component comp, int mask) {
1185:                click(comp, comp.getWidth() / 2, comp.getHeight() / 2, mask);
1186:            }
1187:
1188:            /** Click in the component at the given location. */
1189:            final public void click(Component comp, int x, int y) {
1190:                click(comp, x, y, InputEvent.BUTTON1_MASK);
1191:            }
1192:
1193:            /** Click in the component at the given location with the given button. */
1194:            final public void click(Component comp, int x, int y, int mask) {
1195:                click(comp, x, y, mask, 1);
1196:            }
1197:
1198:            /** Click in the given part of the component.  All other click methods
1199:             * must eventually invoke this one.  This method sometimes needs to be
1200:             * redefined (i.e. JComponent to scroll before clicking).
1201:             */
1202:            public void click(Component comp, int x, int y, int mask, int count) {
1203:                Log.debug("Click at (" + x + "," + y + ") on " + toString(comp)
1204:                        + (count > 1 ? (" count=" + count) : ""));
1205:                int keyModifiers = mask & ~AWTConstants.BUTTON_MASK;
1206:                mask &= AWTConstants.BUTTON_MASK;
1207:                setModifiers(keyModifiers, true);
1208:                // Adjust the auto-delay to ensure we actually get a multiple click
1209:                // In general clicks have to be less than 200ms apart, although the
1210:                // actual setting is not readable by java that I'm aware of.
1211:                int oldDelay = getAutoDelay();
1212:                if (count > 1 && oldDelay * 2 > 200) {
1213:                    setAutoDelay(0);
1214:                }
1215:                long last = System.currentTimeMillis();
1216:                mousePress(comp, x, y, mask);
1217:                while (count-- > 1) {
1218:                    mouseRelease(mask);
1219:                    long delta = System.currentTimeMillis() - last;
1220:                    if (delta > AWTConstants.MULTI_CLICK_INTERVAL)
1221:                        Log.warn("Unexpected delay in multi-click: " + delta);
1222:                    last = System.currentTimeMillis();
1223:                    mousePress(mask);
1224:                }
1225:                setAutoDelay(oldDelay);
1226:                mouseRelease(mask);
1227:                setModifiers(keyModifiers, false);
1228:            }
1229:
1230:            /** @deprecated Renamed to {@link #selectAWTMenuItem(Frame,String)}. */
1231:            public void selectAWTMenuItemByLabel(Frame frame, String path) {
1232:                selectAWTMenuItem(frame, path);
1233:            }
1234:
1235:            /** Select the given menu item from the given Frame.  The given String may
1236:                be either a label or path of labels, but must uniquely identify the
1237:                menu item.  For example, "Copy" would be valid if there is only one
1238:                instance of that menu label under the MenuBar, otherwise you would
1239:                need to specify "Edit|Copy" to ensure the proper selection. 
1240:                Note that this method doesn't require referencing the MenuComponent
1241:                directly as a parameter. 
1242:             */
1243:            public void selectAWTMenuItem(Frame frame, String path) {
1244:                MenuBar mb = frame.getMenuBar();
1245:                if (mb == null) {
1246:                    String msg = Strings.get("tester.Robot.no_menu_bar",
1247:                            new Object[] { toString(frame) });
1248:                    throw new ActionFailedException(msg);
1249:                }
1250:                MenuItem[] items = AWT.findAWTMenuItems(frame, path);
1251:                if (items.length == 0) {
1252:                    String msg = Strings.get("tester.Robot.no_menu_item",
1253:                            new Object[] { path, toString(frame) });
1254:                    throw new ActionFailedException(msg);
1255:                }
1256:                if (items.length > 1) {
1257:                    String msg = Strings
1258:                            .get("tester.Robot.multiple_menu_items");
1259:                    throw new ActionFailedException(msg);
1260:                }
1261:                selectAWTMenuItem(items[0]);
1262:            }
1263:
1264:            /** @deprecated Renamed to
1265:                {@link #selectAWTPopupMenuItem(Component,String)}.
1266:             */
1267:            public void selectAWTPopupMenuItemByLabel(Component invoker,
1268:                    String path) {
1269:                selectAWTPopupMenuItem(invoker, path);
1270:            }
1271:
1272:            /** Select the given menu item from a PopupMenu on the given Component.
1273:                The given String may be either a label or path of labels, but must
1274:                uniquely identify the menu item.  For example, "Copy" would be valid
1275:                if there is only one instance of that menu label under the MenuBar,
1276:                otherwise you would need to specify "Edit|Copy" to ensure the proper
1277:                selection.  If there are more than one PopupMenu registerd on the
1278:                invoking component, you will need to prefix the PopupMenu name as
1279:                well, e.g. "popup0|Edit|Copy". */
1280:            public void selectAWTPopupMenuItem(Component invoker, String path) {
1281:                try {
1282:                    PopupMenu[] popups = AWT.getPopupMenus(invoker);
1283:                    if (popups.length == 0)
1284:                        throw new ActionFailedException(Strings
1285:                                .get("tester.Robot.awt_popup_missing"));
1286:
1287:                    MenuItem[] items = AWT.findAWTPopupMenuItems(invoker, path);
1288:                    if (items.length == 1) {
1289:                        selectAWTPopupMenuItem(items[0]);
1290:                        return;
1291:                    } else if (items.length == 0) {
1292:                        String msg = Strings.get(
1293:                                "tester.Robot.no_popup_menu_item",
1294:                                new Object[] { path, toString(invoker) });
1295:                        throw new ActionFailedException(msg);
1296:                    }
1297:                    String msg = Strings.get(
1298:                            "tester.Robot.multiple_menu_items",
1299:                            new Object[] { path });
1300:                    throw new ActionFailedException(msg);
1301:                } finally {
1302:                    AWT.dismissAWTPopup();
1303:                }
1304:            }
1305:
1306:            protected void fireAccessibleAction(Component context,
1307:                    final AccessibleAction action, String name) {
1308:                if (action != null && action.getAccessibleActionCount() > 0) {
1309:                    invokeLater(context, new Runnable() {
1310:                        public void run() {
1311:                            action.doAccessibleAction(0);
1312:                        }
1313:                    });
1314:                } else {
1315:                    String msg = Strings.get(
1316:                            "tester.Robot.no_accessible_action",
1317:                            new String[] { name });
1318:                    throw new ActionFailedException(msg);
1319:                }
1320:            }
1321:
1322:            private Component getContext(MenuComponent item) {
1323:                while (!(item.getParent() instanceof  Component)
1324:                        && item.getParent() instanceof  MenuComponent)
1325:                    item = (MenuComponent) item.getParent();
1326:                return (Component) item.getParent();
1327:            }
1328:
1329:            /** Select an AWT menu item.  */
1330:            public void selectAWTMenuItem(MenuComponent item) {
1331:                // Can't do this through coordinates because MenuComponents don't
1332:                // store any of that information
1333:                fireAccessibleAction(getContext(item), item
1334:                        .getAccessibleContext().getAccessibleAction(),
1335:                        toString(item));
1336:                if (queueBlocked())
1337:                    key(KeyEvent.VK_ESCAPE);
1338:            }
1339:
1340:            /** Select an AWT popup menu item. */
1341:            public void selectAWTPopupMenuItem(MenuComponent item) {
1342:                // Can't do this through coordinates because MenuComponents don't
1343:                // store any of that information
1344:                fireAccessibleAction(getContext(item), item
1345:                        .getAccessibleContext().getAccessibleAction(),
1346:                        toString(item));
1347:                if (queueBlocked())
1348:                    key(KeyEvent.VK_ESCAPE);
1349:            }
1350:
1351:            /** Is the given component ready for robot input? */
1352:            protected boolean isReadyForInput(Component c) {
1353:                if (eventMode == EM_AWT)
1354:                    return c.isShowing();
1355:                Window w = AWT.getWindow(c);
1356:                if (w == null) {
1357:                    throw new ActionFailedException("Component '" + toString(c)
1358:                            + "' has no Window ancestor");
1359:                }
1360:                return c.isShowing() && tracker.isWindowReady(w);
1361:            }
1362:
1363:            private boolean isOnJMenuBar(Component item) {
1364:                if (item instanceof  javax.swing.JMenuBar)
1365:                    return true;
1366:                Component parent = item instanceof  JPopupMenu ? ((JPopupMenu) item)
1367:                        .getInvoker()
1368:                        : item.getParent();
1369:                return parent != null && isOnJMenuBar(parent);
1370:            }
1371:
1372:            /** Find and select the given menu item, by path. */
1373:            public void selectMenuItem(Component sameWindow, String path) {
1374:                try {
1375:                    Window window = AWT.getWindow(sameWindow);
1376:
1377:                    java.util.List selectionPath = JMenuItemMatcher
1378:                            .splitMenuPath(path);
1379:
1380:                    // For each path entry select in turn to make sure we trigger
1381:                    // any lazy loading
1382:                    //
1383:
1384:                    int i = selectionPath.size();
1385:                    Container context = window;
1386:                    for (int j = 0; j < i; j++) {
1387:
1388:                        // If we are at the last item then we are looking
1389:                        // for a menu item, otherwise we are looking for
1390:                        // a menu instead
1391:                        //
1392:
1393:                        String nextPath = (String) selectionPath.get(j);
1394:                        Matcher m = (j == i - 1) ? new JMenuItemMatcher(
1395:                                nextPath) : new JMenuMatcher(nextPath);
1396:                        // Don't care about the hierarchy on this one, since there'll only
1397:                        // ever be one popup active at a time.
1398:                        Component item = BasicFinder.getDefault().find(context,
1399:                                m);
1400:                        selectMenuItem(item);
1401:                        waitForIdle();
1402:                        context = (Container) item;
1403:                    }
1404:                } catch (ComponentNotFoundException e) {
1405:                    throw new ComponentMissingException(
1406:                            "Can't find menu item '" + path + "'");
1407:                } catch (MultipleComponentsFoundException e) {
1408:                    throw new ActionFailedException(e.getMessage());
1409:                }
1410:            }
1411:
1412:            /** Find and select the given menu item. */
1413:            public void selectMenuItem(Component item) {
1414:                Log.debug("Selecting menu item " + toString(item));
1415:                Component parent = item.getParent();
1416:                JPopupMenu parentPopup = null;
1417:                if (parent instanceof  JPopupMenu) {
1418:                    parentPopup = (JPopupMenu) parent;
1419:                    parent = ((JPopupMenu) parent).getInvoker();
1420:                }
1421:                boolean inMenuBar = parent instanceof  javax.swing.JMenuBar;
1422:                boolean isMenu = item instanceof  javax.swing.JMenu;
1423:
1424:                if (isOnJMenuBar(item) && useScreenMenuBar()) {
1425:                    // Use accessibility action instead
1426:                    fireAccessibleAction(item, item.getAccessibleContext()
1427:                            .getAccessibleAction(), toString(item));
1428:                    return;
1429:                }
1430:
1431:                // If our parent is a menu, activate it first, if it's not already.
1432:                if (parent instanceof  javax.swing.JMenuItem) {
1433:                    if (parentPopup == null || !parentPopup.isShowing()) {
1434:                        Log.debug("Opening parent menu " + toString(parent));
1435:                        selectMenuItem(parent);
1436:                    }
1437:                }
1438:
1439:                // Make sure the appropriate window is in front
1440:                if (inMenuBar) {
1441:                    final Window win = AWT.getWindow(parent);
1442:                    if (win != null) {
1443:                        // Make sure the window is in front, or its menus may be
1444:                        // obscured by another window.
1445:                        invokeAndWait(win, new Runnable() {
1446:                            public void run() {
1447:                                win.toFront();
1448:                            }
1449:                        });
1450:                        mouseMove(win);
1451:                    }
1452:                }
1453:
1454:                // Activate the item
1455:                if (isMenu && !inMenuBar) {
1456:                    // Submenus only require a mouse-over to activate, but do
1457:                    // a click to be certain
1458:                    if (subMenuDelay > autoDelay) {
1459:                        delay(subMenuDelay - autoDelay);
1460:                    }
1461:                }
1462:                // Top-level menus and menu items *must* be clicked on
1463:                Log.debug("Activating menu item " + toString(item));
1464:                if (!item.isEnabled()) {
1465:                    throw new ActionFailedException("Menu item "
1466:                            + toString(item) + " is disabled");
1467:                }
1468:                click(item);
1469:                waitForIdle();
1470:
1471:                // If this item is a menu, make sure its popup is showing before we
1472:                // return 
1473:                if (isMenu) {
1474:                    JPopupMenu popup = ((javax.swing.JMenu) item)
1475:                            .getPopupMenu();
1476:                    if (!waitForComponent(popup, popupDelay)) {
1477:                        String msg = "Clicking on '"
1478:                                + ((javax.swing.JMenu) item).getText()
1479:                                + "' never produced a popup menu";
1480:                        throw new ComponentMissingException(msg);
1481:                    }
1482:                    // for OSX 1.4.1; isShowing set before popup is available
1483:                    if (subMenuDelay > autoDelay) {
1484:                        delay(subMenuDelay - autoDelay);
1485:                    }
1486:                }
1487:            }
1488:
1489:            public void selectPopupMenuItem(Component invoker,
1490:                    ComponentLocation loc, String path) {
1491:                Point where = loc.getPoint(invoker);
1492:
1493:                if (where.x == -1)
1494:                    where.x = invoker.getWidth() / 2;
1495:                if (where.y == -1)
1496:                    where.y = invoker.getHeight() / 2;
1497:                Component popup = showPopupMenu(invoker, where.x, where.y);
1498:                try {
1499:
1500:                    java.util.List selectionPath = JMenuItemMatcher
1501:                            .splitMenuPath(path);
1502:
1503:                    // For each path entry select in turn to make sure we trigger
1504:                    // any lazy loading
1505:                    //
1506:
1507:                    Container context = (Container) popup;
1508:                    int i = selectionPath.size();
1509:                    for (int j = 0; j < i; j++) {
1510:                        Matcher m = new JMenuItemMatcher((String) selectionPath
1511:                                .get(j));
1512:                        // Don't care about the hierarchy on this one, since there'll only
1513:                        // ever be one popup active at a time.
1514:                        Component item = BasicFinder.getDefault().find(context,
1515:                                m);
1516:                        selectMenuItem(item);
1517:                        waitForIdle();
1518:                        context = (Container) item;
1519:                    }
1520:
1521:                } catch (ComponentNotFoundException e) {
1522:                    throw new ComponentMissingException(
1523:                            "Can't find menu item '" + path + "'");
1524:                } catch (MultipleComponentsFoundException e) {
1525:                    throw new ActionFailedException(e.getMessage());
1526:                }
1527:            }
1528:
1529:            /** Attempt to display a popup menu at center of the component. */
1530:            public Component showPopupMenu(Component invoker) {
1531:                return showPopupMenu(invoker, invoker.getWidth() / 2, invoker
1532:                        .getHeight() / 2);
1533:            }
1534:
1535:            /** Attempt to display a popup menu at the given coordinates. */
1536:            public Component showPopupMenu(Component invoker, int x, int y) {
1537:                String where = " at (" + x + "," + y + ")";
1538:                Log.debug("Invoking popup " + where);
1539:                click(invoker, x, y, AWTConstants.POPUP_MASK);
1540:
1541:                Component popup = AWT.findActivePopupMenu();
1542:                if (popup == null) {
1543:                    String msg = "No popup responded to "
1544:                            + AWTConstants.POPUP_MODIFIER + where + " on "
1545:                            + toString(invoker);
1546:                    throw new ComponentMissingException(msg);
1547:                }
1548:                int POPUP_DELAY = 10000;
1549:                long start = System.currentTimeMillis();
1550:                while (!isReadyForInput(SwingUtilities.getWindowAncestor(popup))
1551:                        && System.currentTimeMillis() - start > POPUP_DELAY) {
1552:                    sleep();
1553:                }
1554:                return popup;
1555:            }
1556:
1557:            /** Activate the given window. */
1558:            public void activate(final Window win) {
1559:                // ACTIVATE means window gets keyboard focus.
1560:                invokeAndWait(win, new Runnable() {
1561:                    // FIXME figure out why two are sometimes needed
1562:                    public void run() {
1563:                        win.toFront();
1564:                        win.toFront();
1565:                    }
1566:                });
1567:                // For pointer-focus systems
1568:                mouseMove(win);
1569:            }
1570:
1571:            protected Point getCloseLocation(Container c) {
1572:                Dimension size = c.getSize();
1573:                Insets insets = c.getInsets();
1574:                if (Platform.isOSX()) {
1575:                    return new Point(insets.left + 15, insets.top / 2);
1576:                }
1577:                return new Point(size.width - insets.right - 10, insets.top / 2);
1578:            }
1579:
1580:            /** Invoke the window close operation. */
1581:            public void close(Window w) {
1582:                if (w.isShowing()) {
1583:                    // Move to a corner and "pretend" to use the window manager
1584:                    // control 
1585:                    try {
1586:                        Point p = getCloseLocation(w);
1587:                        mouseMove(w, p.x, p.y);
1588:                    } catch (Exception e) {
1589:                        // ignore
1590:                    }
1591:                    WindowEvent ev = new WindowEvent(w,
1592:                            WindowEvent.WINDOW_CLOSING);
1593:                    // If the window contains an applet, send the event on the
1594:                    // applet's queue instead to ensure a shutdown from the
1595:                    // applet's context (assists AppletViewer cleanup).
1596:                    Component applet = AWT.findAppletDescendent(w);
1597:                    EventQueue eq = tracker.getQueue(applet != null ? applet
1598:                            : w);
1599:                    eq.postEvent(ev);
1600:                }
1601:            }
1602:
1603:            /** Return where the mouse usually grabs to move a window.  Center of the
1604:             * top of the frame is usually a good choice.
1605:             */
1606:            protected Point getMoveLocation(Container c) {
1607:                Dimension size = c.getSize();
1608:                Insets insets = c.getInsets();
1609:                return new Point(size.width / 2, insets.top / 2);
1610:            }
1611:
1612:            /** Move the given Frame/Dialog to the requested location. */
1613:            public void move(Container comp, int newx, int newy) {
1614:                Point loc = AWT.getLocationOnScreen(comp);
1615:                moveBy(comp, newx - loc.x, newy - loc.y);
1616:            }
1617:
1618:            /** Move the given Window by the given amount. */
1619:            public void moveBy(final Container comp, final int dx, final int dy) {
1620:                final Point loc = AWT.getLocationOnScreen(comp);
1621:                boolean userMovable = userMovable(comp);
1622:                if (userMovable) {
1623:                    Point p = getMoveLocation(comp);
1624:                    mouseMove(comp, p.x, p.y);
1625:                    mouseMove(comp, p.x + dx, p.y + dy);
1626:                }
1627:                invokeAndWait(comp, new Runnable() {
1628:                    public void run() {
1629:                        comp.setLocation(new Point(loc.x + dx, loc.y + dy));
1630:                    }
1631:                });
1632:                if (userMovable) {
1633:                    Point p = getMoveLocation(comp);
1634:                    mouseMove(comp, p.x, p.y);
1635:                }
1636:            }
1637:
1638:            /** Return where the mouse usually grabs to resize a window.  The lower
1639:             * right corner of the window is usually a good choice.
1640:             */
1641:            protected Point getResizeLocation(Container c) {
1642:                Dimension size = c.getSize();
1643:                Insets insets = c.getInsets();
1644:                return new Point(size.width - insets.right / 2, size.height
1645:                        - insets.bottom / 2);
1646:            }
1647:
1648:            /** Return whether it is possible for the user to move the given
1649:                component.
1650:             */
1651:            protected boolean userMovable(Component comp) {
1652:                return comp instanceof  Dialog || comp instanceof  Frame
1653:                        || canMoveWindows();
1654:            }
1655:
1656:            /** Return whether it is possible for the user to resize the given
1657:                component.
1658:             */
1659:            protected boolean userResizable(Component comp) {
1660:                if (comp instanceof  Dialog)
1661:                    return ((Dialog) comp).isResizable();
1662:                if (comp instanceof  Frame)
1663:                    return ((Frame) comp).isResizable();
1664:                // most X11 window managers allow arbitrary resizing
1665:                return canResizeWindows();
1666:            }
1667:
1668:            /** Resize the given Frame/Dialog to the given size.  */
1669:            public void resize(Container comp, int width, int height) {
1670:                Dimension size = comp.getSize();
1671:                resizeBy(comp, width - size.width, height - size.height);
1672:            }
1673:
1674:            /** Resize the given Frame/Dialog by the given amounts.  */
1675:            public void resizeBy(final Container comp, final int dx,
1676:                    final int dy) {
1677:                // Fake the pointer motion like we're resizing
1678:                boolean userResizable = userResizable(comp);
1679:                if (userResizable) {
1680:                    Point p = getResizeLocation(comp);
1681:                    mouseMove(comp, p.x, p.y);
1682:                    mouseMove(comp, p.x + dx, p.y + dy);
1683:                }
1684:                invokeAndWait(comp, new Runnable() {
1685:                    public void run() {
1686:                        comp.setSize(comp.getWidth() + dx, comp.getHeight()
1687:                                + dy);
1688:                    }
1689:                });
1690:                if (userResizable) {
1691:                    Point p = getResizeLocation(comp);
1692:                    mouseMove(comp, p.x, p.y);
1693:                }
1694:            }
1695:
1696:            /** Identify the coordinates of the iconify button where we can, returning
1697:             * (0, 0) if we can't.
1698:             */
1699:            protected Point getIconifyLocation(Container c) {
1700:                Dimension size = c.getSize();
1701:                Insets insets = c.getInsets();
1702:                // We know the exact layout of the window manager frames for w32 and
1703:                // OSX.  Currently no way of detecting the WM under X11.  Maybe we
1704:                // could send a WM message (WM_ICONIFY)?
1705:                Point loc = new Point();
1706:                loc.y = insets.top / 2;
1707:                if (Platform.isOSX()) {
1708:                    loc.x = 35;
1709:                } else if (Platform.isWindows()) {
1710:                    int offset = Platform.isWindowsXP() ? 64 : 45;
1711:                    loc.x = size.width - insets.right - offset;
1712:                }
1713:                return loc;
1714:            }
1715:
1716:            private static final int MAXIMIZE_BUTTON_OFFSET = Platform.isOSX() ? 25
1717:                    : Platform.isWindows() ? -20 : 0;
1718:
1719:            /** Identify the coordinates of the maximize button where possible,
1720:                returning null if not.
1721:             */
1722:            protected Point getMaximizeLocation(Container c) {
1723:                Point loc = getIconifyLocation(c);
1724:                loc.x += MAXIMIZE_BUTTON_OFFSET;
1725:                return loc;
1726:            }
1727:
1728:            /** Iconify the given Frame.  Don't support iconification of Dialogs at
1729:             * this point (although maybe should).
1730:             */
1731:            public void iconify(final Frame frame) {
1732:                Point loc = getIconifyLocation(frame);
1733:                if (loc != null) {
1734:                    mouseMove(frame, loc.x, loc.y);
1735:                }
1736:                invokeLater(frame, new Runnable() {
1737:                    public void run() {
1738:                        frame.setState(Frame.ICONIFIED);
1739:                    }
1740:                });
1741:            }
1742:
1743:            public void deiconify(Frame frame) {
1744:                normalize(frame);
1745:            }
1746:
1747:            public void normalize(final Frame frame) {
1748:                invokeLater(frame, new Runnable() {
1749:                    public void run() {
1750:                        frame.setState(Frame.NORMAL);
1751:                        if (Bugs.hasFrameDeiconifyBug())
1752:                            frame.setVisible(true);
1753:                    }
1754:                });
1755:            }
1756:
1757:            /** Make the window full size.  On 1.3.1, this is not reversible. */
1758:            public void maximize(final Frame frame) {
1759:                Point loc = getMaximizeLocation(frame);
1760:                if (loc != null) {
1761:                    mouseMove(frame, loc.x, loc.y);
1762:                }
1763:                invokeLater(frame, new Runnable() {
1764:                    public void run() {
1765:                        // If the maximize is unavailable, set to full screen size
1766:                        // instead. 
1767:                        try {
1768:                            final int MAXIMIZED_BOTH = 6;
1769:                            Boolean b = (Boolean) Toolkit.class.getMethod(
1770:                                    "isFrameStateSupported",
1771:                                    new Class[] { int.class })
1772:                                    .invoke(
1773:                                            toolkit,
1774:                                            new Object[] { new Integer(
1775:                                                    MAXIMIZED_BOTH) });
1776:                            if (b.booleanValue() && !serviceMode) {
1777:                                Frame.class.getMethod("setExtendedState",
1778:                                        new Class[] { int.class, }).invoke(
1779:                                        frame,
1780:                                        new Object[] { new Integer(
1781:                                                MAXIMIZED_BOTH) });
1782:                            } else {
1783:                                throw new ActionFailedException(
1784:                                        "Platform won't maximize");
1785:                            }
1786:                        } catch (Exception e) {
1787:                            Log.debug("Maximize not supported: " + e);
1788:                            Rectangle rect = frame.getGraphicsConfiguration()
1789:                                    .getBounds();
1790:                            frame.setLocation(rect.x, rect.y);
1791:                            frame.setSize(rect.width, rect.height);
1792:                        }
1793:                    }
1794:                });
1795:            }
1796:
1797:            /** Send the given event as appropriate to the event-generation mode. */
1798:            public void sendEvent(AWTEvent event) {
1799:                // Modifiers are ignored, assuming that an event will be
1800:                // sent that causes modifiers to be sent appropriately.  
1801:                if (eventMode == EM_ROBOT) {
1802:                    int id = event.getID();
1803:                    Log.debug("Sending event id " + id);
1804:                    if (id >= MouseEvent.MOUSE_FIRST
1805:                            && id <= MouseEvent.MOUSE_LAST) {
1806:                        MouseEvent me = (MouseEvent) event;
1807:                        Component comp = me.getComponent();
1808:                        if (id == MouseEvent.MOUSE_MOVED) {
1809:                            mouseMove(comp, me.getX(), me.getY());
1810:                        } else if (id == MouseEvent.MOUSE_DRAGGED) {
1811:                            mouseMove(comp, me.getX(), me.getY());
1812:                        } else if (id == MouseEvent.MOUSE_PRESSED) {
1813:                            mouseMove(comp, me.getX(), me.getY());
1814:                            mousePress(me.getModifiers()
1815:                                    & AWTConstants.BUTTON_MASK);
1816:                        } else if (id == MouseEvent.MOUSE_ENTERED) {
1817:                            mouseMove(comp, me.getX(), me.getY());
1818:                        } else if (id == MouseEvent.MOUSE_EXITED) {
1819:                            mouseMove(comp, me.getX(), me.getY());
1820:                        } else if (id == MouseEvent.MOUSE_RELEASED) {
1821:                            mouseMove(comp, me.getX(), me.getY());
1822:                            mouseRelease(me.getModifiers()
1823:                                    & AWTConstants.BUTTON_MASK);
1824:                        }
1825:                    } else if (id >= KeyEvent.KEY_FIRST
1826:                            && id <= KeyEvent.KEY_LAST) {
1827:                        KeyEvent ke = (KeyEvent) event;
1828:                        if (id == KeyEvent.KEY_PRESSED) {
1829:                            keyPress(ke.getKeyCode());
1830:                        } else if (id == KeyEvent.KEY_RELEASED) {
1831:                            keyRelease(ke.getKeyCode());
1832:                        }
1833:                    } else {
1834:                        Log.warn("Event not supported: " + event);
1835:                    }
1836:                } else {
1837:                    // Post the event to the appropriate AWT event queue
1838:                    postEvent((Component) event.getSource(), event);
1839:                }
1840:            }
1841:
1842:            /** Return the symbolic name of the given event's ID. */
1843:            public static String getEventID(AWTEvent event) {
1844:                // Optimize here to avoid field name lookup overhead
1845:                switch (event.getID()) {
1846:                case MouseEvent.MOUSE_MOVED:
1847:                    return "MOUSE_MOVED";
1848:                case MouseEvent.MOUSE_DRAGGED:
1849:                    return "MOUSE_DRAGGED";
1850:                case MouseEvent.MOUSE_PRESSED:
1851:                    return "MOUSE_PRESSED";
1852:                case MouseEvent.MOUSE_CLICKED:
1853:                    return "MOUSE_CLICKED";
1854:                case MouseEvent.MOUSE_RELEASED:
1855:                    return "MOUSE_RELEASED";
1856:                case MouseEvent.MOUSE_ENTERED:
1857:                    return "MOUSE_ENTERED";
1858:                case MouseEvent.MOUSE_EXITED:
1859:                    return "MOUSE_EXITED";
1860:                case KeyEvent.KEY_PRESSED:
1861:                    return "KEY_PRESSED";
1862:                case KeyEvent.KEY_TYPED:
1863:                    return "KEY_TYPED";
1864:                case KeyEvent.KEY_RELEASED:
1865:                    return "KEY_RELEASED";
1866:                case WindowEvent.WINDOW_OPENED:
1867:                    return "WINDOW_OPENED";
1868:                case WindowEvent.WINDOW_CLOSING:
1869:                    return "WINDOW_CLOSING";
1870:                case WindowEvent.WINDOW_CLOSED:
1871:                    return "WINDOW_CLOSED";
1872:                case WindowEvent.WINDOW_ICONIFIED:
1873:                    return "WINDOW_ICONIFIED";
1874:                case WindowEvent.WINDOW_DEICONIFIED:
1875:                    return "WINDOW_DEICONIFIED";
1876:                case WindowEvent.WINDOW_ACTIVATED:
1877:                    return "WINDOW_ACTIVATED";
1878:                case WindowEvent.WINDOW_DEACTIVATED:
1879:                    return "WINDOW_DEACTIVATED";
1880:                case ComponentEvent.COMPONENT_MOVED:
1881:                    return "COMPONENT_MOVED";
1882:                case ComponentEvent.COMPONENT_RESIZED:
1883:                    return "COMPONENT_RESIZED";
1884:                case ComponentEvent.COMPONENT_SHOWN:
1885:                    return "COMPONENT_SHOWN";
1886:                case ComponentEvent.COMPONENT_HIDDEN:
1887:                    return "COMPONENT_HIDDEN";
1888:                case FocusEvent.FOCUS_GAINED:
1889:                    return "FOCUS_GAINED";
1890:                case FocusEvent.FOCUS_LOST:
1891:                    return "FOCUS_LOST";
1892:                case HierarchyEvent.HIERARCHY_CHANGED:
1893:                    return "HIERARCHY_CHANGED";
1894:                case HierarchyEvent.ANCESTOR_MOVED:
1895:                    return "ANCESTOR_MOVED";
1896:                case HierarchyEvent.ANCESTOR_RESIZED:
1897:                    return "ANCESTOR_RESIZED";
1898:                case PaintEvent.PAINT:
1899:                    return "PAINT";
1900:                case PaintEvent.UPDATE:
1901:                    return "UPDATE";
1902:                case ActionEvent.ACTION_PERFORMED:
1903:                    return "ACTION_PERFORMED";
1904:                case InputMethodEvent.CARET_POSITION_CHANGED:
1905:                    return "CARET_POSITION_CHANGED";
1906:                case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:
1907:                    return "INPUT_METHOD_TEXT_CHANGED";
1908:                default:
1909:                    return Reflector.getFieldName(event.getClass(), event
1910:                            .getID(), "");
1911:                }
1912:            }
1913:
1914:            public static Class getCanonicalClass(Class refClass) {
1915:                // Don't use classnames from anonymous inner classes...
1916:                // Don't use classnames from platform LAF classes...
1917:                String className = refClass.getName();
1918:                while (className.indexOf("$") != -1
1919:                        || className.startsWith("javax.swing.plaf")
1920:                        || className.startsWith("com.apple.mrj")) {
1921:                    refClass = refClass.getSuperclass();
1922:                    className = refClass.getName();
1923:                }
1924:                return refClass;
1925:            }
1926:
1927:            /** Provides a more concise representation of the component than the
1928:             * default Component.toString().
1929:             */
1930:            public static String toString(Component comp) {
1931:                if (comp == null)
1932:                    return "(null)";
1933:
1934:                if (AWT.isTransientPopup(comp)) {
1935:                    boolean tooltip = AWT.isToolTip(comp);
1936:                    if (AWT.isHeavyweightPopup(comp)) {
1937:                        return tooltip ? Strings
1938:                                .get("component.heavyweight_tooltip") : Strings
1939:                                .get("component.heavyweight_popup");
1940:                    } else if (AWT.isLightweightPopup(comp)) {
1941:                        return tooltip ? Strings
1942:                                .get("component.lightweight_tooltip") : Strings
1943:                                .get("component.lightweight_popup");
1944:                    }
1945:                } else if (AWT.isSharedInvisibleFrame(comp)) {
1946:                    return Strings.get("component.default_frame");
1947:                }
1948:                String name = getDescriptiveName(comp);
1949:                String classDesc = descriptiveClassName(comp.getClass());
1950:                if (name == null) {
1951:                    if (AWT.isContentPane(comp)) {
1952:                        name = Strings.get("component.content_pane");
1953:                    } else if (AWT.isGlassPane(comp)) {
1954:                        name = Strings.get("component.glass_pane");
1955:                    } else if (comp instanceof  JLayeredPane) {
1956:                        name = Strings.get("component.layered_pane");
1957:                    } else if (comp instanceof  JRootPane) {
1958:                        name = Strings.get("component.root_pane");
1959:                    } else {
1960:                        name = classDesc + " instance";
1961:                    }
1962:                } else {
1963:                    name = "'" + name + "' (" + classDesc + ")";
1964:                }
1965:                return name;
1966:            }
1967:
1968:            /** Provide a string representation of the given component (Component or
1969:             * MenuComponent.
1970:             */
1971:            public static String toString(Object obj) {
1972:                if (obj instanceof  Component)
1973:                    return toString((Component) obj);
1974:                else if (obj instanceof  MenuBar)
1975:                    return "MenuBar";
1976:                else if (obj instanceof  MenuItem)
1977:                    return ((MenuItem) obj).getLabel();
1978:                return obj.toString();
1979:            }
1980:
1981:            protected static String descriptiveClassName(Class cls) {
1982:                StringBuffer desc = new StringBuffer(simpleClassName(cls));
1983:                Class coreClass = getCanonicalClass(cls);
1984:                String coreClassName = coreClass.getName();
1985:                while (!coreClassName.startsWith("java.awt.")
1986:                        && !coreClassName.startsWith("javax.swing.")
1987:                        && !coreClassName.startsWith("java.applet.")) {
1988:                    coreClass = coreClass.getSuperclass();
1989:                    coreClassName = coreClass.getName();
1990:                }
1991:                if (!coreClass.equals(cls)) {
1992:                    desc.append("/");
1993:                    desc.append(simpleClassName(coreClass));
1994:                }
1995:                return desc.toString();
1996:            }
1997:
1998:            /** Provides the hierarchic path of the given component by component
1999:                class, e.g. "JFrame:JRootPane:JPanel:JButton".
2000:             */
2001:            public static String toHierarchyPath(Component c) {
2002:                StringBuffer buf = new StringBuffer();
2003:                Container parent = c.getParent();
2004:                if (parent != null) {
2005:                    buf.append(toHierarchyPath(parent));
2006:                    buf.append(":");
2007:                }
2008:                buf.append(descriptiveClassName(c.getClass()));
2009:                String name = getDescriptiveName(c);
2010:                if (name != null) {
2011:                    buf.append("(");
2012:                    buf.append(name);
2013:                    buf.append(")");
2014:                } else if (parent != null && parent.getComponentCount() > 1
2015:                        && c instanceof  JPanel) {
2016:                    buf.append("[");
2017:                    buf.append(String.valueOf(getIndex(parent, c)));
2018:                    buf.append("]");
2019:                }
2020:                return buf.toString();
2021:            }
2022:
2023:            /** Provide a more concise representation of the event than the default
2024:             * AWTEvent.toString().
2025:             */
2026:            public static String toString(AWTEvent event) {
2027:                String name = toString(event.getSource());
2028:                String desc = getEventID(event);
2029:                if (event.getID() == KeyEvent.KEY_PRESSED
2030:                        || event.getID() == KeyEvent.KEY_RELEASED) {
2031:                    KeyEvent ke = (KeyEvent) event;
2032:                    desc += " (" + AWT.getKeyCode(ke.getKeyCode());
2033:                    if (ke.getModifiers() != 0) {
2034:                        desc += "/" + AWT.getKeyModifiers(ke.getModifiers());
2035:                    }
2036:                    desc += ")";
2037:                } else if (event.getID() == InputMethodEvent.INPUT_METHOD_TEXT_CHANGED) {
2038:                    desc += " ("
2039:                            + ((InputMethodEvent) event)
2040:                                    .getCommittedCharacterCount() + ")";
2041:                } else if (event.getID() == KeyEvent.KEY_TYPED) {
2042:                    char ch = ((KeyEvent) event).getKeyChar();
2043:                    int mods = ((KeyEvent) event).getModifiers();
2044:                    desc += " ('"
2045:                            + ch
2046:                            + (mods != 0 ? "/" + AWT.getKeyModifiers(mods) : "")
2047:                            + "')";
2048:                } else if (event.getID() >= MouseEvent.MOUSE_FIRST
2049:                        && event.getID() <= MouseEvent.MOUSE_LAST) {
2050:                    MouseEvent me = (MouseEvent) event;
2051:                    if (me.getModifiers() != 0) {
2052:                        desc += " <" + AWT.getMouseModifiers(me.getModifiers());
2053:                        if (me.getClickCount() > 1) {
2054:                            desc += "," + me.getClickCount();
2055:                        }
2056:                        desc += ">";
2057:                    }
2058:                    desc += " (" + me.getX() + "," + me.getY() + ")";
2059:                } else if (event.getID() == HierarchyEvent.HIERARCHY_CHANGED) {
2060:                    HierarchyEvent he = (HierarchyEvent) event;
2061:                    long flags = he.getChangeFlags();
2062:                    String type = "";
2063:                    String bar = "";
2064:                    if ((flags & HierarchyEvent.SHOWING_CHANGED) != 0) {
2065:                        type += (he.getComponent().isShowing() ? "" : "!")
2066:                                + "SHOWING";
2067:                        bar = "|";
2068:                    }
2069:                    if ((flags & HierarchyEvent.PARENT_CHANGED) != 0) {
2070:                        type += bar + "PARENT:"
2071:                                + toString(he.getComponent().getParent());
2072:                        bar = "|";
2073:                    }
2074:                    if ((flags & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0) {
2075:                        type += bar + "DISPLAYABILITY";
2076:                    }
2077:                    desc += " (" + type + ")";
2078:                }
2079:                return desc + " on " + name;
2080:            }
2081:
2082:            /** Return the numeric event ID corresponding to the given string. */
2083:            public static int getEventID(Class cls, String id) {
2084:                return Reflector.getFieldValue(cls, id);
2085:            }
2086:
2087:            /** Strip the package from the class name. */
2088:            public static String simpleClassName(Class cls) {
2089:                String name = cls.getName();
2090:                int dot = name.lastIndexOf(".");
2091:                return name.substring(dot + 1, name.length());
2092:            }
2093:
2094:            private AWTEvent lastEventPosted = null;
2095:            private MouseEvent lastMousePress = null;
2096:            private boolean countingClicks = false;
2097:
2098:            /** Post the given event to the corresponding event queue for the given
2099:                component. */
2100:            protected void postEvent(Component comp, AWTEvent ev) {
2101:                if (Log.isClassDebugEnabled(Robot.class))
2102:                    Log.debug("POST: " + toString(ev));
2103:                if (eventMode == EM_AWT && AWT.isAWTPopupMenuBlocking()) {
2104:                    throw new Error(
2105:                            "Event queue is blocked by an active AWT PopupMenu");
2106:                }
2107:                // Force an update of the input state, so that we're in synch
2108:                // internally.  Otherwise we might post more events before this
2109:                // one gets processed and end up using stale values for those events.
2110:                state.update(ev);
2111:                EventQueue q = getEventQueue(comp);
2112:                q.postEvent(ev);
2113:                delay(autoDelay);
2114:                AWTEvent prev = lastEventPosted;
2115:                lastEventPosted = ev;
2116:                if (ev instanceof  MouseEvent) {
2117:                    if (ev.getID() == MouseEvent.MOUSE_PRESSED) {
2118:                        lastMousePress = (MouseEvent) ev;
2119:                        countingClicks = true;
2120:                    } else if (ev.getID() != MouseEvent.MOUSE_RELEASED
2121:                            && ev.getID() != MouseEvent.MOUSE_CLICKED) {
2122:                        countingClicks = false;
2123:                    }
2124:                }
2125:
2126:                // Generate a click if there are no events between press/release
2127:                // Unfortunately, I can only guess how the VM generates them
2128:                if (eventMode == EM_AWT
2129:                        && ev.getID() == MouseEvent.MOUSE_RELEASED
2130:                        && prev.getID() == MouseEvent.MOUSE_PRESSED) {
2131:                    MouseEvent me = (MouseEvent) ev;
2132:                    AWTEvent click = new MouseEvent(comp,
2133:                            MouseEvent.MOUSE_CLICKED, System
2134:                                    .currentTimeMillis(), me.getModifiers(), me
2135:                                    .getX(), me.getY(), me.getClickCount(),
2136:                            false);
2137:                    postEvent(comp, click);
2138:                }
2139:            }
2140:
2141:            /** Wait for the given Condition to return true.  The default timeout may
2142:             * be changed by setting abbot.robot.default_delay.
2143:             * @throws WaitTimedOutError if the default timeout (30s) is exceeded. 
2144:             * @see Robot#wait(Condition, long, int) Robot.wait For a description of the use of this function to support lazy loading in class files
2145:             */
2146:            public void wait(Condition condition) {
2147:                wait(condition, defaultDelay);
2148:            }
2149:
2150:            /** Wait for the given Condition to return true, waiting for timeout ms.
2151:             * @throws WaitTimedOutError if the timeout is exceeded. 
2152:             * @see Robot#wait(Condition, long, int) Robot.wait For a description of the use of this function to support lazy loading in class files
2153:             */
2154:            public void wait(Condition condition, long timeout) {
2155:                wait(condition, timeout, SLEEP_INTERVAL);
2156:            }
2157:
2158:            /** 
2159:             * Wait for the given Condition to return true, waiting for timeout ms,
2160:             * polling at the given interval. This method can be used generically to
2161:             * support components that are lazily loaded in the context of writing
2162:             * testers or other testing code.
2163:             * <p>
2164:             * Take for example the simple case of trying to select an item in a list.
2165:             * If the model for this list is populate asynchronously then you may need
2166:             * to poll the list for a given amount of time until the item appears. This
2167:             * is very common in an application that contains many long running tasks.
2168:             * <p>
2169:             * A general solution to the problem can be seen in this pseudo code:
2170:             * <pre>
2171:             *   wait(new Condition()
2172:             *        {
2173:             *           public boolean test()
2174:             *           {
2175:             *             return whether the ui element is avaliable
2176:             *           }
2177:             *        });
2178:             *   performAction(ui element);
2179:             * </pre>
2180:             * <p>
2181:             * If you are writing a tester method then it is a good idea to use a standard
2182:             * timeout such as {@link Robot#componentDelay} to ensure they are consistently
2183:             * handled accross different testers. 
2184:             * 
2185:             * @throws WaitTimedOutError if the timeout is exceeded. 
2186:             */
2187:            public void wait(Condition condition, long timeout, int interval) {
2188:                long start = System.currentTimeMillis();
2189:                while (!condition.test()) {
2190:                    if (System.currentTimeMillis() - start > timeout) {
2191:                        String msg = "Timed out waiting for " + condition;
2192:                        throw new WaitTimedOutError(msg);
2193:                    }
2194:                    delay(interval);
2195:                }
2196:            }
2197:
2198:            public void reset() {
2199:                if (eventMode == EM_ROBOT) {
2200:                    Dimension d = toolkit.getScreenSize();
2201:                    mouseMove(d.width / 2, d.height / 2);
2202:                    mouseMove(d.width / 2 - 1, d.height / 2 - 1);
2203:                } else {
2204:                    // clear any held state
2205:                    state.clear();
2206:                }
2207:            }
2208:
2209:            /** Return the Component which currently owns the focus. */
2210:            public Component findFocusOwner() {
2211:                return AWT.getFocusOwner();
2212:            }
2213:
2214:            /** Return a descriptive name for the given component for use in UI
2215:             * text (may be localized if appropriate and need not be re-usable
2216:             * across locales.
2217:             */
2218:            public static String getDescriptiveName(Component c) {
2219:                if (AWT.isSharedInvisibleFrame(c))
2220:                    return Strings.get("component.default_frame");
2221:
2222:                String name = getName(c);
2223:                if (name == null) {
2224:                    if ((name = getTitle(c)) == null) {
2225:                        if ((name = getText(c)) == null) {
2226:                            if ((name = getLabel(c)) == null) {
2227:                                if ((name = getIconName(c)) == null) {
2228:                                }
2229:                            }
2230:                        }
2231:                    }
2232:                }
2233:                return name;
2234:            }
2235:
2236:            public static String getName(Component c) {
2237:                String name = AWT.hasDefaultName(c) ? null : c.getName();
2238:                // Accessibility behaves like what we used to do with getTag.
2239:                // Not too helpful for our purposes, especially when the
2240:                // data on which the name is based might be dynamic.
2241:                /*
2242:                if (name == null) {
2243:                    AccessibleContext context = c.getAccessibleContext();
2244:                    if (context != null) 
2245:                        name = context.getAccessibleName();
2246:                }
2247:                 */
2248:                return name;
2249:            }
2250:
2251:            /** Returns the index of the given component within the given container. */
2252:            public static int getIndex(Container parent, Component comp) {
2253:                if (comp instanceof  Window) {
2254:                    Window[] owned = ((Window) parent).getOwnedWindows();
2255:                    for (int i = 0; i < owned.length; i++) {
2256:                        if (owned[i] == comp) {
2257:                            return i;
2258:                        }
2259:                    }
2260:                } else {
2261:                    Component[] children = parent.getComponents();
2262:                    for (int i = 0; i < children.length; ++i) {
2263:                        if (children[i] == comp) {
2264:                            return i;
2265:                        }
2266:                    }
2267:                }
2268:                return -1;
2269:            }
2270:
2271:            public static String getText(Component c) {
2272:                if (c instanceof  AbstractButton) {
2273:                    return ComponentTester.stripHTML(((AbstractButton) c)
2274:                            .getText());
2275:                } else if (c instanceof  JLabel) {
2276:                    return ComponentTester.stripHTML(((JLabel) c).getText());
2277:                } else if (c instanceof  Label) {
2278:                    return ((Label) c).getText();
2279:                }
2280:                return null;
2281:            }
2282:
2283:            public static String getLabel(Component c) {
2284:                String label = null;
2285:                if (c instanceof  JComponent) {
2286:                    Object obj = ((JComponent) c)
2287:                            .getClientProperty(LABELED_BY_PROPERTY);
2288:                    // While the default is a JLabel, users may use something else as
2289:                    // the property, so be careful.
2290:                    if (obj != null) {
2291:                        if (obj instanceof  JLabel) {
2292:                            label = ((JLabel) obj).getText();
2293:                        } else if (obj instanceof  String) {
2294:                            label = (String) obj;
2295:                        }
2296:                    }
2297:                } else if (c instanceof  Button) {
2298:                    label = ((Button) c).getLabel();
2299:                } else if (c instanceof  Checkbox) {
2300:                    label = ((Checkbox) c).getLabel();
2301:                }
2302:                return ComponentTester.stripHTML(label);
2303:            }
2304:
2305:            public static String getIconName(Component c) {
2306:                String icon = null;
2307:                AccessibleContext context = c.getAccessibleContext();
2308:                if (context != null) {
2309:                    AccessibleIcon[] icons = context.getAccessibleIcon();
2310:                    if (icons != null && icons.length > 0) {
2311:                        icon = icons[0].getAccessibleIconDescription();
2312:                        if (icon != null) {
2313:                            icon = icon.substring(icon.lastIndexOf("/") + 1);
2314:                            icon = icon.substring(icon.lastIndexOf("\\") + 1);
2315:                        }
2316:                    }
2317:                }
2318:                return icon;
2319:            }
2320:
2321:            public static String getBorderTitle(Component c) {
2322:                String title = null;
2323:                if (c instanceof  JComponent) {
2324:                    title = getBorderTitle(((JComponent) c).getBorder());
2325:                }
2326:                return title;
2327:            }
2328:
2329:            /** See javax.swing.JComponent.getBorderTitle. */
2330:            private static String getBorderTitle(Border b) {
2331:                String title = null;
2332:                if (b instanceof  TitledBorder)
2333:                    title = ((TitledBorder) b).getTitle();
2334:                else if (b instanceof  CompoundBorder) {
2335:                    title = getBorderTitle(((CompoundBorder) b)
2336:                            .getInsideBorder());
2337:                    if (title == null) {
2338:                        title = getBorderTitle(((CompoundBorder) b)
2339:                                .getOutsideBorder());
2340:                    }
2341:                }
2342:                return title;
2343:            }
2344:
2345:            public static String getTitle(Component c) {
2346:                if (c instanceof  Dialog)
2347:                    return ((Dialog) c).getTitle();
2348:                else if (c instanceof  Frame)
2349:                    return ((Frame) c).getTitle();
2350:                else if (c instanceof  JInternalFrame)
2351:                    return ((JInternalFrame) c).getTitle();
2352:                return null;
2353:            }
2354:
2355:            /** Returns whether it is possible to resize windows that are not an
2356:                instance of Frame or Dialog.  Most X11 window managers will allow
2357:                this, but stock Macintosh and Windows do not.
2358:             */
2359:            public static boolean canResizeWindows() {
2360:                return !Platform.isWindows() && !Platform.isMacintosh();
2361:            }
2362:
2363:            /** Returns whether it is possible to move windows that are not an
2364:                instance of Frame or Dialog.  Most X11 window managers will allow
2365:                this, but stock Macintosh and Windows do not.
2366:             */
2367:            public static boolean canMoveWindows() {
2368:                return !Platform.isWindows() && !Platform.isMacintosh();
2369:            }
2370:
2371:            /** Returns the appropriate auto delay for robot-generated events. 
2372:             */
2373:            public static int getPreferredRobotAutoDelay() {
2374:                // better safe than sorry, and slower and accurate than
2375:                // fast and inaccurate.
2376:                /*
2377:                if (Platform.isWindows() || Platform.isOSX() || Platform.isX11())
2378:                    return 0;
2379:                 */
2380:                // >= 40 causes problems registering a double-click when clicks
2381:                // are requested separately (due to auto-jitter and other delay 
2382:                // being added on individual clicks).
2383:                return 30;
2384:            }
2385:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.