EnqueueWithDialogButtonTest.java revision 14851:980da45565c8
1/*
2 * Copyright (c) 2003, 2016, 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 * @test
26 * @key headful
27 * @bug 4799136
28 * @summary Tests that type-ahead for dialog works and doesn't block program
29 * @author Dmitry.Cherepanov@SUN.COM area=awt.focus
30 * @run main EnqueueWithDialogButtonTest
31 */
32
33import java.awt.*;
34import java.lang.reflect.InvocationTargetException;
35import java.awt.event.*;
36import java.util.concurrent.CountDownLatch;
37import java.util.concurrent.TimeUnit;
38
39/*
40 * Tests that type-ahead works correctly. That means
41 * that the key events are not delivered until a focus
42 * transfer is completed.
43 * There is another pretty similar test EnqueueWithDialogTest
44 * written in time before 6347235 resolution. We'll keep it
45 * to track quite unrelated suspicious waitForIdle behavior.
46 */
47
48public class EnqueueWithDialogButtonTest
49{
50    static Frame f;
51    static Button b;
52    static Dialog d;
53    static Button ok;
54    static CountDownLatch pressLatch = new CountDownLatch(1);
55    static CountDownLatch robotLatch = new CountDownLatch(1);
56    static volatile boolean gotFocus = false;
57    static Robot robot;
58    public static void main(String args[]) throws Exception {
59        EnqueueWithDialogButtonTest test = new EnqueueWithDialogButtonTest();
60        test.init();
61        test.start();
62    }
63    public void init()
64    {
65        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
66                public void eventDispatched(AWTEvent e) {
67                    if (e instanceof InputEvent){
68                        System.err.println(e.toString()+","+((InputEvent)e).getWhen());
69                    }else{
70                        System.err.println(e.toString());
71                    }
72                 }
73            }, AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
74
75
76        f = new Frame("frame");
77        f.setPreferredSize(new Dimension(100,100));
78        f.setLocation(100,50);
79        b = new Button("press");
80        d = new Dialog(f, "dialog", true);
81        d.setPreferredSize(new Dimension(70,70));
82        ok = new Button("ok");
83        d.add(ok);
84        d.pack();
85        ok.addKeyListener(new KeyAdapter() {
86                public void keyPressed(KeyEvent e) {
87                    System.err.println("OK pressed: should arrive after got focus");
88                    d.dispose();
89                    f.dispose();
90                    // Typed-ahead key events should only be accepted if
91                    // they arrive after FOCUS_GAINED
92                    if (gotFocus) {
93                        pressLatch.countDown();
94                    }
95                }
96            });
97        ok.addFocusListener(new FocusAdapter() {
98                public void focusGained(FocusEvent e) {
99                    gotFocus = true;
100                    System.err.println("OK got focus");
101                }
102            });
103        f.add(b);
104        f.pack();
105        b.addActionListener(new ActionListener() {
106                public void actionPerformed(ActionEvent e) {
107                    System.err.println(e.toString()+","+e.getWhen());
108                    System.err.println("B pressed");
109                    robotLatch.countDown();
110
111                    EventQueue.invokeLater(new Runnable() {
112                            public void run() {
113                                waitTillShown(d);
114                                EnqueueWithDialogButtonTest.this.d.toFront();
115                                EnqueueWithDialogButtonTest.this.moveMouseOver(d);
116                            }
117                        });
118
119                    // This will cause enqueue the following key events
120                    d.setVisible(true);
121                }
122            });
123
124    }//End  init()
125
126    public void start () throws Exception
127    {
128
129        robot = new Robot();
130        robot.setAutoDelay(50);
131
132        f.setVisible(true);
133        waitTillShown(b);
134        System.err.println("b is shown");
135        f.toFront();
136        moveMouseOver(f);
137        robot.waitForIdle();
138        robot.delay(100);
139        makeFocused(b);
140        robot.waitForIdle();
141        robot.delay(100);
142        System.err.println("b is focused");
143
144        robot.keyPress(KeyEvent.VK_SPACE);
145        robot.keyRelease(KeyEvent.VK_SPACE);
146        boolean ok = robotLatch.await(1, TimeUnit.SECONDS);
147        if(!ok) {
148            throw new RuntimeException("Was B button pressed?");
149        }
150
151        robot.keyPress(KeyEvent.VK_SPACE);
152        robot.keyRelease(KeyEvent.VK_SPACE);
153        robot.delay(500);
154        ok = pressLatch.await(3, TimeUnit.SECONDS);
155        if(!ok) {
156            throw new RuntimeException("Type-ahead doesn't work");
157        }
158
159    }// start()
160
161    private void moveMouseOver(Container c) {
162        Point p = c.getLocationOnScreen();
163        Dimension d = c.getSize();
164        robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2));
165    }
166
167    private void waitTillShown(Component c) {
168        while (true) {
169            try {
170                Thread.sleep(100);
171                c.getLocationOnScreen();
172                break;
173            } catch (InterruptedException ie) {
174                ie.printStackTrace();
175                break;
176            } catch (Exception e) {
177            }
178        }
179    }
180    private void makeFocused(Component comp) {
181        if (comp.isFocusOwner()) {
182            return;
183        }
184        final Semaphore sema = new Semaphore();
185        final FocusAdapter fa = new FocusAdapter() {
186                public void focusGained(FocusEvent fe) {
187                    sema.raise();
188                }
189            };
190        comp.addFocusListener(fa);
191        comp.requestFocusInWindow();
192        if (comp.isFocusOwner()) {
193            return;
194        }
195        try {
196            sema.doWait(3000);
197        } catch (InterruptedException ie) {
198            ie.printStackTrace();
199        }
200        comp.removeFocusListener(fa);
201        if (!comp.isFocusOwner()) {
202            throw new RuntimeException("Can't make " + comp + " focused, current owner is " + KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
203        }
204    }
205
206static class Semaphore {
207    boolean state = false;
208    int waiting = 0;
209    public Semaphore() {
210    }
211    public synchronized void doWait() throws InterruptedException {
212        if (state) {
213            return;
214        }
215        waiting++;
216        wait();
217        waiting--;
218    }
219    public synchronized void doWait(int timeout) throws InterruptedException {
220        if (state) {
221            return;
222        }
223        waiting++;
224        wait(timeout);
225        waiting--;
226    }
227    public synchronized void raise() {
228        state = true;
229        if (waiting > 0) {
230            notifyAll();
231        }
232    }
233    public synchronized boolean getState() {
234        return state;
235    }
236}
237}// class TestDialogTypeAhead
238
239
240/****************************************************
241 Standard Test Machinery
242 DO NOT modify anything below -- it's a standard
243  chunk of code whose purpose is to make user
244  interaction uniform, and thereby make it simpler
245  to read and understand someone else's test.
246 ****************************************************/
247
248/**
249 This is part of the standard test machinery.
250 It creates a dialog (with the instructions), and is the interface
251  for sending text messages to the user.
252 To print the instructions, send an array of strings to Sysout.createDialog
253  WithInstructions method.  Put one line of instructions per array entry.
254 To display a message for the tester to see, simply call Sysout.println
255  with the string to be displayed.
256 This mimics System.out.println but works within the test harness as well
257  as standalone.
258 */
259
260class Sysout
261{
262    private static TestDialog dialog;
263
264    public static void createDialogWithInstructions( String[] instructions )
265    {
266        dialog = new TestDialog( new Frame(), "Instructions" );
267        dialog.printInstructions( instructions );
268        dialog.setVisible(true);
269        println( "Any messages for the tester will display here." );
270    }
271
272    public static void createDialog( )
273    {
274        dialog = new TestDialog( new Frame(), "Instructions" );
275        String[] defInstr = { "Instructions will appear here. ", "" } ;
276        dialog.printInstructions( defInstr );
277        dialog.setVisible(true);
278        println( "Any messages for the tester will display here." );
279    }
280
281
282    public static void printInstructions( String[] instructions )
283    {
284        dialog.printInstructions( instructions );
285    }
286
287
288    public static void println( String messageIn )
289    {
290        dialog.displayMessage( messageIn );
291    }
292
293}// Sysout  class
294
295/**
296  This is part of the standard test machinery.  It provides a place for the
297   test instructions to be displayed, and a place for interactive messages
298   to the user to be displayed.
299  To have the test instructions displayed, see Sysout.
300  To have a message to the user be displayed, see Sysout.
301  Do not call anything in this dialog directly.
302  */
303class TestDialog extends Dialog
304{
305
306    TextArea instructionsText;
307    TextArea messageText;
308    int maxStringLength = 80;
309
310    //DO NOT call this directly, go through Sysout
311    public TestDialog( Frame frame, String name )
312    {
313        super( frame, name );
314        int scrollBoth = TextArea.SCROLLBARS_BOTH;
315        instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
316        add( "North", instructionsText );
317
318        messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
319        add("Center", messageText);
320
321        pack();
322
323        show();
324    }// TestDialog()
325
326    //DO NOT call this directly, go through Sysout
327    public void printInstructions( String[] instructions )
328    {
329        //Clear out any current instructions
330        instructionsText.setText( "" );
331
332        //Go down array of instruction strings
333
334        String printStr, remainingStr;
335        for( int i=0; i < instructions.length; i++ )
336        {
337            //chop up each into pieces maxSringLength long
338            remainingStr = instructions[ i ];
339            while( remainingStr.length() > 0 )
340            {
341                //if longer than max then chop off first max chars to print
342                if( remainingStr.length() >= maxStringLength )
343                {
344                    //Try to chop on a word boundary
345                    int posOfSpace = remainingStr.
346                        lastIndexOf( ' ', maxStringLength - 1 );
347
348                    if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
349
350                    printStr = remainingStr.substring( 0, posOfSpace + 1 );
351                    remainingStr = remainingStr.substring( posOfSpace + 1 );
352                }
353                //else just print
354                else
355                {
356                    printStr = remainingStr;
357                    remainingStr = "";
358                }
359
360                instructionsText.append( printStr + "\n" );
361
362            }// while
363
364        }// for
365
366    }//printInstructions()
367
368    //DO NOT call this directly, go through Sysout
369    public void displayMessage( String messageIn )
370    {
371        messageText.append( messageIn + "\n" );
372        System.out.println(messageIn);
373    }
374
375}// TestDialog  class
376