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