OverlappingTestBase.java revision 9971:b3bd0f3320b6
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
24import java.awt.*;
25import java.awt.event.*;
26import java.awt.peer.ComponentPeer;
27import java.lang.reflect.Constructor;
28import java.lang.reflect.InvocationTargetException;
29import java.lang.reflect.Method;
30import java.util.ArrayList;
31import javax.swing.*;
32import sun.awt.*;
33import java.io.*;
34
35/**
36 * <p>This class provides basis for AWT Mixing testing.
37 * <p>It provides all standard test machinery and should be used by
38 * extending and overriding next methods:
39 * <li> {@link OverlappingTestBase#prepareControls()} - setup UI components
40 * <li> {@link OverlappingTestBase#performTest()} -  run particular test
41 * Those methods would be run in the loop for each AWT component.
42 * <p>Current AWT component should be added to the tested UI by {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) ()}.
43 * There AWT components are prepared to be tested as being overlayed by other (e.g. Swing) components - they are colored to
44 * {@link OverlappingTestBase#AWT_BACKGROUND_COLOR} and throws failure on catching mouse event.
45 * <p> Validation of component being overlayed should be tested by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
46 * See each method javadoc for more details.
47 *
48 * <p>Due to test machinery limitations all test should be run from their own main() by calling next coe
49 * <code>
50 *     public static void main(String args[]) throws InterruptedException {
51 *        instance = new YourTestInstance();
52 *        OverlappingTestBase.doMain(args);
53 *     }
54 * </code>
55 *
56 * @author Sergey Grinev
57 */
58public abstract class OverlappingTestBase {
59    // working variables
60    private static volatile boolean wasHWClicked = false;
61    private static volatile boolean passed = true;
62    // constants
63    /**
64     * Default color for AWT component used for validate correct drawing of overlapping. <b>Never</b> use it for lightweight components.
65     */
66    protected static final Color AWT_BACKGROUND_COLOR = new Color(21, 244, 54);
67    protected static Color AWT_VERIFY_COLOR = AWT_BACKGROUND_COLOR;
68    protected static final int ROBOT_DELAY = 500;
69    private static final String[] simpleAwtControls = {"Button", "Checkbox", "Label", "TextArea"};
70    /**
71     * Generic strings array. To be used for population of List based controls.
72     */
73    protected static final String[] petStrings = {"Bird", "Cat", "Dog", "Rabbit", "Rhynocephalia Granda", "Bear", "Tiger", "Mustang"};
74    // "properties"
75    /**
76     * Tests customization. Set this variable to test only control from java.awt
77     * <p>Usage of this variable should be marked with CR being the reason.
78     * <p>Do not use this variable simultaneously with {@link OverlappingTestBase#skipClassNames}
79     */
80    protected String onlyClassName = null;
81    /**
82     * For customizing tests. List classes' simple names to skip them from testings.
83     * <p>Usage of this variable should be marked with CR being the reason.
84     */
85    protected String[] skipClassNames = null;
86    /**
87     * Set to false to avoid event delivery validation
88     * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
89     */
90    protected boolean useClickValidation = true;
91    /**
92     * Set to false if test doesn't supposed to verify EmbeddedFrame
93     */
94    protected boolean testEmbeddedFrame = false;
95    /**
96     * Set this variable to true if testing embedded frame is impossible (on Mac, for instance, for now).
97     * The testEmbeddedFrame is explicitly set to true in dozen places.
98     */
99    protected boolean skipTestingEmbeddedFrame = false;
100
101    public static final boolean isMac = System.getProperty("os.name").toLowerCase().contains("os x");
102    private boolean isFrameBorderCalculated;
103    private int borderShift;
104
105    {    if (Toolkit.getDefaultToolkit().getClass().getName().matches(".*L.*Toolkit")) {
106             // No EmbeddedFrame in LWToolkit/LWCToolkit, yet
107             // And it should be programmed some other way, too, in any case
108             System.err.println("skipTestingEmbeddedFrame");
109             skipTestingEmbeddedFrame = true;
110         }else {
111             System.err.println("do not skipTestingEmbeddedFrame");
112         }
113    }
114
115    protected int frameBorderCounter() {
116        if (!isFrameBorderCalculated) {
117            try {
118                new FrameBorderCounter(); // force compilation by jtreg
119                String JAVA_HOME = System.getProperty("java.home");
120                Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");
121                try {
122                    p.waitFor();
123                } catch (InterruptedException e) {
124                    e.printStackTrace();
125                    throw new RuntimeException(e);
126                }
127                if (p.exitValue() != 0) {
128                    throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));
129                }
130                borderShift = Integer.parseInt(readInputStream(p.getInputStream()).trim());
131                isFrameBorderCalculated = true;
132            } catch (IOException e) {
133                e.printStackTrace();
134                System.exit(1);
135            }
136        }
137        return borderShift;
138    }
139
140    public void getVerifyColor() {
141        try {
142            final int size = 200;
143            final SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
144            final Point[] p = new Point[1];
145            SwingUtilities.invokeAndWait(new Runnable() {
146                public void run(){
147                    JFrame frame = new JFrame("set back");
148                    frame.getContentPane().setBackground(AWT_BACKGROUND_COLOR);
149                    frame.setSize(size, size);
150                    frame.setUndecorated(true);
151                    frame.setVisible(true);
152                    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
153                    p[0] = frame.getLocation();
154                }
155            });
156            Robot robot = new Robot();
157            toolkit.realSync();
158            Thread.sleep(ROBOT_DELAY);
159            AWT_VERIFY_COLOR = robot.getPixelColor(p[0].x+size/2, p[0].y+size/2);
160            System.out.println("Color will be compared with " + AWT_VERIFY_COLOR + " instead of " + AWT_BACKGROUND_COLOR);
161        } catch (Exception e) {
162            System.err.println("Cannot get verify color: "+e.getMessage());
163        }
164    }
165
166    private String readInputStream(InputStream is) throws IOException {
167        byte[] buffer = new byte[4096];
168        int len = 0;
169        StringBuilder sb = new StringBuilder();
170        try (InputStreamReader isr = new InputStreamReader(is)) {
171            while ((len = is.read(buffer)) > 0) {
172                sb.append(new String(buffer, 0, len));
173            }
174        }
175        return sb.toString();
176    }
177
178    private void setupControl(final Component control) {
179        if (useClickValidation) {
180            control.addMouseListener(new MouseAdapter() {
181                @Override
182                public void mouseClicked(MouseEvent e) {
183                    System.err.println("ERROR: " + control.getClass() + " received mouse click.");
184                    wasHWClicked = true;
185                }
186            });
187        }
188        control.setBackground(AWT_BACKGROUND_COLOR);
189        control.setForeground(AWT_BACKGROUND_COLOR);
190        control.setPreferredSize(new Dimension(150, 150));
191        control.setFocusable(false);
192    }
193
194    private void addAwtControl(java.util.List<Component> container, final Component control) {
195        String simpleName = control.getClass().getSimpleName();
196        if (onlyClassName != null && !simpleName.equals(onlyClassName)) {
197            return;
198        }
199        if (skipClassNames != null) {
200            for (String skipMe : skipClassNames) {
201                if (simpleName.equals(skipMe)) {
202                    return;
203                }
204            }
205        }
206        setupControl(control);
207        container.add(control);
208    }
209
210    private void addSimpleAwtControl(java.util.List<Component> container, String className) {
211        try {
212            Class definition = Class.forName("java.awt." + className);
213            Constructor constructor = definition.getConstructor(new Class[]{String.class});
214            java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className});
215            addAwtControl(container, component);
216        } catch (Exception ex) {
217            System.err.println(ex.getMessage());
218            fail("Setup error, this jdk doesn't have awt conrol " + className);
219        }
220    }
221
222    /**
223     * Adds current AWT control to container
224     * <p>N.B.: if testEmbeddedFrame == true this method will also add EmbeddedFrame over Canvas
225     * and it should be called <b>after</b> Frame.setVisible(true) call
226     * @param container container to hold AWT component
227     */
228    protected final void propagateAWTControls(Container container) {
229        if (currentAwtControl != null) {
230            container.add(currentAwtControl);
231        } else { // embedded frame
232            try {
233
234                //create embedder
235                Canvas embedder = new Canvas();
236                embedder.setBackground(Color.RED);
237                embedder.setPreferredSize(new Dimension(150, 150));
238                container.add(embedder);
239                container.setVisible(true); // create peer
240
241                long frameWindow = 0;
242                String getWindowMethodName = "getHWnd";
243                if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
244                    getWindowMethodName = "getWindow";
245                }
246                ComponentPeer peer = embedder.getPeer();
247//                System.err.println("Peer: " + peer);
248                Method getWindowMethod = peer.getClass().getMethod(getWindowMethodName);
249                frameWindow = (Long) getWindowMethod.invoke(peer);
250//                System.err.println("frame peer ID: " + frameWindow);
251
252                String eframeClassName = "sun.awt.windows.WEmbeddedFrame";
253                if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) {
254                    eframeClassName = "sun.awt.X11.XEmbeddedFrame";
255                }
256                Class eframeClass = Class.forName(eframeClassName);
257                Constructor eframeCtor = eframeClass.getConstructor(long.class);
258                EmbeddedFrame eframe = (EmbeddedFrame) eframeCtor.newInstance(frameWindow);
259                setupControl(eframe);
260                eframe.setSize(new Dimension(150, 150));
261                eframe.setVisible(true);
262//                System.err.println(eframe.getSize());
263            } catch (Exception ex) {
264                ex.printStackTrace();
265                fail("Failed to instantiate EmbeddedFrame: " + ex.getMessage());
266            }
267        }
268    }
269    private static final Font hugeFont = new Font("Arial", Font.BOLD, 70);
270
271    private java.util.List<Component> getAWTControls() {
272        java.util.List<Component> components = new ArrayList<Component>();
273
274        for (String clazz : simpleAwtControls) {
275            addSimpleAwtControl(components, clazz);
276        }
277
278        TextField tf = new TextField();
279        tf.setFont(hugeFont);
280        addAwtControl(components, tf);
281
282        // more complex controls
283        Choice c = new Choice();
284        for (int i = 0; i < petStrings.length; i++) {
285            c.add(petStrings[i]);
286        }
287        addAwtControl(components, c);
288        c.setPreferredSize(null);
289        c.setFont(hugeFont); // to make control bigger as setPrefferedSize don't do his job here
290
291        List l = new List(petStrings.length);
292        for (int i = 0; i < petStrings.length; i++) {
293            l.add(petStrings[i]);
294        }
295        addAwtControl(components, l);
296
297        Canvas canvas = new Canvas();
298        canvas.setSize(100, 200);
299        addAwtControl(components, canvas);
300
301        Scrollbar sb = new Scrollbar(Scrollbar.VERTICAL, 500, 1, 0, 500);
302        addAwtControl(components, sb);
303
304        Scrollbar sb2 = new Scrollbar(Scrollbar.HORIZONTAL, 500, 1, 0, 500);
305        addAwtControl(components, sb2);
306
307        return components;
308    }
309    /**
310     * Default shift for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) }
311     */
312    protected static Point shift = new Point(16, 16);
313
314    /**
315     * Verifies point using specified AWT Robot. Supposes <code>defaultShift == true</code> for {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean) }.
316     * This method is used to verify controls by providing just their plain screen coordinates.
317     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
318     * @param lLoc point to verify
319     * @see OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point, boolean)
320     */
321    protected void clickAndBlink(Robot robot, Point lLoc) {
322        clickAndBlink(robot, lLoc, true);
323    }
324    /**
325     * Default failure message for color check
326     * @see OverlappingTestBase#performTest()
327     */
328    protected String failMessageColorCheck = "The LW component did not pass pixel color check and is overlapped";
329    /**
330     * Default failure message event check
331     * @see OverlappingTestBase#performTest()
332     */
333    protected String failMessage = "The LW component did not received the click.";
334
335    private static boolean isValidForPixelCheck(Component component) {
336        if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) {
337            return false;
338        }
339        return true;
340    }
341
342    /**
343     * Preliminary validation - should be run <b>before</b> overlapping happens to ensure test is correct.
344     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
345     * @param lLoc point to validate to be <b>of</b> {@link OverlappingTestBase#AWT_BACKGROUND_COLOR}
346     * @param component tested component, should be pointed out as not all components are valid for pixel check.
347     */
348    protected void pixelPreCheck(Robot robot, Point lLoc, Component component) {
349        if (isValidForPixelCheck(component)) {
350            int tries = 10;
351            Color c = null;
352            while (tries-- > 0) {
353                c = robot.getPixelColor(lLoc.x, lLoc.y);
354                System.out.println("Precheck. color: "+c+" compare with "+AWT_VERIFY_COLOR);
355                if (c.equals(AWT_VERIFY_COLOR)) {
356                    return;
357                }
358                try {
359                    Thread.sleep(100);
360                } catch (InterruptedException e) {
361                }
362            }
363            System.err.println(lLoc + ": " + c);
364            fail("Dropdown test setup failure, colored part of AWT component is not located at click area");
365        }
366    }
367
368    /**
369     * Verifies point using specified AWT Robot.
370     * <p>Firstly, verifies point by color pixel check
371     * <p>Secondly, verifies event delivery by mouse click
372     * @param robot AWT Robot. Usually created by {@link Util#createRobot() }
373     * @param lLoc point to verify
374     * @param defaultShift if true verified position will be shifted by {@link OverlappingTestBase#shift }.
375     */
376    protected void clickAndBlink(Robot robot, Point lLoc, boolean defaultShift) {
377        Point loc = lLoc.getLocation();
378        //check color
379        Util.waitForIdle(robot);
380        try{
381            Thread.sleep(500);
382        }catch(Exception exx){
383            exx.printStackTrace();
384        }
385
386        if (defaultShift) {
387            loc.translate(shift.x, shift.y);
388        }
389        if (!(System.getProperty("os.name").toLowerCase().contains("os x"))) {
390            Color c = robot.getPixelColor(loc.x, loc.y);
391            System.out.println("C&B. color: "+c+" compare with "+AWT_VERIFY_COLOR);
392            if (c.equals(AWT_VERIFY_COLOR)) {
393                fail(failMessageColorCheck);
394                passed = false;
395            }
396
397            // perform click
398            Util.waitForIdle(robot);
399        }
400
401        robot.mouseMove(loc.x, loc.y);
402
403        robot.mousePress(InputEvent.BUTTON1_MASK);
404        robot.mouseRelease(InputEvent.BUTTON1_MASK);
405        Util.waitForIdle(robot);
406    }
407
408    /**
409     * This method should be overriden with code which setups UI for testing.
410     * Code in this method <b>will</b> be called only from AWT thread so Swing operations can be called directly.
411     *
412     * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
413     */
414    protected abstract void prepareControls();
415
416    /**
417     * This method should be overriden with test execution. It will <b>not</b> be called from AWT thread so all Swing operations should be treated accordingly.
418     * @return true if test passed. Otherwise fail with default fail message.
419     * @see {@link OverlappingTestBase#failMessage} default fail message
420     */
421    protected abstract boolean performTest();
422    /**
423     * This method can be overriden with cleanup routines. It will be called from AWT thread so all Swing operations should be treated accordingly.
424     */
425    protected void cleanup() {
426        // intentionally do nothing
427    }
428    /**
429     * Currect tested AWT Control. Usually shouldn't be accessed directly.
430     *
431     * @see {@link OverlappingTestBase#propagateAWTControls(java.awt.Container) } for instructions about adding tested AWT control to UI
432     */
433    protected Component currentAwtControl;
434
435    private void testComponent(Component component) throws InterruptedException, InvocationTargetException {
436        currentAwtControl = component;
437        System.out.println("Testing " + currentAwtControl.getClass().getSimpleName());
438        SwingUtilities.invokeAndWait(new Runnable() {
439            public void run() {
440                prepareControls();
441            }
442        });
443        if (component != null) {
444            Util.waitTillShown(component);
445        }
446        Util.waitForIdle(null);
447        try {
448            Thread.sleep(500); // wait for graphic effects on systems like Win7
449        } catch (InterruptedException ex) {
450        }
451        if (!instance.performTest()) {
452            fail(failMessage);
453            passed = false;
454        }
455        SwingUtilities.invokeAndWait(new Runnable() {
456            public void run() {
457                cleanup();
458            }
459        });
460    }
461
462    private void testEmbeddedFrame() throws InvocationTargetException, InterruptedException {
463        System.out.println("Testing EmbeddedFrame");
464        currentAwtControl = null;
465        SwingUtilities.invokeAndWait(new Runnable() {
466            public void run() {
467                prepareControls();
468            }
469        });
470        Util.waitForIdle(null);
471        try {
472            Thread.sleep(500); // wait for graphic effects on systems like Win7
473        } catch (InterruptedException ex) {
474        }
475        if (!instance.performTest()) {
476            fail(failMessage);
477            passed = false;
478        }
479        SwingUtilities.invokeAndWait(new Runnable() {
480            public void run() {
481                cleanup();
482            }
483        });
484    }
485
486    private void testAwtControls() throws InterruptedException {
487        try {
488            for (Component component : getAWTControls()) {
489                testComponent(component);
490            }
491            if (testEmbeddedFrame && !skipTestingEmbeddedFrame) {
492                testEmbeddedFrame();
493            }
494        } catch (InvocationTargetException ex) {
495            ex.printStackTrace();
496            fail(ex.getMessage());
497        }
498    }
499    /**
500     * Used by standard test machinery. See usage at {@link OverlappingTestBase }
501     */
502    protected static OverlappingTestBase instance;
503
504    protected OverlappingTestBase() {
505        getVerifyColor();
506    }
507
508    /*****************************************************
509     * Standard Test Machinery Section
510     * DO NOT modify anything in this section -- it's a
511     * standard chunk of code which has all of the
512     * synchronisation necessary for the test harness.
513     * By keeping it the same in all tests, it is easier
514     * to read and understand someone else's test, as
515     * well as insuring that all tests behave correctly
516     * with the test harness.
517     * There is a section following this for test-
518     * classes
519     ******************************************************/
520    private static void init() throws InterruptedException {
521        //*** Create instructions for the user here ***
522        //System.setProperty("sun.awt.disableMixing", "true");
523
524        String[] instructions = {
525            "This is an AUTOMATIC test, simply wait until it is done.",
526            "The result (passed or failed) will be shown in the",
527            "message window below."
528        };
529        Sysout.createDialog();
530        Sysout.printInstructions(instructions);
531
532        instance.testAwtControls();
533
534        if (wasHWClicked) {
535            fail("HW component received the click.");
536            passed = false;
537        }
538        if (passed) {
539            pass();
540        }
541    }//End  init()
542    private static boolean theTestPassed = false;
543    private static boolean testGeneratedInterrupt = false;
544    private static String failureMessage = "";
545    private static Thread mainThread = null;
546    private static int sleepTime = 300000;
547
548    // Not sure about what happens if multiple of this test are
549    //  instantiated in the same VM.  Being static (and using
550    //  static vars), it aint gonna work.  Not worrying about
551    //  it for now.
552    /**
553     * Starting point for test runs. See usage at {@link OverlappingTestBase }
554     * @param args regular main args, not used.
555     * @throws InterruptedException
556     */
557    public static void doMain(String args[]) throws InterruptedException {
558        mainThread = Thread.currentThread();
559        try {
560            init();
561        } catch (TestPassedException e) {
562            //The test passed, so just return from main and harness will
563            // interepret this return as a pass
564            return;
565        }
566        //At this point, neither test pass nor test fail has been
567        // called -- either would have thrown an exception and ended the
568        // test, so we know we have multiple threads.
569
570        //Test involves other threads, so sleep and wait for them to
571        // called pass() or fail()
572        try {
573            Thread.sleep(sleepTime);
574            //Timed out, so fail the test
575            throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
576        } catch (InterruptedException e) {
577            //The test harness may have interrupted the test.  If so, rethrow the exception
578            // so that the harness gets it and deals with it.
579            if (!testGeneratedInterrupt) {
580                throw e;
581            }
582
583            //reset flag in case hit this code more than once for some reason (just safety)
584            testGeneratedInterrupt = false;
585
586            if (theTestPassed == false) {
587                throw new RuntimeException(failureMessage);
588            }
589        }
590
591    }//main
592
593    /**
594     * Test will fail if not passed after this timeout. Default timeout is 300 seconds.
595     * @param seconds timeout in seconds
596     */
597    public static synchronized void setTimeoutTo(int seconds) {
598        sleepTime = seconds * 1000;
599    }
600
601    /**
602     * Set test as passed. Usually shoudn't be called directly.
603     */
604    public static synchronized void pass() {
605        Sysout.println("The test passed.");
606        Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
607        //first check if this is executing in main thread
608        if (mainThread == Thread.currentThread()) {
609            //Still in the main thread, so set the flag just for kicks,
610            // and throw a test passed exception which will be caught
611            // and end the test.
612            theTestPassed = true;
613            throw new TestPassedException();
614        }
615        theTestPassed = true;
616        testGeneratedInterrupt = true;
617        mainThread.interrupt();
618    }//pass()
619
620    /**
621     * Fail test generic message.
622     */
623    public static synchronized void fail() {
624        //test writer didn't specify why test failed, so give generic
625        fail("it just plain failed! :-)");
626    }
627
628    /**
629     * Fail test providing specific reason.
630     * @param whyFailed reason
631     */
632    public static synchronized void fail(String whyFailed) {
633        Sysout.println("The test failed: " + whyFailed);
634        Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
635        //check if this called from main thread
636        if (mainThread == Thread.currentThread()) {
637            //If main thread, fail now 'cause not sleeping
638            throw new RuntimeException(whyFailed);
639        }
640        theTestPassed = false;
641        testGeneratedInterrupt = true;
642        failureMessage = whyFailed;
643        mainThread.interrupt();
644    }//fail()
645}// class LWComboBox
646class TestPassedException extends RuntimeException {
647}
648
649//*********** End Standard Test Machinery Section **********
650//************ Begin classes defined for the test ****************
651// if want to make listeners, here is the recommended place for them, then instantiate
652//  them in init()
653
654/* Example of a class which may be written as part of a test
655class NewClass implements anInterface
656{
657static int newVar = 0;
658
659public void eventDispatched(AWTEvent e)
660{
661//Counting events to see if we get enough
662eventCount++;
663
664if( eventCount == 20 )
665{
666//got enough events, so pass
667
668LWComboBox.pass();
669}
670else if( tries == 20 )
671{
672//tried too many times without getting enough events so fail
673
674LWComboBox.fail();
675}
676
677}// eventDispatched()
678
679}// NewClass class
680
681 */
682//************** End classes defined for the test *******************
683/****************************************************
684Standard Test Machinery
685DO NOT modify anything below -- it's a standard
686chunk of code whose purpose is to make user
687interaction uniform, and thereby make it simpler
688to read and understand someone else's test.
689 ****************************************************/
690/**
691This is part of the standard test machinery.
692It creates a dialog (with the instructions), and is the interface
693for sending text messages to the user.
694To print the instructions, send an array of strings to Sysout.createDialog
695WithInstructions method.  Put one line of instructions per array entry.
696To display a message for the tester to see, simply call Sysout.println
697with the string to be displayed.
698This mimics System.out.println but works within the test harness as well
699as standalone.
700 */
701class Sysout {
702    private static TestDialog dialog;
703
704    public static void createDialogWithInstructions(String[] instructions) {
705        dialog = new TestDialog(new Frame(), "Instructions");
706        dialog.printInstructions(instructions);
707        //dialog.setVisible(true);
708        println("Any messages for the tester will display here.");
709    }
710
711    public static void createDialog() {
712        dialog = new TestDialog(new Frame(), "Instructions");
713        String[] defInstr = {"Instructions will appear here. ", ""};
714        dialog.printInstructions(defInstr);
715        //dialog.setVisible(true);
716        println("Any messages for the tester will display here.");
717    }
718
719    public static void printInstructions(String[] instructions) {
720        dialog.printInstructions(instructions);
721    }
722
723    public static void println(String messageIn) {
724        dialog.displayMessage(messageIn);
725        System.out.println(messageIn);
726    }
727}// Sysout  class
728
729/**
730This is part of the standard test machinery.  It provides a place for the
731test instructions to be displayed, and a place for interactive messages
732to the user to be displayed.
733To have the test instructions displayed, see Sysout.
734To have a message to the user be displayed, see Sysout.
735Do not call anything in this dialog directly.
736 */
737class TestDialog extends Dialog {
738    TextArea instructionsText;
739    TextArea messageText;
740    int maxStringLength = 80;
741
742    //DO NOT call this directly, go through Sysout
743    public TestDialog(Frame frame, String name) {
744        super(frame, name);
745        int scrollBoth = TextArea.SCROLLBARS_BOTH;
746        instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
747        add("North", instructionsText);
748
749        messageText = new TextArea("", 5, maxStringLength, scrollBoth);
750        add("Center", messageText);
751
752        pack();
753
754       //setVisible(true);
755    }// TestDialog()
756
757    //DO NOT call this directly, go through Sysout
758    public void printInstructions(String[] instructions) {
759        //Clear out any current instructions
760        instructionsText.setText("");
761
762        //Go down array of instruction strings
763
764        String printStr, remainingStr;
765        for (int i = 0; i < instructions.length; i++) {
766            //chop up each into pieces maxSringLength long
767            remainingStr = instructions[i];
768            while (remainingStr.length() > 0) {
769                //if longer than max then chop off first max chars to print
770                if (remainingStr.length() >= maxStringLength) {
771                    //Try to chop on a word boundary
772                    int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);
773
774                    if (posOfSpace <= 0) {
775                        posOfSpace = maxStringLength - 1;
776                    }
777
778                    printStr = remainingStr.substring(0, posOfSpace + 1);
779                    remainingStr = remainingStr.substring(posOfSpace + 1);
780                } //else just print
781                else {
782                    printStr = remainingStr;
783                    remainingStr = "";
784                }
785
786                instructionsText.append(printStr + "\n");
787
788            }// while
789
790        }// for
791
792    }//printInstructions()
793
794    //DO NOT call this directly, go through Sysout
795    public void displayMessage(String messageIn) {
796        messageText.append(messageIn + "\n");
797        System.out.println(messageIn);
798    }
799}// TestDialog  class
800
801