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