1 /*
   2  * Copyright (c) 2011, 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
  26             colors to be visible
  27  * @summary com.apple.junit.utils
  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 
  38     // interval between mouse down and mouse up events
  39     public static final int CLICK_DELAY = 20;
  40     // interval between clicks of a double click
  41     public static final int DOUBLE_CLICK_DELAY = 100;
  42     // allow some time for visual verification
  43     public static final int POST_MOVE_DELAY = 250;
  44     // allow some time for frame to draw
  45     public static final int PRE_TEST_DELAY = 250;
  46     // allow some time for event processing/visual verification
  47     public static final int POST_TEST_DELAY = 750;
  48 
  49     public RobotUtilities() {
  50 
  51     }
  52 
  53     public static void pressKey(int num) {
  54         Robot robot = getRobot();
  55         robot.keyPress(num);
  56     }
  57 
  58     public static void releaseKey(int num) {
  59         Robot robot = getRobot();
  60         robot.keyRelease(num);
  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 
  72     private static Robot getRobot() {
  73         if (_robot == null) {
  74             try {
  75                 _robot = new Robot();
  76             } catch (AWTException e) {
  77                 throw new RuntimeException(e);
  78             }
  79         }
  80         return _robot;
  81     }
  82 
  83     ////////////////////////////////////////////////////////////////////////
  84     // moveMouse - move the cusor to the specified location
  85     ////////////////////////////////////////////////////////////////////////
  86     public static void moveMouseTo(int posX, int posY) {
  87         Robot robot = getRobot();
  88         robot.mouseMove(posX, posY);
  89         robot.delay(POST_MOVE_DELAY);
  90     }
  91 
  92     ////////////////////////////////////////////////////////////////////////
  93     // moveMouse - move the cusor to the specified location of the component
  94     // positive values specify the offset from the top-left of the component
  95     // negative values specify the offset from the bottom-right of the component
  96     ////////////////////////////////////////////////////////////////////////
  97     public static void moveMouseTo(Component c, int posX, int posY) {
  98         Point pt;
  99         int x;
 100         int y;
 101 
 102         if (c == null) {
 103             return;
 104         }
 105 
 106         // Get the position of the component
 107         pt = c.getLocationOnScreen();
 108 
 109         x = pt.x + posX;
 110         if (posX < 0) {
 111             x += c.getWidth();
 112         }
 113 
 114         y = pt.y + posY;
 115         if (posY < 0) {
 116             y += c.getHeight();
 117         }
 118 
 119         moveMouseTo(x, y);
 120 //        robot.mouseMove(x , y);
 121 //        robot.delay(POST_MOVE_DELAY);
 122     }
 123 
 124     /////////////////////////////////////////////////////////////////////////
 125     // moveMouse - move the cusor to the specified location of the component
 126     // positive values specify the offset from the top-left of the component
 127     // negative values specify the offset from the bottom-right of the component
 128     /////////////////////////////////////////////////////////////////////////
 129     public static void moveMouseFromCenter(Component c,
 130             int offsetX,
 131             int offsetY) {
 132         Point pt;
 133         int x;
 134         int y;
 135 
 136         if (c == null) {
 137             return;
 138         }
 139 
 140         // Get the position of the component
 141         pt = c.getLocationOnScreen();
 142 
 143         x = pt.x + offsetX + c.getWidth() / 2;
 144 
 145         y = pt.y + offsetY + c.getHeight() / 2;
 146 
 147         moveMouseTo(x, y);
 148     }
 149 
 150     ///////////////////////////////////////////////////////////////////////
 151     // moveMouseToCenter - move the cusor to the center of the component
 152     ///////////////////////////////////////////////////////////////////////
 153     public static void moveMouseToCenter(Component c) {
 154         Point pt;
 155         int x;
 156         int y;
 157 
 158         if (c == null) {
 159             return;
 160         }
 161 
 162         // Get the position of the component
 163         pt = c.getLocationOnScreen();
 164 
 165         x = pt.x + c.getWidth() / 2;
 166 
 167         y = pt.y + c.getHeight() / 2;
 168 
 169         moveMouseTo(x, y);
 170     }
 171 
 172     public static void pressMouseButton() {
 173         Robot robot = getRobot();
 174         robot.mousePress(InputEvent.BUTTON1_MASK);
 175     }
 176 
 177     public static void releaseMouseButton() {
 178         Robot robot = getRobot();
 179         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 180     }
 181 
 182     public static void click() {
 183         Robot robot = getRobot();
 184         robot.mousePress(InputEvent.BUTTON1_MASK);
 185         robot.delay(CLICK_DELAY);
 186         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 187     }
 188 
 189     public static void click(Component c) {
 190         Point pt;
 191         int x;
 192         int y;
 193 
 194         if (c == null) {
 195             return;
 196         }
 197 
 198         // Get the position of the component
 199         pt = c.getLocationOnScreen();
 200 
 201         x = pt.x + c.getWidth() / 2;
 202         y = pt.y + c.getHeight() / 2;
 203 
 204         moveMouseTo(x, y);
 205 
 206         click();
 207     }
 208 
 209     public static void doubleClick() {
 210         Robot robot = getRobot();
 211         click();
 212         robot.delay(DOUBLE_CLICK_DELAY);
 213         click();
 214     }
 215 
 216     public static void doubleClick(Component c) {
 217         Point pt;
 218         int x;
 219         int y;
 220 
 221         if (c == null) {
 222             return;
 223         }
 224 
 225         // Get the position of the component
 226         pt = c.getLocationOnScreen();
 227 
 228         x = pt.x + c.getWidth() / 2;
 229         y = pt.y + c.getHeight() / 2;
 230 
 231         moveMouseTo(x, y);
 232 
 233         doubleClick();
 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     public static void tripleClick(Component c) {
 246         Point pt;
 247         int x;
 248         int y;
 249 
 250         if (c == null) {
 251             return;
 252         }
 253 
 254         // Get the position of the component
 255         pt = c.getLocationOnScreen();
 256 
 257         x = pt.x + c.getWidth() / 2;
 258         y = pt.y + c.getHeight() / 2;
 259 
 260         moveMouseTo(x, y);
 261 
 262         tripleClick();
 263     }
 264 
 265     ///////////////////////////////////////////////////////////////////////
 266     // clickAt - click at specified point
 267     ///////////////////////////////////////////////////////////////////////
 268     public static void clickAt(int posX, int posY) {
 269         moveMouseTo(posX, posY);
 270         click();
 271     }
 272 
 273     /////////////////////////////////////////////////////////////////////////
 274     // clickAt - click at specified point in the component
 275     // positive values specify the offset from the top-left of the component
 276     // negative values specify the offset from the bottom-right of the component
 277     //////////////////////////////////////////////////////////////////////////
 278     public static void clickAt(Component c, int posX, int posY) {
 279         moveMouseTo(c, posX, posY);
 280         click();
 281     }
 282 
 283     ///////////////////////////////////////////////////////////////////////
 284     ///////////////////////////////////////////////////////////////////////
 285     public static void delay(int interval) {
 286         Robot robot = getRobot();
 287         robot.delay(interval);
 288     }
 289 
 290     /////////////////////////////////////////////////////////////////////////
 291     // clickAndDrag - click and drag within the component
 292     // positive values specify the offset from the top-left of the component
 293     // negative values specify the offset from the bottom-right of the component
 294     /////////////////////////////////////////////////////////////////////////
 295     public static void clickAndDrag(Component c,
 296             int startX,
 297             int startY,
 298             int endX,
 299             int endY) {
 300         Point pt;
 301         int x;
 302         int y;
 303 
 304         if (c == null) {
 305             return;
 306         }
 307 
 308         // Get the position of the component
 309         pt = c.getLocationOnScreen();
 310 
 311         // Make adjustments for negative values of offset
 312         x = pt.x + startX;
 313         if (startX < 0) {
 314             x += c.getWidth();
 315         }
 316 
 317         y = pt.y + startY;
 318         if (startY < 0) {
 319             y += c.getHeight();
 320         }
 321 
 322         moveMouseTo(x, y);
 323         pressMouseButton();
 324 
 325         x = pt.x + endX;
 326         if (endX < 0) {
 327             x += c.getWidth();
 328         }
 329 
 330         y = pt.y + endY;
 331         if (endY < 0) {
 332             y += c.getHeight();
 333         }
 334 
 335         moveMouseTo(x, y);
 336         releaseMouseButton();
 337     }
 338 
 339     ///////////////////////////////////////////////////////////////////////
 340     // screenshot - take a screenshot and save to disk as a jpg
 341     //  basename - base name of the file. the file will be named
 342     //             <basename>.<timestamp>.jpg
 343     //  location - parent directory. If null, uses the current working directory.
 344     //  return value - the File for the newly created image.
 345     //  failure cases - if the basename is null, the file already exists, or
 346     //                  location isn't a directory, returns null.
 347     ///////////////////////////////////////////////////////////////////////
 348     public static java.io.File screenshot(String basename,
 349             java.io.File location)
 350             throws java.io.IOException, java.awt.AWTException {
 351         if (basename == null) {
 352             return null;
 353         }
 354         if (location != null) {
 355             if (!location.exists() || !location.isDirectory()) {
 356                 return null;
 357             }
 358         }
 359 
 360         Robot robot = getRobot();
 361         java.awt.image.BufferedImage screenshot = robot.createScreenCapture(
 362                 new java.awt.Rectangle(
 363                         java.awt.Toolkit.getDefaultToolkit().getScreenSize()));
 364 
 365         java.util.GregorianCalendar calendar = new java.util.GregorianCalendar();
 366         StringBuffer sb = new StringBuffer();
 367         sb.append(basename);
 368         sb.append(".");
 369         sb.append(calendar.get(java.util.Calendar.YEAR));
 370         sb.append(calendar.get(java.util.Calendar.MONTH));
 371         sb.append(calendar.get(java.util.Calendar.DAY_OF_MONTH));
 372         sb.append(calendar.get(java.util.Calendar.HOUR_OF_DAY));
 373         sb.append(calendar.get(java.util.Calendar.MINUTE));
 374         sb.append(".png");
 375 
 376         java.io.File outputFile = new java.io.File(location, sb.toString());
 377         javax.imageio.ImageIO.write(screenshot, "png", outputFile);
 378 
 379         return outputFile;
 380     }
 381 
 382     /*
 383      * Utility function to walk the container heirarchy looking for a JButton
 384      * matching a specific text string.  For example, this is used to extract
 385      * the "Cancel" button from a JDialog.
 386      */
 387     public static JButton extractJButton(Container parent, String text) {
 388         JButton cancel = null;
 389         Component[] c = parent.getComponents();
 390         for (int i = 0; i < c.length; i += 1) {
 391             if (c[i] instanceof JButton) {
 392                 JButton b = (JButton) c[i];
 393                 if (b.getText().equals(text)) {
 394                     cancel = (JButton) c[i];
 395                     break;
 396                 }
 397             } else if (c[i] instanceof Container) {
 398                 cancel = extractJButton((Container) c[i], text);
 399             }
 400         }
 401         return cancel;
 402     }
 403 
 404     /*
 405      *    Utility class that takes a JButton and, later on, clicks it
 406      */
 407     public static class Clicker extends TimerTask {
 408 
 409         JButton target = null;
 410         private Exception cachedException;
 411 
 412         // We need to know what to click
 413         public Clicker(JButton target) {
 414             super();
 415             this.target = target;
 416         }
 417 
 418         // This does the clicking
 419         public void run() {
 420             try {
 421                 Robot r = new Robot();
 422                 Point pt = target.getLocationOnScreen();
 423                 int x = pt.x + target.getWidth() / 2;
 424                 int y = pt.y + target.getHeight() / 2;
 425                 r.mouseMove(x, y);
 426                 r.delay(30);
 427                 r.mousePress(InputEvent.BUTTON1_MASK);
 428                 r.delay(101);
 429                 r.mouseRelease(InputEvent.BUTTON1_MASK);
 430             } catch (Exception x) {
 431                 setCachedException(x);
 432             }
 433         }
 434 
 435         void setCachedException(Exception cachedException) {
 436             this.cachedException = cachedException;
 437         }
 438 
 439         public Exception getCachedException() {
 440             return cachedException;
 441         }
 442     }
 443 }