| /* |
| * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| import java.awt.*; |
| import java.awt.event.*; |
| import java.beans.*; |
| import java.lang.reflect.*; |
| import java.util.*; |
| |
| import javax.swing.*; |
| |
| /** |
| * SwingTestHelper is a utility class for writing AWT/Swing regression |
| * tests that require interacting with the UI. Typically such tests |
| * consist of executing a chunk of code, waiting on an event, executing |
| * more code ... This is painful in that you typically have to use various |
| * invokeLaters and threading to handle that interaction. SwingTestHelper |
| * strealines this process. |
| * <p> |
| * SwingTestHelper uses reflection to invoke all methods starting with |
| * the name <code>onEDT</code> on the EDT and all methods starting with |
| * <code>onBackgroundThread</code> on a background thread. Between each method |
| * invocation all pending events on the EDT are processed. The methods |
| * are first sorted based on an integer after the method names and invoked |
| * in that order. For example, the following subclass: |
| * <pre> |
| * class Test extends SwingTestHelper { |
| * private void onEDT10(); |
| * private void onBackgroundThread20(); |
| * private void onBackgroundThread30(); |
| * private void onEDT40(); |
| * private void onBackgroundThread50(); |
| * } |
| * </pre> |
| * Will have the methods invoked in the order <code>onEDT10</code>, |
| * <code>onBackgroundThread20</code>, <code>onBackgroundThread30</code>, |
| * <code>onEDT40</code>, <code>onBackgroundThread50</code>. |
| * <p> |
| * If you're not happy with method mangling you can also use annotations. |
| * The following gives the same result as the previous example: |
| * <pre> |
| * class Test extends SwingTestHelper { |
| * @Test(10) |
| * private void foo(); // Was onEDT10 |
| * |
| * @Test(value=20, onEDT=false) |
| * private void bar(); // Was onBackgroundThread20 |
| * |
| * @Test(value=30, onEDT=false) |
| * private void baz(); // Was onBackgroundThread30 |
| * |
| * @Test(40) |
| * private void zed(); // Was onEDT40 |
| * |
| * @Test(value=50, onEDT=false) |
| * private void onBackgroundThread50(); // Was onBackgroundThread50 |
| * } |
| * </pre> |
| * <p> |
| * It is recommended that you increment the value in increments of |
| * 10. This makes it easier to add methods at a later date without |
| * having to change all method names/annotations after the newly added |
| * method. |
| * <p> |
| * Between each of the methods, all pending events (native and Java) |
| * are processed. |
| * <p> |
| * Failure of the test is signaled by any method throwing |
| * an exception, directly invoking <code>fail</code> or one of the |
| * <code>assert</code> variants. If no methods throw an exception the test is |
| * assumed to have passed. |
| * <p> |
| * Often times it is necessary to block until focus has been gained on a |
| * particular widget. This can be handled by the |
| * <code>requestAndWaitForFocus</code> method. It will invoke |
| * <code>requestFocus</code> and block the test (not the EDT) until focus |
| * has been granted to the widget. |
| * <p> |
| * Care must be taken when using <code>Robot</code> directly. For |
| * example, it's tempting to flood <code>Robot</code> with events and |
| * assume they will be received after some delay. Depending upon the |
| * machine you may need to increase the delay. Instead it's |
| * preferrable to block test execution until the event has been |
| * received and processed. This can be done using the method |
| * <code>waitForEvent</code>. For example, to block until a key typed |
| * event has been processed do the following: |
| * <pre> |
| * private void onEDT() { |
| * robot.moveMouseTo(myComponent); |
| * robot.mousePress(xxx); |
| * robot.mouseRelease(xxx); |
| * waitForEvent(myComponent, MouseEvent.MOUSE_RELEASED); |
| * } |
| * </pre> |
| * <p> |
| * Waiting for focus and events are specific examples of a more |
| * general problem. Often times you need the EDT to continue processing |
| * events, but want to block test execution until something happens. |
| * In the case of focus you want to block test execution until focus |
| * is gained. The method <code>waitForCondition</code> can be used to |
| * block test execution until the supplied <code>Runnable</code> returns. The |
| * <code>Runnable</code> is invoked on the background thread. |
| * <p> |
| * To use this class you will need to do the following: |
| * <ol> |
| * <li>Override the method <code>createContentPane</code>. All of your logic |
| * for setting up the test environment should go here. This method is |
| * invoked on the EDT. |
| * <li>Implement the necessary <code>onEDTXX</code> and |
| * <code>onBackgroundThreadXXX</code> methods to do the actual testing. |
| * <li>Make your <code>main</code> method look like: |
| * <code>new MySwingTestHelper().run(args)</code>. This will block |
| * until the test fails or succeeds. |
| * <li>To use this with jtreg you'll need to have something like: |
| * <pre> |
| * @library ../../../regtesthelpers |
| * @build Test JRobot Assert SwingTestHelper |
| * @run main MySwingTestHelper |
| * * </pre> |
| * </ol> |
| * <p> |
| * Here's a complete example: |
| * <pre> |
| * public class bug4852305 extends SwingTestHelper { |
| * private JTable table; |
| * |
| * public static void main(String[] args) throws Throwable { |
| * new bug4852305().run(args); |
| * } |
| * |
| * protected Component createContentPane() { |
| * DefaultTableModel model = new DefaultTableModel(1, 2); |
| * model.setValueAt("x", 0, 0); |
| * model.setValueAt("z", 0, 1); |
| * table = new JTable(model); |
| * table.setDefaultEditor(Object.class, new DefaultCellEditor(new JTextField()) { |
| * public boolean isCellEditable(EventObject anEvent) { |
| * if ((anEvent instanceof KeyEvent) || |
| * (anEvent instanceof ActionEvent)) { |
| * return false; |
| * } |
| * return true; |
| * } |
| * }); |
| * return new JScrollPane(table); |
| * } |
| * |
| * private void onEDT10() { |
| * requestAndWaitForFocus(table); |
| * } |
| * |
| * private void onEDT20() { |
| * robot.keyPress(KeyEvent.VK_A); |
| * robot.keyRelease(KeyEvent.VK_A); |
| * waitForEvent(table, KeyEvent.KEY_RELEASED); |
| * } |
| * |
| * private void onEDT30() { |
| * if (table.isEditing()) { |
| * fail("Should not be editing"); |
| * } |
| * } |
| * } |
| * </pre> |
| * |
| * |
| * @author Scott Violet |
| */ |
| public abstract class SwingTestHelper { |
| private static final String ON_EDT_METHOD_NAME = "onEDT"; |
| private static final String IN_BACKGROUND_METHOD_NAME = "onBackgroundThread"; |
| |
| // Whether or not we've installed a PropertyChangeListener on the |
| // KeyboardFocusManager |
| private boolean installedFocusListener; |
| // Component currently blocking on until focus has been received. |
| private Component componentWaitingForFocus; |
| |
| // Set to true when done. |
| private boolean done; |
| // If failed, this gives the exception. Only the first exception is |
| // kept. |
| private Throwable error; |
| |
| // List of methods to invoke |
| private java.util.List<Method> methods; |
| |
| // The conditions the background thread is blocked on. |
| private java.util.List<Runnable> conditions; |
| |
| // Whether or not we've installed the AWTEventListener |
| private boolean installedEventListener; |
| |
| /** |
| * Instance of <code>Robot</code> returned from <code>createRobot</code>. |
| */ |
| protected JRobot robot; |
| |
| /** |
| * <code>Window</code> returned from <code>createWindow</code>. |
| */ |
| protected Window window; |
| |
| // Listens for the first paint event |
| private AWTEventListener paintListener; |
| // Whether or not we've received a paint event. |
| private boolean receivedFirstPaint; |
| |
| // used if the user wants to slow down method processing |
| private PauseCondition delay = null; |
| |
| private boolean showProgress; |
| private JProgressBar progBar; |
| |
| |
| public SwingTestHelper() { |
| paintListener = new AWTEventListener() { |
| public void eventDispatched(AWTEvent ev) { |
| if ((ev.getID() & PaintEvent.PAINT) != 0 && |
| ev.getSource() == window) { |
| synchronized(SwingTestHelper.this) { |
| if (receivedFirstPaint) { |
| return; |
| } |
| receivedFirstPaint = true; |
| } |
| Toolkit.getDefaultToolkit().removeAWTEventListener( |
| paintListener); |
| startControlLoop(); |
| } |
| } |
| }; |
| Toolkit.getDefaultToolkit().addAWTEventListener( |
| paintListener, AWTEvent.PAINT_EVENT_MASK); |
| } |
| |
| /** |
| * Sets whether SwingTestHelper should use {@code SunToolkit.realSync} |
| * to wait for events to finish, or {@code Robot.waitForIdle}. The default |
| * is to use realSync. |
| * Nov 2014: no realSync any more, just robot.waitForIdle which actually |
| * _is_ realSync on all platforms but OS X (and thus cannot be used on EDT). |
| */ |
| public void setUseRealSync(boolean useRealSync) { |
| //NOOP |
| } |
| |
| /** |
| * Set the amount of time to delay between invoking methods in |
| * the control loop. Useful to slow down testing. |
| */ |
| protected void setDelay(int delay) { |
| if (delay <= 0) { |
| this.delay = null; |
| } else { |
| this.delay = new PauseCondition(delay); |
| } |
| } |
| |
| /** |
| * Sets whether or not progress through the list of methods is |
| * shown by a progress bar at the bottom of the window created |
| * by {@code createWindow}. |
| */ |
| protected void setShowProgress(boolean showProgress) { |
| this.showProgress = showProgress; |
| } |
| |
| /** |
| * Creates and returns the <code>Window</code> for the test. This |
| * implementation returns a JFrame with a default close operation |
| * of <code>EXIT_ON_CLOSE</code>. The <code>Component</code> |
| * returned from <code>createContentPane</code> is added the |
| * <code>JFrame</code> and the the frame is packed. |
| * <p> |
| * Typically you only need override <code>createContentPane</code>. |
| */ |
| protected Window createWindow() { |
| JFrame frame = new JFrame("Test: " + getClass().getName()); |
| frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
| frame.add(createContentPane()); |
| if (showProgress) { |
| progBar = new JProgressBar(); |
| progBar.setString(""); |
| progBar.setStringPainted(true); |
| frame.add(progBar, BorderLayout.SOUTH); |
| } |
| frame.pack(); |
| return frame; |
| } |
| |
| /** |
| * Returns the <code>Component</code> to place in the frame. |
| * Override this or the <code>createWindow</code> method. |
| */ |
| protected Component createContentPane() { |
| return null; |
| } |
| |
| /** |
| * Invokes <code>requestFocus</code> on the passed in component (assuming |
| * it doesn't already have focus). Test execution is blocked until focus |
| * has been gained on the component. This method <b>must</b> be invoked |
| * on the EDT, if you do not invoke it from the edt the test will fail. |
| * |
| * @param c the <code>Component</code> to wait for focus on |
| */ |
| protected void requestAndWaitForFocus(Component c) { |
| requestAndWaitForFocus(c, true); |
| } |
| |
| /** |
| * Blocks test execution until focus is gained on the component. |
| * This method <b>must</b> be invoked |
| * on the EDT, if you do not invoke it from the edt the test will fail. |
| */ |
| protected void waitForFocusGained(Component c) { |
| requestAndWaitForFocus(c, false); |
| } |
| |
| private void requestAndWaitForFocus(Component c, boolean requestFocus) { |
| if (!EventQueue.isDispatchThread()) { |
| System.out.println( |
| "requestAndWaitForFocus should be invoked on EDT"); |
| throw new RuntimeException(); |
| } |
| if (componentWaitingForFocus != null) { |
| System.out.println("Already waiting for focus"); |
| throw new RuntimeException(); |
| } |
| if (!installedFocusListener) { |
| installedFocusListener = true; |
| KeyboardFocusManager.getCurrentKeyboardFocusManager(). |
| addPropertyChangeListener(new FocusListener()); |
| } |
| synchronized(this) { |
| if (c.hasFocus()) { |
| return; |
| } |
| componentWaitingForFocus = c; |
| } |
| if (requestFocus) { |
| c.requestFocus(); |
| } |
| waitForCondition(new FocusCondition()); |
| } |
| |
| /** |
| * Blocks test execution until the specified event has been received. |
| * This method immediately returns and the EDT will continue to |
| * process events, but test execution is blocked until |
| * the event is received. |
| * |
| * @param event the event type to wait for |
| */ |
| protected void waitForEvent(int event) { |
| waitForEvent(null, event); |
| } |
| |
| /** |
| * Blocks test execution until the specified event has been received. |
| * This method immediately returns and the EDT will continue to |
| * process events, but test execution is blocked until |
| * the event is received. |
| * |
| * @param target the <code>Component</code> to wait for the event on; |
| * <code>null</code> indicates it does not matter which |
| * component the event is received on |
| * @param event the event type to wait for |
| */ |
| protected void waitForEvent(Component target, int event) { |
| waitForCondition(new EventCondition(target, event)); |
| if (!installedEventListener) { |
| installedEventListener = true; |
| Toolkit.getDefaultToolkit().addAWTEventListener( |
| new EventListener(), 0xFFFFFFFFFFFFFFFFl); |
| } |
| } |
| |
| /** |
| * Paused test execution for the specified amount of time. The caller |
| * immediately returns and the EDT can process events. |
| * |
| * @param time the amount of time, in milliseconds, to pause for |
| */ |
| protected void pause(int time) { |
| waitForCondition(new PauseCondition(time)); |
| } |
| |
| /** |
| * Schedules a <code>Runnable</code> that will be processed in the |
| * background thread. This method immediately returns, and the |
| * EDT is free to continue processing events. Test execution is |
| * blocked until the <code>Runnable</code> completes. |
| */ |
| protected void waitForCondition(Runnable runnable) { |
| synchronized(this) { |
| if (conditions == null) { |
| conditions = new LinkedList<Runnable>(); |
| } |
| conditions.add(runnable); |
| } |
| } |
| |
| /** |
| * Runs the test. This method blocks the caller until the test |
| * fails or succeeds. Recognized arguments are: |
| * <p> |
| * "-exit": Causes main to exit when the test is done. |
| * "-showProg": Indicate the progress of the test with a |
| * progress bar in the main window. Only works |
| * if the test hasn't overridden {@code createWindow}. |
| * "-delay int": Sets the delay between executing methods. |
| * Useful when you want to slow a test to watch it. |
| * |
| * @param args the arguments from main, it's ok to pass in null |
| */ |
| protected final void run(String[] args) throws Throwable { |
| boolean exit = false; |
| if (args != null) { |
| for (int i = 0; i < args.length; i++) { |
| if (args[i].equals("-exit")) { |
| exit = true; |
| } else if (args[i].equals("-delay")) { |
| try { |
| setDelay(Integer.parseInt(args[++i])); |
| } catch (NumberFormatException ne) { |
| throw new RuntimeException("-delay requires an integer value"); |
| } catch (ArrayIndexOutOfBoundsException ae) { |
| throw new RuntimeException("-delay requires an integer value"); |
| } |
| } else if (args[i].equals("-showProg")) { |
| setShowProgress(true); |
| } else { |
| throw new RuntimeException("Invalid argument \"" + args[i] + "\""); |
| } |
| } |
| } |
| |
| createWindow0(); |
| synchronized(this) { |
| while(!done) { |
| wait(); |
| } |
| } |
| if (exit) { |
| // Not in harness |
| if (error != null) { |
| System.out.println("FAILED: " + error); |
| error.printStackTrace(); |
| } |
| System.exit(0); |
| } |
| if (error != null) { |
| throw error; |
| } |
| } |
| |
| /** |
| * Creates the window, on the EDT. |
| */ |
| private void createWindow0() { |
| EventQueue.invokeLater(new Runnable() { |
| public void run() { |
| window = createWindow(); |
| window.show(); |
| } |
| }); |
| } |
| |
| /** |
| * Initializes the progress bar if necessary. |
| */ |
| private void initProgressBar(final int size) { |
| EventQueue.invokeLater(new Runnable() { |
| public void run() { |
| if (progBar != null) { |
| progBar.setMaximum(size); |
| } |
| } |
| }); |
| } |
| |
| /** |
| * Starst the control loop. |
| */ |
| private void startControlLoop() { |
| robot = createRobot(); |
| if (robot != null) { |
| calculateMethods(); |
| initProgressBar(methods.size()); |
| new Thread(new Runnable() { |
| public void run() { |
| controlLoop(); |
| } |
| }).start(); |
| } |
| } |
| |
| /** |
| * Increment the progress bar. |
| */ |
| private void nextProgress(final String name) { |
| EventQueue.invokeLater(new Runnable() { |
| public void run() { |
| if (progBar != null) { |
| progBar.setString(name); |
| progBar.setValue(progBar.getValue() + 1); |
| } |
| } |
| }); |
| } |
| |
| private synchronized Runnable currentCondition() { |
| if (conditions != null && conditions.size() > 0) { |
| return conditions.get(0); |
| } |
| return null; |
| } |
| |
| private synchronized Runnable nextCondition() { |
| return conditions.remove(0); |
| } |
| |
| private void controlLoop() { |
| int methodIndex = 0; |
| while (methodIndex < methods.size()) { |
| // Wait for any pending conditions |
| Runnable condition; |
| while ((condition = currentCondition()) != null) { |
| try { |
| condition.run(); |
| } catch (Exception e) { |
| fail(e); |
| return; |
| } |
| waitForEDTToFinish(); |
| synchronized(this) { |
| if (done) { |
| return; |
| } |
| } |
| // Advance to next condition |
| nextCondition(); |
| } |
| |
| // Let all events on the EDT finish |
| waitForEDTToFinish(); |
| |
| if (delay != null) { |
| delay.run(); |
| } |
| |
| // Invoke the next method |
| Method method = methods.get(methodIndex++); |
| Test test = method.getAnnotation(Test.class); |
| boolean onEDT = true; |
| if (test != null) { |
| onEDT = test.onEDT(); |
| } |
| else if (!method.getName().startsWith(ON_EDT_METHOD_NAME)) { |
| onEDT = false; |
| } |
| if (onEDT) { |
| invokeOnEDT(method); |
| } |
| else { |
| invoke(method); |
| } |
| |
| // Let all events on the EDT finish |
| waitForEDTToFinish(); |
| |
| nextProgress(method.getName()); |
| |
| // If done, stop. |
| synchronized(this) { |
| if (done) { |
| return; |
| } |
| } |
| } |
| |
| // No more methods, if we get and done isn't true, set it true |
| // so that the main thread wakes up. |
| synchronized(this) { |
| if (!done) { |
| done = true; |
| notifyAll(); |
| } |
| } |
| } |
| |
| private void waitForEDTToFinish() { |
| robot.waitForIdle(); |
| } |
| |
| private void invokeOnEDT(final Method method) { |
| try { |
| EventQueue.invokeAndWait(new Runnable() { |
| public void run() { |
| invoke(method); |
| } |
| }); |
| } catch (InvocationTargetException ite) { |
| fail(ite); |
| } catch (InterruptedException ie) { |
| fail(ie); |
| } |
| } |
| |
| private void invoke(Method method) { |
| System.out.println("invoking: " + method.getName()); |
| try { |
| if (Modifier.isPrivate(method.getModifiers())) { |
| method.setAccessible(true); |
| } |
| method.invoke(this); |
| } catch (Exception e) { |
| fail(e); |
| } |
| } |
| |
| // Determines the methods to execute. |
| private void calculateMethods() { |
| // Using a Set avoids duplicating methods returned by both |
| // getMethods() and getDeclaredMethods(). |
| HashSet<Method> allMethods = new HashSet<Method>(); |
| allMethods.addAll(Arrays.asList(getClass().getMethods())); |
| allMethods.addAll(Arrays.asList(getClass().getDeclaredMethods())); |
| |
| methods = new ArrayList<Method>(); |
| for (Method method : allMethods) { |
| Test test = method.getAnnotation(Test.class); |
| if (test != null) { |
| methods.add(method); |
| } |
| else if (method.getName().startsWith(ON_EDT_METHOD_NAME)) { |
| methods.add(method); |
| } |
| else if (method.getName().startsWith(IN_BACKGROUND_METHOD_NAME)) { |
| methods.add(method); |
| } |
| } |
| Comparator<Method> comparator = new Comparator<Method>() { |
| public int compare(Method m1, Method m2) { |
| int index1 = getIndex(m1); |
| int index2 = getIndex(m2); |
| return index1 - index2; |
| } |
| private int getIndex(Method m) { |
| String name = m.getName(); |
| String indexAsString; |
| Test test = m.getAnnotation(Test.class); |
| if (test != null) { |
| return test.value(); |
| } |
| if (name.startsWith(ON_EDT_METHOD_NAME)) { |
| indexAsString = name.substring( |
| ON_EDT_METHOD_NAME.length()); |
| } |
| else { |
| indexAsString = name.substring( |
| IN_BACKGROUND_METHOD_NAME.length()); |
| } |
| if (indexAsString.length() == 0) { |
| System.out.println( |
| "onEDT and onBackgroundThread must be " + |
| "followed by an integer specifying " + |
| "order."); |
| System.exit(0); |
| } |
| return Integer.parseInt(indexAsString); |
| } |
| }; |
| Collections.sort(methods, comparator); |
| } |
| |
| /** |
| * Invoke if the test should be considered to have failed. This will |
| * stop test execution. |
| */ |
| public void fail(String reason) { |
| fail(new RuntimeException(reason)); |
| } |
| |
| /** |
| * Invoke if the test should be considered to have failed. This will |
| * stop test execution. |
| */ |
| public void fail(Throwable error) { |
| synchronized(this) { |
| if (this.error == null) { |
| if (error instanceof InvocationTargetException) { |
| this.error = ((InvocationTargetException)error). |
| getCause(); |
| } |
| else { |
| this.error = error; |
| } |
| this.done = true; |
| notifyAll(); |
| } |
| } |
| } |
| |
| /** |
| * Invoke to prematurely stop test execution while there are remaining |
| * methods. You typically don't invoke this, instead if all methods have |
| * been executed and fail hasn't been invoked, the test is considered to |
| * have passed. |
| */ |
| public void succeeded() { |
| synchronized(this) { |
| this.done = true; |
| notifyAll(); |
| } |
| } |
| |
| /** |
| * Creates and returns the Robot that will be used. You generally don't |
| * need to override this. |
| */ |
| protected JRobot createRobot() { |
| JRobot robot = JRobot.getRobot(false); |
| return robot; |
| } |
| |
| |
| private class FocusListener implements PropertyChangeListener { |
| public void propertyChange(PropertyChangeEvent e) { |
| if (componentWaitingForFocus != null && |
| "focusOwner".equals(e.getPropertyName()) && |
| componentWaitingForFocus == e.getNewValue()) { |
| synchronized(SwingTestHelper.this) { |
| componentWaitingForFocus = null; |
| SwingTestHelper.this.notifyAll(); |
| } |
| } |
| } |
| } |
| |
| |
| private class EventCondition implements Runnable { |
| private Component component; |
| private int eventID; |
| private boolean received; |
| |
| EventCondition(Component component, int eventID) { |
| this.component = component; |
| this.eventID = eventID; |
| } |
| |
| public int getEventID() { |
| return eventID; |
| } |
| |
| public Component getComponent() { |
| return component; |
| } |
| |
| public void received() { |
| synchronized(SwingTestHelper.this) { |
| this.received = true; |
| SwingTestHelper.this.notifyAll(); |
| } |
| } |
| |
| public boolean isWaiting() { |
| return !received; |
| } |
| |
| public void run() { |
| synchronized(SwingTestHelper.this) { |
| while (!received) { |
| try { |
| SwingTestHelper.this.wait(); |
| } catch (InterruptedException ie) { |
| fail(ie); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| private class FocusCondition implements Runnable { |
| public void run() { |
| synchronized(SwingTestHelper.this) { |
| while (componentWaitingForFocus != null) { |
| try { |
| SwingTestHelper.this.wait(); |
| } catch (InterruptedException ie) { |
| fail(ie); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| private class PauseCondition implements Runnable { |
| private int time; |
| PauseCondition(int time) { |
| this.time = time; |
| } |
| public void run() { |
| try { |
| Thread.sleep(time); |
| } catch (InterruptedException ie) { |
| fail(ie); |
| } |
| } |
| } |
| |
| |
| private class EventListener implements AWTEventListener { |
| public void eventDispatched(AWTEvent ev) { |
| int eventID = ev.getID(); |
| synchronized (SwingTestHelper.this) { |
| for (Runnable condition : conditions) { |
| if (condition instanceof EventCondition) { |
| EventCondition ec = (EventCondition)condition; |
| if (ec.isWaiting()) { |
| if (eventID == ec.getEventID() && |
| (ec.getComponent() == null || |
| ev.getSource() == ec.getComponent())) { |
| ec.received(); |
| } |
| return; |
| } |
| } |
| else { |
| return; |
| } |
| } |
| } |
| } |
| } |
| } |