1 /*
   2  * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @summary Utility routines that wait for a window to be displayed or for colors to be visible
  26  * @summary com.apple.junit.utils
  27  */
  28 
  29 package test.java.awt.regtesthelpers;
  30 
  31 import java.awt.*;
  32 import java.awt.event.InputEvent;
  33 import java.util.TimerTask;
  34 import javax.swing.JButton;
  35 
  36 public class RobotUtilities {
  37     public static final int CLICK_DELAY = 20;        // interval between mouse down and mouse up events
  38     public static final int DOUBLE_CLICK_DELAY = 100;    // interval between clicks of a double click
  39     public static final int POST_MOVE_DELAY = 250;    // allow some time for visual verification
  40     public static final int PRE_TEST_DELAY = 250;    // allow some time for frame to draw
  41     public static final int POST_TEST_DELAY = 750;    // allow some time for event processing/visual verification
  42 
  43     public RobotUtilities() {
  44 
  45     }
  46 
  47     /////////////////////////////////////////////////////////////////////////////////////////////////
  48     /////////////////////////////////////////////////////////////////////////////////////////////////
  49     public static void pressKey(int num) {
  50         Robot robot = getRobot();
  51         robot.keyPress(num);
  52     }
  53 
  54     /////////////////////////////////////////////////////////////////////////////////////////////////
  55     /////////////////////////////////////////////////////////////////////////////////////////////////
  56     public static void releaseKey(int num) {
  57         Robot robot = getRobot();
  58         robot.keyRelease(num);
  59     }
  60 
  61     /////////////////////////////////////////////////////////////////////////////////////////////////
  62     /////////////////////////////////////////////////////////////////////////////////////////////////
  63     public static void typeKey(int num) {
  64         Robot robot = getRobot();
  65         robot.keyPress(num);
  66         robot.delay(CLICK_DELAY);
  67         robot.keyRelease(num);
  68     }
  69 
  70     static Robot _robot;
  71     private static Robot getRobot() {
  72         if (_robot == null) {
  73             try { _robot = new Robot(); } catch (AWTException e) { throw new RuntimeException(e); }
  74         }
  75         return _robot;
  76     }
  77 
  78     /////////////////////////////////////////////////////////////////////////////////////////////////
  79     // moveMouse - move the cusor to the specified location
  80     /////////////////////////////////////////////////////////////////////////////////////////////////
  81     public static void moveMouseTo(int posX, int posY) {
  82         Robot robot = getRobot();
  83         robot.mouseMove(posX , posY);
  84         robot.delay(POST_MOVE_DELAY);
  85     }
  86 
  87     /////////////////////////////////////////////////////////////////////////////////////////////////
  88     // moveMouse - move the cusor to the specified location of the component
  89     //    positive values specify the offset from the top-left of the component
  90     //    negative values specify the offset from the bottom-right of the component
  91     /////////////////////////////////////////////////////////////////////////////////////////////////
  92         public static void moveMouseTo(Component c, int posX, int posY) {
  93         Point pt;
  94         int x;
  95         int y;
  96 
  97         if(c == null)
  98             return;
  99 
 100         // Get the position of the component
 101         pt = c.getLocationOnScreen();
 102 
 103         x = pt.x + posX;
 104         if(posX < 0)
 105             x += c.getWidth();
 106 
 107         y = pt.y + posY;
 108         if(posY < 0)
 109             y += c.getHeight();
 110 
 111         moveMouseTo(x, y);
 112 //        robot.mouseMove(x , y);
 113 //        robot.delay(POST_MOVE_DELAY);
 114     }
 115 
 116     /////////////////////////////////////////////////////////////////////////////////////////////////
 117     // moveMouse - move the cusor to the specified location of the component
 118     //    positive values specify the offset from the top-left of the component
 119     //    negative values specify the offset from the bottom-right of the component
 120     /////////////////////////////////////////////////////////////////////////////////////////////////
 121     public static void moveMouseFromCenter(Component c, int offsetX, int offsetY) {
 122         Point pt;
 123         int x;
 124         int y;
 125 
 126         if(c == null)
 127             return;
 128 
 129         // Get the position of the component
 130         pt = c.getLocationOnScreen();
 131 
 132         x = pt.x + offsetX + c.getWidth()/2;
 133 
 134         y = pt.y + offsetY + c.getHeight()/2;
 135 
 136         moveMouseTo(x, y);
 137     }
 138 
 139     /////////////////////////////////////////////////////////////////////////////////////////////////
 140     // moveMouseToCenter - move the cusor to the center of the component
 141     /////////////////////////////////////////////////////////////////////////////////////////////////
 142     public static void moveMouseToCenter(Component c) {
 143         Point pt;
 144         int x;
 145         int y;
 146 
 147         if(c == null)
 148             return;
 149 
 150         // Get the position of the component
 151         pt = c.getLocationOnScreen();
 152 
 153         x = pt.x + c.getWidth()/2;
 154 
 155         y = pt.y + c.getHeight()/2;
 156 
 157         moveMouseTo(x, y);
 158     }
 159 
 160     /////////////////////////////////////////////////////////////////////////////////////////////////
 161     /////////////////////////////////////////////////////////////////////////////////////////////////
 162     public static void pressMouseButton() {
 163         Robot robot = getRobot();
 164         robot.mousePress(InputEvent.BUTTON1_MASK);
 165     }
 166 
 167     /////////////////////////////////////////////////////////////////////////////////////////////////
 168     /////////////////////////////////////////////////////////////////////////////////////////////////
 169     public static void releaseMouseButton() {
 170         Robot robot = getRobot();
 171         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 172     }
 173 
 174     /////////////////////////////////////////////////////////////////////////////////////////////////
 175     /////////////////////////////////////////////////////////////////////////////////////////////////
 176     public static void click() {
 177         Robot robot = getRobot();
 178         robot.mousePress(InputEvent.BUTTON1_MASK);
 179         robot.delay(CLICK_DELAY);
 180         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 181     }
 182 
 183     /////////////////////////////////////////////////////////////////////////////////////////////////
 184     /////////////////////////////////////////////////////////////////////////////////////////////////
 185     public static void click(Component c) {
 186     Point pt;
 187     int x;
 188     int y;
 189 
 190     if(c == null)
 191         return;
 192 
 193         // Get the position of the component
 194     pt = c.getLocationOnScreen();
 195 
 196     x = pt.x + c.getWidth()/2;
 197     y = pt.y + c.getHeight()/2;
 198 
 199         moveMouseTo(x , y);
 200 
 201         click();
 202     }
 203 
 204     /////////////////////////////////////////////////////////////////////////////////////////////////
 205     /////////////////////////////////////////////////////////////////////////////////////////////////
 206     public static void doubleClick() {
 207         Robot robot = getRobot();
 208         click();
 209         robot.delay(DOUBLE_CLICK_DELAY);
 210         click();
 211     }
 212 
 213     /////////////////////////////////////////////////////////////////////////////////////////////////
 214     /////////////////////////////////////////////////////////////////////////////////////////////////
 215     public static void doubleClick(Component c) {
 216     Point pt;
 217     int x;
 218     int y;
 219 
 220     if(c == null)
 221         return;
 222 
 223         // Get the position of the component
 224     pt = c.getLocationOnScreen();
 225 
 226     x = pt.x + c.getWidth()/2;
 227     y = pt.y + c.getHeight()/2;
 228 
 229         moveMouseTo(x , y);
 230 
 231         doubleClick();
 232     }
 233 
 234     /////////////////////////////////////////////////////////////////////////////////////////////////
 235     /////////////////////////////////////////////////////////////////////////////////////////////////
 236     public static void tripleClick() {
 237         Robot robot = getRobot();
 238         click();
 239         robot.delay(DOUBLE_CLICK_DELAY);
 240         click();
 241         robot.delay(DOUBLE_CLICK_DELAY);
 242         click();
 243     }
 244 
 245     /////////////////////////////////////////////////////////////////////////////////////////////////
 246     /////////////////////////////////////////////////////////////////////////////////////////////////
 247     public static void tripleClick(Component c) {
 248     Point pt;
 249     int x;
 250     int y;
 251 
 252     if(c == null)
 253         return;
 254 
 255         // Get the position of the component
 256     pt = c.getLocationOnScreen();
 257 
 258     x = pt.x + c.getWidth()/2;
 259     y = pt.y + c.getHeight()/2;
 260 
 261         moveMouseTo(x , y);
 262 
 263         tripleClick();
 264     }
 265 
 266     /////////////////////////////////////////////////////////////////////////////////////////////////
 267     // clickAt - click at specified point
 268     /////////////////////////////////////////////////////////////////////////////////////////////////
 269     public static void clickAt(int posX, int posY) {
 270         moveMouseTo(posX , posY);
 271         click();
 272     }
 273 
 274     /////////////////////////////////////////////////////////////////////////////////////////////////
 275     // clickAt - click at specified point in the component
 276     //    positive values specify the offset from the top-left of the component
 277     //    negative values specify the offset from the bottom-right of the component
 278     /////////////////////////////////////////////////////////////////////////////////////////////////
 279     public static void clickAt(Component c, int posX, int posY) {
 280         moveMouseTo(c, posX, posY);
 281         click();
 282     }
 283 
 284     /////////////////////////////////////////////////////////////////////////////////////////////////
 285     /////////////////////////////////////////////////////////////////////////////////////////////////
 286     public static void delay(int interval) {
 287         Robot robot = getRobot();
 288         robot.delay(interval);
 289     }
 290 
 291     /////////////////////////////////////////////////////////////////////////////////////////////////
 292     // clickAndDrag - click and drag within the component
 293     //    positive values specify the offset from the top-left of the component
 294     //    negative values specify the offset from the bottom-right of the component
 295     /////////////////////////////////////////////////////////////////////////////////////////////////
 296     public static void clickAndDrag(Component c, int startX, int startY, int endX, int endY) {
 297     Point pt;
 298     int x;
 299     int y;
 300 
 301     if(c == null)
 302         return;
 303 
 304         // Get the position of the component
 305     pt = c.getLocationOnScreen();
 306 
 307     // Make adjustments for negative values of offset
 308         x = pt.x + startX;
 309         if(startX < 0)
 310             x += c.getWidth();
 311 
 312     y = pt.y + startY;
 313         if(startY < 0)
 314             y += c.getHeight();
 315 
 316 
 317         moveMouseTo(x , y);
 318         pressMouseButton();
 319 
 320         x = pt.x + endX;
 321         if(endX < 0)
 322             x += c.getWidth();
 323 
 324     y = pt.y + endY;
 325         if(endY < 0)
 326             y += c.getHeight();
 327 
 328         moveMouseTo(x , y);
 329         releaseMouseButton();
 330     }
 331 
 332 
 333     /////////////////////////////////////////////////////////////////////////////////////////////////
 334     // screenshot - take a screenshot and save to disk as a jpg
 335     //  basename - base name of the file. the file will be named <basename>.<timestamp>.jpg
 336     //  location - parent directory. If null, uses the current working directory.
 337     //  return value - the File for the newly created image.
 338     //  failure cases - if the basename is null, the file already exists, or location isn't a directory, returns null.
 339     /////////////////////////////////////////////////////////////////////////////////////////////////
 340     public static java.io.File screenshot(String basename, java.io.File location) throws java.io.IOException, java.awt.AWTException {
 341         if (basename == null) return null;
 342         if (location != null) {
 343             if (!location.exists() || !location.isDirectory()) {
 344                 return null;
 345             }
 346         }
 347 
 348         Robot robot = getRobot();
 349         java.awt.image.BufferedImage screenshot = robot.createScreenCapture(new java.awt.Rectangle(java.awt.Toolkit.getDefaultToolkit().getScreenSize()));
 350 
 351         java.util.GregorianCalendar calendar = new java.util.GregorianCalendar();
 352         StringBuffer sb = new StringBuffer();
 353         sb.append(basename);
 354         sb.append(".");
 355         sb.append(calendar.get(java.util.Calendar.YEAR));
 356         sb.append(calendar.get(java.util.Calendar.MONTH));
 357         sb.append(calendar.get(java.util.Calendar.DAY_OF_MONTH));
 358         sb.append(calendar.get(java.util.Calendar.HOUR_OF_DAY));
 359         sb.append(calendar.get(java.util.Calendar.MINUTE));
 360         sb.append(".png");
 361 
 362         java.io.File outputFile = new java.io.File(location, sb.toString());
 363         javax.imageio.ImageIO.write(screenshot, "png", outputFile);
 364 
 365         return outputFile;
 366     }
 367 
 368 
 369     /*
 370      * Utility function to walk the container heirarchy looking for a JButton
 371      * matching a specific text string.  For example, this is used to extract
 372      * the "Cancel" button from a JDialog.
 373      */
 374 
 375     public static JButton extractJButton( Container parent, String text ) {
 376         JButton cancel = null;
 377         Component[] c = parent.getComponents();
 378         for (int i = 0; i < c.length; i += 1) {
 379             if (c[i]instanceof JButton) {
 380                 JButton b = (JButton) c[i];
 381                 if (b.getText().equals( text )) {
 382                     cancel = (JButton) c[i];
 383                     break;
 384                 }
 385             }
 386             else if (c[i]instanceof Container) {
 387                 cancel = extractJButton( (Container) c[i], text );
 388             }
 389         }
 390         return cancel;
 391     }
 392 
 393 
 394     /*
 395      *    Utility class that takes a JButton and, later on, clicks it
 396      */
 397 
 398     public static class Clicker extends TimerTask {
 399         JButton target = null;
 400         private Exception cachedException;
 401 
 402         // We need to know what to click
 403         public Clicker( JButton target) {
 404             super();
 405             this.target = target;
 406         }
 407 
 408         // This does the clicking
 409         public void run() {
 410             try {
 411                 Robot r = new Robot();
 412                 Point pt = target.getLocationOnScreen();
 413                 int x = pt.x + target.getWidth() / 2;
 414                 int y = pt.y + target.getHeight() / 2;
 415                 r.mouseMove( x, y );
 416                 r.delay( 30 );
 417                 r.mousePress( InputEvent.BUTTON1_MASK );
 418                 r.delay( 101 );
 419                 r.mouseRelease( InputEvent.BUTTON1_MASK );
 420             }
 421             catch(Exception x) {
 422                 setCachedException(x);
 423             }
 424         }
 425 
 426         void setCachedException(Exception cachedException) {
 427             this.cachedException = cachedException;
 428         }
 429 
 430         public Exception getCachedException() {
 431             return cachedException;
 432         }
 433 
 434 
 435     }
 436 
 437 }