jdk/test/java/awt/Mixing/AWT_Mixing/Util.java
changeset 26382 b764fbee45e2
parent 26381 bbce32388a2d
parent 26380 436d37b20f8d
child 26384 3b419bf4f176
equal deleted inserted replaced
26381:bbce32388a2d 26382:b764fbee45e2
     1 /*
       
     2  * Copyright (c) 2014, 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 import java.awt.Component;
       
    25 import java.awt.Frame;
       
    26 import java.awt.Dialog;
       
    27 import java.awt.Window;
       
    28 import java.awt.Button;
       
    29 import java.awt.Point;
       
    30 import java.awt.Dimension;
       
    31 import java.awt.Rectangle;
       
    32 import java.awt.Robot;
       
    33 import java.awt.Toolkit;
       
    34 import java.awt.IllegalComponentStateException;
       
    35 import java.awt.AWTException;
       
    36 import java.awt.AWTEvent;
       
    37 
       
    38 import java.awt.event.InputEvent;
       
    39 import java.awt.event.WindowAdapter;
       
    40 import java.awt.event.WindowEvent;
       
    41 import java.awt.event.ActionEvent;
       
    42 import java.awt.event.FocusEvent;
       
    43 import java.awt.event.WindowListener;
       
    44 import java.awt.event.WindowFocusListener;
       
    45 import java.awt.event.FocusListener;
       
    46 import java.awt.event.ActionListener;
       
    47 
       
    48 import java.awt.peer.FramePeer;
       
    49 
       
    50 import java.lang.reflect.Constructor;
       
    51 import java.lang.reflect.Field;
       
    52 import java.lang.reflect.InvocationTargetException;
       
    53 import java.lang.reflect.Method;
       
    54 
       
    55 import java.security.PrivilegedAction;
       
    56 import java.security.AccessController;
       
    57 
       
    58 import java.util.concurrent.atomic.AtomicBoolean;
       
    59 
       
    60 /**
       
    61  * <p>This class contains utilities useful for regression testing.
       
    62  * <p>When using jtreg you would include this class into the build
       
    63  * list via something like:
       
    64  * <pre>
       
    65      &amp;library ../../../../share/lib/AWT_Mixing/src/regtesthelpers/
       
    66      &amp;build Util
       
    67      &amp;run main YourTest
       
    68    </pre>
       
    69  * Note that if you are about to create a test based on
       
    70  * Applet-template, then put those lines into html-file, not in java-file.
       
    71  * <p> And put an
       
    72  * import regtesthelpers.Util;
       
    73  * into the java source of test.
       
    74 */
       
    75 public final class Util {
       
    76     private Util() {} // this is a helper class with static methods :)
       
    77 
       
    78     /*
       
    79      * @throws RuntimeException when creation failed
       
    80      */
       
    81     public static Robot createRobot() {
       
    82         try {
       
    83             return new Robot();
       
    84         } catch (AWTException e) {
       
    85             throw new RuntimeException("Error: unable to create robot", e);
       
    86         }
       
    87     }
       
    88 
       
    89     public static Frame createEmbeddedFrame(final Frame embedder)
       
    90         throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException,
       
    91                InstantiationException, InvocationTargetException
       
    92     {
       
    93         Toolkit tk = Toolkit.getDefaultToolkit();
       
    94         FramePeer frame_peer = (FramePeer) embedder.getPeer();
       
    95         System.out.println("frame's peer = " + frame_peer);
       
    96         if ("sun.awt.windows.WToolkit".equals(tk.getClass().getName())) {
       
    97             Class comp_peer_class =
       
    98                 Class.forName("sun.awt.windows.WComponentPeer");
       
    99             System.out.println("comp peer class = " + comp_peer_class);
       
   100             Field hwnd_field = comp_peer_class.getDeclaredField("hwnd");
       
   101             hwnd_field.setAccessible(true);
       
   102             System.out.println("hwnd_field =" + hwnd_field);
       
   103             long hwnd = hwnd_field.getLong(frame_peer);
       
   104             System.out.println("hwnd = " + hwnd);
       
   105 
       
   106             Class clazz = Class.forName("sun.awt.windows.WEmbeddedFrame");
       
   107             Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE});
       
   108             return (Frame) constructor.newInstance (new Object[] {hwnd});
       
   109         } else if ("sun.awt.X11.XToolkit".equals(tk.getClass().getName())) {
       
   110             Class x_base_window_class = Class.forName("sun.awt.X11.XBaseWindow");
       
   111             System.out.println("x_base_window_class = " + x_base_window_class);
       
   112             Method get_window = x_base_window_class.getMethod("getWindow", new Class[0]);
       
   113             System.out.println("get_window = " + get_window);
       
   114             long window = (Long) get_window.invoke(frame_peer, new Object[0]);
       
   115             System.out.println("window = " + window);
       
   116             Class clazz = Class.forName("sun.awt.X11.XEmbeddedFrame");
       
   117             Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE, Boolean.TYPE});
       
   118             return (Frame) constructor.newInstance (new Object[] {window, true});
       
   119         }
       
   120 
       
   121         throw new RuntimeException("Unexpected toolkit - " + tk);
       
   122     }
       
   123 
       
   124     /**
       
   125      * Makes the window visible and waits until it's shown.
       
   126      */
       
   127     public static void showWindowWait(Window win) {
       
   128         win.setVisible(true);
       
   129         waitTillShown(win);
       
   130     }
       
   131 
       
   132     /**
       
   133      * Moves mouse pointer in the center of given {@code comp} component
       
   134      * using {@code robot} parameter.
       
   135      */
       
   136     public static void pointOnComp(final Component comp, final Robot robot) {
       
   137         Rectangle bounds = new Rectangle(comp.getLocationOnScreen(), comp.getSize());
       
   138         robot.mouseMove(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
       
   139     }
       
   140 
       
   141     /**
       
   142      * Moves mouse pointer in the center of a given {@code comp} component
       
   143      * and performs a left mouse button click using the {@code robot} parameter
       
   144      * with the {@code delay} delay between press and release.
       
   145      */
       
   146     public static void clickOnComp(final Component comp, final Robot robot, int delay) {
       
   147         pointOnComp(comp, robot);
       
   148         robot.delay(delay);
       
   149         robot.mousePress(InputEvent.BUTTON1_MASK);
       
   150         robot.delay(delay);
       
   151         robot.mouseRelease(InputEvent.BUTTON1_MASK);
       
   152     }
       
   153 
       
   154     /**
       
   155      * Moves mouse pointer in the center of a given {@code comp} component
       
   156      * and performs a left mouse button click using the {@code robot} parameter
       
   157      * with the default delay between press and release.
       
   158      */
       
   159     public static void clickOnComp(final Component comp, final Robot robot) {
       
   160         clickOnComp(comp, robot, 50);
       
   161     }
       
   162 
       
   163     /*
       
   164      * Clicks on a title of Frame/Dialog.
       
   165      * WARNING: it may fail on some platforms when the window is not wide enough.
       
   166      */
       
   167     public static void clickOnTitle(final Window decoratedWindow, final Robot robot) {
       
   168         Point p = decoratedWindow.getLocationOnScreen();
       
   169         Dimension d = decoratedWindow.getSize();
       
   170 
       
   171         if (decoratedWindow instanceof Frame || decoratedWindow instanceof Dialog) {
       
   172             robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)decoratedWindow.getInsets().top/2);
       
   173             robot.delay(50);
       
   174             robot.mousePress(InputEvent.BUTTON1_MASK);
       
   175             robot.delay(50);
       
   176             robot.mouseRelease(InputEvent.BUTTON1_MASK);
       
   177         }
       
   178     }
       
   179 
       
   180     public static void waitForIdle(final Robot robot) {
       
   181         // we do not use robot for now, use SunToolkit.realSync() instead
       
   182         ((sun.awt.SunToolkit)Toolkit.getDefaultToolkit()).realSync();
       
   183     }
       
   184 
       
   185     public static Field getField(final Class klass, final String fieldName) {
       
   186         return AccessController.doPrivileged(new PrivilegedAction<Field>() {
       
   187             public Field run() {
       
   188                 try {
       
   189                     Field field = klass.getDeclaredField(fieldName);
       
   190                     assert (field != null);
       
   191                     field.setAccessible(true);
       
   192                     return field;
       
   193                 } catch (SecurityException se) {
       
   194                     throw new RuntimeException("Error: unexpected exception caught!", se);
       
   195                 } catch (NoSuchFieldException nsfe) {
       
   196                     throw new RuntimeException("Error: unexpected exception caught!", nsfe);
       
   197                 }
       
   198             }
       
   199         });
       
   200     }
       
   201 
       
   202     /*
       
   203      * Waits for a notification and for a boolean condition to become true.
       
   204      * The method returns when the above conditions are fullfilled or when the timeout
       
   205      * occurs.
       
   206      *
       
   207      * @param condition the object to be notified and the booelan condition to wait for
       
   208      * @param timeout the maximum time to wait in milliseconds
       
   209      * @param catchExceptions if {@code true} the method catches InterruptedException
       
   210      * @return the final boolean value of the {@code condition}
       
   211      * @throws InterruptedException if the awaiting proccess has been interrupted
       
   212      */
       
   213     public static boolean waitForConditionEx(final AtomicBoolean condition, long timeout)
       
   214       throws InterruptedException
       
   215         {
       
   216             synchronized (condition) {
       
   217                 long startTime = System.currentTimeMillis();
       
   218                 while (!condition.get()) {
       
   219                     condition.wait(timeout);
       
   220                     if (System.currentTimeMillis() - startTime >= timeout ) {
       
   221                         break;
       
   222                     }
       
   223                 }
       
   224             }
       
   225             return condition.get();
       
   226         }
       
   227 
       
   228     /*
       
   229      * The same as {@code waitForConditionEx(AtomicBoolean, long)} except that it
       
   230      * doesn't throw InterruptedException.
       
   231      */
       
   232     public static boolean waitForCondition(final AtomicBoolean condition, long timeout) {
       
   233         try {
       
   234             return waitForConditionEx(condition, timeout);
       
   235         } catch (InterruptedException e) {
       
   236             throw new RuntimeException("Error: unexpected exception caught!", e);
       
   237         }
       
   238     }
       
   239 
       
   240     /*
       
   241      * The same as {@code waitForConditionEx(AtomicBoolean, long)} but without a timeout.
       
   242      */
       
   243     public static void waitForConditionEx(final AtomicBoolean condition)
       
   244       throws InterruptedException
       
   245         {
       
   246             synchronized (condition) {
       
   247                 while (!condition.get()) {
       
   248                     condition.wait();
       
   249                 }
       
   250             }
       
   251         }
       
   252 
       
   253     /*
       
   254      * The same as {@code waitForConditionEx(AtomicBoolean)} except that it
       
   255      * doesn't throw InterruptedException.
       
   256      */
       
   257     public static void waitForCondition(final AtomicBoolean condition) {
       
   258         try {
       
   259             waitForConditionEx(condition);
       
   260         } catch (InterruptedException e) {
       
   261             throw new RuntimeException("Error: unexpected exception caught!", e);
       
   262         }
       
   263     }
       
   264 
       
   265     public static void waitTillShownEx(final Component comp) throws InterruptedException {
       
   266         while (true) {
       
   267             try {
       
   268                 Thread.sleep(100);
       
   269                 comp.getLocationOnScreen();
       
   270                 break;
       
   271             } catch (IllegalComponentStateException e) {}
       
   272         }
       
   273     }
       
   274     public static void waitTillShown(final Component comp) {
       
   275         try {
       
   276             waitTillShownEx(comp);
       
   277         } catch (InterruptedException e) {
       
   278             throw new RuntimeException("Error: unexpected exception caught!", e);
       
   279         }
       
   280     }
       
   281 
       
   282     /**
       
   283      * Drags from one point to another with the specified mouse button pressed.
       
   284      *
       
   285      * @param robot a robot to use for moving the mouse, etc.
       
   286      * @param startPoint a start point of the drag
       
   287      * @param endPoint an end point of the drag
       
   288      * @param button one of {@code InputEvent.BUTTON1_MASK},
       
   289      *     {@code InputEvent.BUTTON2_MASK}, {@code InputEvent.BUTTON3_MASK}
       
   290      *
       
   291      * @throws IllegalArgumentException if {@code button} is not one of
       
   292      *     {@code InputEvent.BUTTON1_MASK}, {@code InputEvent.BUTTON2_MASK},
       
   293      *     {@code InputEvent.BUTTON3_MASK}
       
   294      */
       
   295     public static void drag(Robot robot, Point startPoint, Point endPoint, int button) {
       
   296         if (!(button == InputEvent.BUTTON1_MASK || button == InputEvent.BUTTON2_MASK
       
   297                 || button == InputEvent.BUTTON3_MASK))
       
   298         {
       
   299             throw new IllegalArgumentException("invalid mouse button");
       
   300         }
       
   301 
       
   302         robot.mouseMove(startPoint.x, startPoint.y);
       
   303         robot.mousePress(button);
       
   304         try {
       
   305             mouseMove(robot, startPoint, endPoint);
       
   306         } finally {
       
   307             robot.mouseRelease(button);
       
   308         }
       
   309     }
       
   310 
       
   311     /**
       
   312      * Moves the mouse pointer from one point to another.
       
   313      * Uses Bresenham's algorithm.
       
   314      *
       
   315      * @param robot a robot to use for moving the mouse
       
   316      * @param startPoint a start point of the drag
       
   317      * @param endPoint an end point of the drag
       
   318      */
       
   319     public static void mouseMove(Robot robot, Point startPoint, Point endPoint) {
       
   320         int dx = endPoint.x - startPoint.x;
       
   321         int dy = endPoint.y - startPoint.y;
       
   322 
       
   323         int ax = Math.abs(dx) * 2;
       
   324         int ay = Math.abs(dy) * 2;
       
   325 
       
   326         int sx = signWOZero(dx);
       
   327         int sy = signWOZero(dy);
       
   328 
       
   329         int x = startPoint.x;
       
   330         int y = startPoint.y;
       
   331 
       
   332         int d = 0;
       
   333 
       
   334         if (ax > ay) {
       
   335             d = ay - ax/2;
       
   336             while (true){
       
   337                 robot.mouseMove(x, y);
       
   338                 robot.delay(50);
       
   339 
       
   340                 if (x == endPoint.x){
       
   341                     return;
       
   342                 }
       
   343                 if (d >= 0){
       
   344                     y = y + sy;
       
   345                     d = d - ax;
       
   346                 }
       
   347                 x = x + sx;
       
   348                 d = d + ay;
       
   349             }
       
   350         } else {
       
   351             d = ax - ay/2;
       
   352             while (true){
       
   353                 robot.mouseMove(x, y);
       
   354                 robot.delay(50);
       
   355 
       
   356                 if (y == endPoint.y){
       
   357                     return;
       
   358                 }
       
   359                 if (d >= 0){
       
   360                     x = x + sx;
       
   361                     d = d - ay;
       
   362                 }
       
   363                 y = y + sy;
       
   364                 d = d + ax;
       
   365             }
       
   366         }
       
   367     }
       
   368 
       
   369     private static int signWOZero(int i){
       
   370         return (i > 0)? 1: -1;
       
   371     }
       
   372 
       
   373     private static int sign(int n) {
       
   374         return n < 0 ? -1 : n == 0 ? 0 : 1;
       
   375     }
       
   376 
       
   377     /** Returns {@code WindowListener} instance that diposes {@code Window} on
       
   378      *  "window closing" event.
       
   379      *
       
   380      * @return    the {@code WindowListener} instance that could be set
       
   381      *            on a {@code Window}. After that
       
   382      *            the {@code Window} is disposed when "window closed"
       
   383      *            event is sent to the {@code Window}
       
   384      */
       
   385     public static WindowListener getClosingWindowAdapter() {
       
   386         return new WindowAdapter () {
       
   387             public void windowClosing(WindowEvent e) {
       
   388                 e.getWindow().dispose();
       
   389             }
       
   390         };
       
   391     }
       
   392 
       
   393     /*
       
   394      * The values directly map to the ones of
       
   395      * sun.awt.X11.XWM & sun.awt.motif.MToolkit classes.
       
   396      */
       
   397     public final static int
       
   398         UNDETERMINED_WM = 1,
       
   399         NO_WM = 2,
       
   400         OTHER_WM = 3,
       
   401         OPENLOOK_WM = 4,
       
   402         MOTIF_WM = 5,
       
   403         CDE_WM = 6,
       
   404         ENLIGHTEN_WM = 7,
       
   405         KDE2_WM = 8,
       
   406         SAWFISH_WM = 9,
       
   407         ICE_WM = 10,
       
   408         METACITY_WM = 11,
       
   409         COMPIZ_WM = 12,
       
   410         LG3D_WM = 13;
       
   411 
       
   412     /*
       
   413      * Returns -1 in case of not X Window or any problems.
       
   414      */
       
   415     public static int getWMID() {
       
   416         Class clazz = null;
       
   417         try {
       
   418             if ("sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
       
   419                 clazz = Class.forName("sun.awt.X11.XWM");
       
   420             } else if ("sun.awt.motif.MToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName())) {
       
   421                 clazz = Class.forName("sun.awt.motif.MToolkit");
       
   422             }
       
   423         } catch (ClassNotFoundException cnfe) {
       
   424             cnfe.printStackTrace();
       
   425         }
       
   426         if (clazz == null) {
       
   427             return -1;
       
   428         }
       
   429 
       
   430         try {
       
   431             final Class _clazz = clazz;
       
   432             Method m_getWMID = (Method)AccessController.doPrivileged(new PrivilegedAction() {
       
   433                     public Object run() {
       
   434                         try {
       
   435                             Method method = _clazz.getDeclaredMethod("getWMID", new Class[] {});
       
   436                             if (method != null) {
       
   437                                 method.setAccessible(true);
       
   438                             }
       
   439                             return method;
       
   440                         } catch (NoSuchMethodException e) {
       
   441                             assert false;
       
   442                         } catch (SecurityException e) {
       
   443                             assert false;
       
   444                         }
       
   445                         return null;
       
   446                     }
       
   447                 });
       
   448             return ((Integer)m_getWMID.invoke(null, new Object[] {})).intValue();
       
   449         } catch (IllegalAccessException iae) {
       
   450             iae.printStackTrace();
       
   451         } catch (InvocationTargetException ite) {
       
   452             ite.printStackTrace();
       
   453         }
       
   454         return -1;
       
   455     }
       
   456 
       
   457 
       
   458     ////////////////////////////
       
   459     // Some stuff to test focus.
       
   460     ////////////////////////////
       
   461 
       
   462     private static WindowGainedFocusListener wgfListener = new WindowGainedFocusListener();
       
   463     private static FocusGainedListener fgListener = new FocusGainedListener();
       
   464     private static ActionPerformedListener apListener = new ActionPerformedListener();
       
   465 
       
   466     private abstract static class EventListener {
       
   467         AtomicBoolean notifier = new AtomicBoolean(false);
       
   468         Component comp;
       
   469         boolean printEvent;
       
   470 
       
   471         public void listen(Component comp, boolean printEvent) {
       
   472             this.comp = comp;
       
   473             this.printEvent = printEvent;
       
   474             notifier.set(false);
       
   475             setListener(comp);
       
   476         }
       
   477 
       
   478         public AtomicBoolean getNotifier() {
       
   479             return notifier;
       
   480         }
       
   481 
       
   482         abstract void setListener(Component comp);
       
   483 
       
   484         void printAndNotify(AWTEvent e) {
       
   485             if (printEvent) {
       
   486                 System.err.println(e);
       
   487             }
       
   488             synchronized (notifier) {
       
   489                 notifier.set(true);
       
   490                 notifier.notifyAll();
       
   491             }
       
   492         }
       
   493     }
       
   494 
       
   495     private static class WindowGainedFocusListener extends EventListener implements WindowFocusListener {
       
   496 
       
   497         void setListener(Component comp) {
       
   498             ((Window)comp).addWindowFocusListener(this);
       
   499         }
       
   500 
       
   501         public void windowGainedFocus(WindowEvent e) {
       
   502 
       
   503             ((Window)comp).removeWindowFocusListener(this);
       
   504             printAndNotify(e);
       
   505         }
       
   506 
       
   507         public void windowLostFocus(WindowEvent e) {}
       
   508     }
       
   509 
       
   510     private static class FocusGainedListener extends EventListener implements FocusListener {
       
   511 
       
   512         void setListener(Component comp) {
       
   513             comp.addFocusListener(this);
       
   514         }
       
   515 
       
   516         public void focusGained(FocusEvent e) {
       
   517             comp.removeFocusListener(this);
       
   518             printAndNotify(e);
       
   519         }
       
   520 
       
   521         public void focusLost(FocusEvent e) {}
       
   522     }
       
   523 
       
   524     private static class ActionPerformedListener extends EventListener implements ActionListener {
       
   525 
       
   526         void setListener(Component comp) {
       
   527             ((Button)comp).addActionListener(this);
       
   528         }
       
   529 
       
   530         public void actionPerformed(ActionEvent e) {
       
   531             ((Button)comp).removeActionListener(this);
       
   532             printAndNotify(e);
       
   533         }
       
   534     }
       
   535 
       
   536     private static boolean trackEvent(int eventID, Component comp, Runnable action, int time, boolean printEvent) {
       
   537         EventListener listener = null;
       
   538 
       
   539         switch (eventID) {
       
   540         case WindowEvent.WINDOW_GAINED_FOCUS:
       
   541             listener = wgfListener;
       
   542             break;
       
   543         case FocusEvent.FOCUS_GAINED:
       
   544             listener = fgListener;
       
   545             break;
       
   546         case ActionEvent.ACTION_PERFORMED:
       
   547             listener = apListener;
       
   548             break;
       
   549         }
       
   550 
       
   551         listener.listen(comp, printEvent);
       
   552         action.run();
       
   553         return Util.waitForCondition(listener.getNotifier(), time);
       
   554     }
       
   555 
       
   556     /*
       
   557      * Tracks WINDOW_GAINED_FOCUS event for a window caused by an action.
       
   558      * @param window the window to track the event for
       
   559      * @param action the action to perform
       
   560      * @param time the max time to wait for the event
       
   561      * @param printEvent should the event received be printed or doesn't
       
   562      * @return true if the event has been received, otherwise false
       
   563      */
       
   564     public static boolean trackWindowGainedFocus(Window window, Runnable action, int time, boolean printEvent) {
       
   565         return trackEvent(WindowEvent.WINDOW_GAINED_FOCUS, window, action, time, printEvent);
       
   566     }
       
   567 
       
   568     /*
       
   569      * Tracks FOCUS_GAINED event for a component caused by an action.
       
   570      * @see #trackWindowGainedFocus
       
   571      */
       
   572     public static boolean trackFocusGained(Component comp, Runnable action, int time, boolean printEvent) {
       
   573         return trackEvent(FocusEvent.FOCUS_GAINED, comp, action, time, printEvent);
       
   574     }
       
   575 
       
   576     /*
       
   577      * Tracks ACTION_PERFORMED event for a button caused by an action.
       
   578      * @see #trackWindowGainedFocus
       
   579      */
       
   580     public static boolean trackActionPerformed(Button button, Runnable action, int time, boolean printEvent) {
       
   581         return trackEvent(ActionEvent.ACTION_PERFORMED, button, action, time, printEvent);
       
   582     }
       
   583 
       
   584     /*
       
   585      * Requests focus on the component provided and waits for the result.
       
   586      * @return true if the component has been focused, false otherwise.
       
   587      */
       
   588     public static boolean focusComponent(Component comp, int time) {
       
   589         return focusComponent(comp, time, false);
       
   590     }
       
   591     public static boolean focusComponent(final Component comp, int time, boolean printEvent) {
       
   592         return trackFocusGained(comp,
       
   593                                 new Runnable() {
       
   594                                     public void run() {
       
   595                                         comp.requestFocus();
       
   596                                     }
       
   597                                 },
       
   598                                 time, printEvent);
       
   599 
       
   600     }
       
   601 }