1 /*
2 * Copyright 2003-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24 /*
25 test
26 @bug 4799136
27 @summary Tests that type-ahead for dialog works and doesn't block program
28 @author area=awt.focus
29 @run applet TestDialogTypeAhead.html
30 */
31
32 // Note there is no @ in front of test above. This is so that the
33 // harness will not mistake this file as a test file. It should
34 // only see the html file as a test file. (the harness runs all
35 // valid test files, so it would run this test twice if this file
36 // were valid as well as the html file.)
37 // Also, note the area= after Your Name in the author tag. Here, you
38 // should put which functional area the test falls in. See the
39 // AWT-core home page -> test areas and/or -> AWT team for a list of
40 // areas.
41 // Note also the 'TestDialogTypeAhead.html' in the run tag. This should
42 // be changed to the name of the test.
43
44
45 /**
46 * TestDialogTypeAhead.java
47 *
48 * summary:
49 */
50
51 import java.applet.Applet;
52 import java.awt.*;
53 import java.lang.reflect.InvocationTargetException;
54 import java.awt.event.*;
55 import java.awt.peer.DialogPeer;
56 import java.awt.peer.ComponentPeer;
57 import java.lang.reflect.Method;
58 import java.lang.reflect.Proxy;
59 import java.lang.reflect.InvocationHandler;
60 import java.lang.reflect.InvocationTargetException;
61 import test.java.awt.regtesthelpers.Util;
62
63 //Automated tests should run as applet tests if possible because they
64 // get their environments cleaned up, including AWT threads, any
65 // test created threads, and any system resources used by the test
66 // such as file descriptors. (This is normally not a problem as
67 // main tests usually run in a separate VM, however on some platforms
68 // such as the Mac, separate VMs are not possible and non-applet
69 // tests will cause problems). Also, you don't have to worry about
70 // synchronisation stuff in Applet tests they way you do in main
71 // tests...
72
73
74 public class TestDialogTypeAhead extends Applet
75 {
76 //Declare things used in the test, like buttons and labels here
77 static Frame f;
78 static Button b;
79 static Dialog d;
80 static Button ok;
81 static Semaphore pressSema = new Semaphore();
82 static Semaphore robotSema = new Semaphore();
83 static volatile boolean gotFocus = false;
84 static Robot robot;
85 public void init()
86 {
87 //Create instructions for the user here, as well as set up
88 // the environment -- set the layout manager, add buttons,
89 // etc.
90
91 Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
92 public void eventDispatched(AWTEvent e) {
93 System.err.println(e.toString());
94 }
95 }, AWTEvent.KEY_EVENT_MASK);
96
97 this.setLayout (new BorderLayout ());
98
99 f = new Frame("frame");
100 b = new Button("press");
101 d = new TestDialog(f, "dialog", true, robotSema);
102 ok = new Button("ok");
103 d.add(ok);
104 d.pack();
105
106 ok.addKeyListener(new KeyAdapter() {
107 public void keyPressed(KeyEvent e) {
108 System.err.println("OK pressed");
109 d.dispose();
110 f.dispose();
111 // Typed-ahead key events should only be accepted if
112 // they arrive after FOCUS_GAINED
113 if (gotFocus) {
114 pressSema.raise();
115 }
116 }
117 });
118 ok.addFocusListener(new FocusAdapter() {
119 public void focusGained(FocusEvent e) {
120 gotFocus = true;
121 System.err.println("Ok got focus");
122 }
123 });
124 f.add(b);
125 f.pack();
126 b.addActionListener(new ActionListener() {
127 public void actionPerformed(ActionEvent e) {
128 System.err.println("B pressed");
129
130 EventQueue.invokeLater(new Runnable() {
131 public void run() {
132 waitTillShown(d);
133 TestDialogTypeAhead.this.d.toFront();
134 TestDialogTypeAhead.this.moveMouseOver(d);
135 }
136 });
137
138 d.setVisible(true);
139 }
140 });
141
142 }//End init()
143
144 public void start ()
145 {
146 //Get things going. Request focus, set size, et cetera
147 setSize (200,200);
148 setVisible(true);
149 validate();
150 try {
151 robot = new Robot();
152 } catch (Exception e) {
153 throw new RuntimeException("Can't create robot:" + e);
154 }
155
156 f.setVisible(true);
157 waitTillShown(b);
158 System.err.println("b is shown");
159 f.toFront();
160 moveMouseOver(f);
161 waitForIdle();
162 makeFocused(b);
163 waitForIdle();
164 System.err.println("b is focused");
165
166 robot.keyPress(KeyEvent.VK_SPACE);
167 robot.keyRelease(KeyEvent.VK_SPACE);
168 try {
169 robotSema.doWait(1000);
170 } catch (InterruptedException ie) {
171 throw new RuntimeException("Interrupted!");
172 }
173 robot.keyPress(KeyEvent.VK_SPACE);
174 robot.keyRelease(KeyEvent.VK_SPACE);
175 waitForIdle();
176 try {
177 pressSema.doWait(3000);
178 } catch (InterruptedException ie) {
179 throw new RuntimeException("Interrupted!");
180 }
181 if (!pressSema.getState()) {
182 throw new RuntimeException("Type-ahead doesn't work");
183 }
184
185 }// start()
186
187 private void moveMouseOver(Container c) {
188 Point p = c.getLocationOnScreen();
189 Dimension d = c.getSize();
190 robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2));
191 }
192 private void waitForIdle() {
193 try {
194 Toolkit.getDefaultToolkit().sync();
195 sun.awt.SunToolkit.flushPendingEvents();
196 EventQueue.invokeAndWait( new Runnable() {
197 public void run() {
198 // dummy implementation
199 }
200 } );
201 } catch(InterruptedException ite) {
202 System.err.println("Robot.waitForIdle, non-fatal exception caught:");
203 ite.printStackTrace();
204 } catch(InvocationTargetException ine) {
205 System.err.println("Robot.waitForIdle, non-fatal exception caught:");
206 ine.printStackTrace();
207 }
208 }
209
210 private void waitTillShown(Component c) {
211 while (true) {
212 try {
213 Thread.sleep(100);
214 c.getLocationOnScreen();
215 break;
216 } catch (InterruptedException ie) {
217 ie.printStackTrace();
218 break;
219 } catch (Exception e) {
220 }
221 }
222 }
223 private void makeFocused(Component comp) {
224 if (comp.isFocusOwner()) {
225 return;
226 }
227 final Semaphore sema = new Semaphore();
228 final FocusAdapter fa = new FocusAdapter() {
229 public void focusGained(FocusEvent fe) {
230 sema.raise();
231 }
232 };
233 comp.addFocusListener(fa);
234 comp.requestFocusInWindow();
235 if (comp.isFocusOwner()) {
236 return;
237 }
238 try {
239 sema.doWait(3000);
240 } catch (InterruptedException ie) {
241 ie.printStackTrace();
242 }
243 comp.removeFocusListener(fa);
244 if (!comp.isFocusOwner()) {
245 throw new RuntimeException("Can't make " + comp + " focused, current owner is " + KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
246 }
247 }
248
249 static class Semaphore {
250 boolean state = false;
251 int waiting = 0;
252 public Semaphore() {
253 }
254 public synchronized void doWait() throws InterruptedException {
255 if (state) {
256 return;
257 }
258 waiting++;
259 wait();
260 waiting--;
261 }
262 public synchronized void doWait(int timeout) throws InterruptedException {
263 if (state) {
264 return;
265 }
266 waiting++;
267 wait(timeout);
268 waiting--;
269 }
270 public synchronized void raise() {
271 state = true;
272 if (waiting > 0) {
273 notifyAll();
274 }
275 }
276 public synchronized boolean getState() {
277 return state;
278 }
279 }
280
281 // Fix for 6446952.
282 // In the process of showing the dialog we have to catch peer.show() call
283 // so that to trigger key events just before it gets invoked.
284 // We base on the fact that a modal dialog sets type-ahead markers
285 // before it calls 'show' on the peer.
286 // Posting the key events before dialog.setVisible(true) would be actually not
287 // good because it would be Ok to dispatch them to the current focus owner,
288 // not to the dialog.
289 class TestDialog extends Dialog {
290 ComponentPeer origDialogPeer;
291 ComponentPeer proxyInstPeer;
292 Semaphore trigger;
293
294 TestDialog(Frame owner, String title, boolean modal, Semaphore trigger) {
295 super(owner, title, modal);
296 this.trigger = trigger;
297 }
298
299 public void addNotify() {
300 super.addNotify();
301 }
302 }
303 }// class TestDialogTypeAhead
304
305
306 /****************************************************
307 Standard Test Machinery
308 DO NOT modify anything below -- it's a standard
309 chunk of code whose purpose is to make user
310 interaction uniform, and thereby make it simpler
311 to read and understand someone else's test.
312 ****************************************************/
313
314 /**
315 This is part of the standard test machinery.
316 It creates a dialog (with the instructions), and is the interface
317 for sending text messages to the user.
318 To print the instructions, send an array of strings to Sysout.createDialog
319 WithInstructions method. Put one line of instructions per array entry.
320 To display a message for the tester to see, simply call Sysout.println
321 with the string to be displayed.
322 This mimics System.out.println but works within the test harness as well
323 as standalone.
324 */
325
326 class Sysout
327 {
328 private static TestDialog dialog;
329
330 public static void createDialogWithInstructions( String[] instructions )
331 {
332 dialog = new TestDialog( new Frame(), "Instructions" );
333 dialog.printInstructions( instructions );
334 dialog.setVisible(true);
335 println( "Any messages for the tester will display here." );
336 }
337
338 public static void createDialog( )
339 {
340 dialog = new TestDialog( new Frame(), "Instructions" );
341 String[] defInstr = { "Instructions will appear here. ", "" } ;
342 dialog.printInstructions( defInstr );
343 dialog.setVisible(true);
344 println( "Any messages for the tester will display here." );
345 }
346
347
348 public static void printInstructions( String[] instructions )
349 {
350 dialog.printInstructions( instructions );
351 }
352
353
354 public static void println( String messageIn )
355 {
356 dialog.displayMessage( messageIn );
357 }
358
359 }// Sysout class
360
361 /**
362 This is part of the standard test machinery. It provides a place for the
363 test instructions to be displayed, and a place for interactive messages
364 to the user to be displayed.
365 To have the test instructions displayed, see Sysout.
366 To have a message to the user be displayed, see Sysout.
367 Do not call anything in this dialog directly.
368 */
369 class TestDialog extends Dialog
370 {
371
372 TextArea instructionsText;
373 TextArea messageText;
374 int maxStringLength = 80;
375
376 //DO NOT call this directly, go through Sysout
377 public TestDialog( Frame frame, String name )
378 {
379 super( frame, name );
380 int scrollBoth = TextArea.SCROLLBARS_BOTH;
381 instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
382 add( "North", instructionsText );
383
384 messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
385 add("Center", messageText);
386
387 pack();
388
389 show();
390 }// TestDialog()
391
392 //DO NOT call this directly, go through Sysout
393 public void printInstructions( String[] instructions )
394 {
395 //Clear out any current instructions
396 instructionsText.setText( "" );
397
398 //Go down array of instruction strings
399
400 String printStr, remainingStr;
401 for( int i=0; i < instructions.length; i++ )
402 {
403 //chop up each into pieces maxSringLength long
404 remainingStr = instructions[ i ];
405 while( remainingStr.length() > 0 )
406 {
407 //if longer than max then chop off first max chars to print
408 if( remainingStr.length() >= maxStringLength )
409 {
410 //Try to chop on a word boundary
411 int posOfSpace = remainingStr.
412 lastIndexOf( ' ', maxStringLength - 1 );
413
414 if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
415
416 printStr = remainingStr.substring( 0, posOfSpace + 1 );
417 remainingStr = remainingStr.substring( posOfSpace + 1 );
418 }
419 //else just print
420 else
421 {
422 printStr = remainingStr;
423 remainingStr = "";
424 }
425
426 instructionsText.append( printStr + "\n" );
427
428 }// while
429
430 }// for
431
432 }//printInstructions()
433
434 //DO NOT call this directly, go through Sysout
435 public void displayMessage( String messageIn )
436 {
437 messageText.append( messageIn + "\n" );
438 System.out.println(messageIn);
439 }
440
441 }// TestDialog class