1 /* 2 * Copyright (c) 2011, 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 6431076 27 @summary Mouse cursor must remain DEFAULT over scrollbar when text is typed 28 @author Andrei Dmitriev: area=TextArea 29 @run main/manual Test 30 */ 31 32 import java.awt.*; 33 import java.awt.event.*; 34 35 public class Test { 36 private static void init() { 37 Frame f = new Frame("Test for cursor"); 38 final int dim = 100; 39 String line = ""; 40 for( int i=0; i<dim; ++i ) { 41 line += "a"; 42 } 43 String text = ""; 44 for( int i=0; i<dim; ++i ) { 45 text += line; 46 if( i < dim-1 ) { 47 text += "\n"; 48 } 49 } 50 51 f.setLayout( new BorderLayout () ); 52 f.add( new TextArea( text ) ); 53 f.setSize(400, 300); 54 55 f.setVisible(true); 56 57 String[] instructions = { 58 "1. Place keyboard cursor inside TextArea.", 59 "2. Repeat steps 2.* for each of two TextArea's scrollbars.", 60 "2.1. Place mouse cursor over TextArea's scrollbar.", 61 "2.2. If mouse cursor is not DEFAULT_CURSOR (arrow), test failed.", 62 "2.3. Type any symbol into TextArea.", 63 "2.4. Type ENTER symbol into TextArea.", 64 "2.5. If mouse cursor changes to TEXT_CURSOR (beam), test failed", 65 "(if cursor disappears on Windows, it's OK).", 66 "3. Test passed.", 67 }; 68 69 Sysout.createDialogWithInstructions( instructions ); 70 } 71 72 73 74 /***************************************************** 75 * Standard Test Machinery Section 76 * DO NOT modify anything in this section -- it's a 77 * standard chunk of code which has all of the 78 * synchronisation necessary for the test harness. 79 * By keeping it the same in all tests, it is easier 80 * to read and understand someone else's test, as 81 * well as insuring that all tests behave correctly 82 * with the test harness. 83 * There is a section following this for test-defined 84 * classes 85 ******************************************************/ 86 private static boolean theTestPassed = false; 87 private static boolean testGeneratedInterrupt = false; 88 private static String failureMessage = ""; 89 90 private static Thread mainThread = null; 91 92 private static int sleepTime = 300000; 93 94 public static void main( String args[] ) throws InterruptedException 95 { 96 mainThread = Thread.currentThread(); 97 try 98 { 99 init(); 100 } 101 catch( TestPassedException e ) 102 { 103 //The test passed, so just return from main and harness will 104 // interepret this return as a pass 105 return; 106 } 107 //At this point, neither test passed nor test failed has been 108 // called -- either would have thrown an exception and ended the 109 // test, so we know we have multiple threads. 110 111 //Test involves other threads, so sleep and wait for them to 112 // called pass() or fail() 113 try 114 { 115 Thread.sleep( sleepTime ); 116 //Timed out, so fail the test 117 throw new RuntimeException( "Timed out after " + sleepTime/1000 + " seconds" ); 118 } 119 catch (InterruptedException e) 120 { 121 if( ! testGeneratedInterrupt ) throw e; 122 123 //reset flag in case hit this code more than once for some reason (just safety) 124 testGeneratedInterrupt = false; 125 if ( theTestPassed == false ) 126 { 127 throw new RuntimeException( failureMessage ); 128 } 129 } 130 131 }//main 132 133 public static synchronized void setTimeoutTo( int seconds ) 134 { 135 sleepTime = seconds * 1000; 136 } 137 138 public static synchronized void pass() 139 { 140 Sysout.println( "The test passed." ); 141 Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); 142 //first check if this is executing in main thread 143 if ( mainThread == Thread.currentThread() ) 144 { 145 //Still in the main thread, so set the flag just for kicks, 146 // and throw a test passed exception which will be caught 147 // and end the test. 148 theTestPassed = true; 149 throw new TestPassedException(); 150 } 151 //pass was called from a different thread, so set the flag and interrupt 152 // the main thead. 153 theTestPassed = true; 154 testGeneratedInterrupt = true; 155 if (mainThread != null){ 156 mainThread.interrupt(); 157 } 158 }//pass() 159 160 public static synchronized void fail() 161 { 162 //test writer didn't specify why test failed, so give generic 163 fail( "it just plain failed! :-)" ); 164 } 165 166 public static synchronized void fail( String whyFailed ) 167 { 168 Sysout.println( "The test failed: " + whyFailed ); 169 Sysout.println( "The test is over, hit Ctl-C to stop Java VM" ); 170 //check if this called from main thread 171 if ( mainThread == Thread.currentThread() ) 172 { 173 //If main thread, fail now 'cause not sleeping 174 throw new RuntimeException( whyFailed ); 175 } 176 theTestPassed = false; 177 testGeneratedInterrupt = true; 178 failureMessage = whyFailed; 179 mainThread.interrupt(); 180 }//fail() 181 182 }// class 183 184 //This exception is used to exit from any level of call nesting 185 // when it's determined that the test has passed, and immediately 186 // end the test. 187 class TestPassedException extends RuntimeException 188 { 189 } 190 191 //*********** End Standard Test Machinery Section ********** 192 193 194 //************ Begin classes defined for the test **************** 195 196 // make listeners in a class defined here, and instantiate them in init() 197 198 /* Example of a class which may be written as part of a test 199 class NewClass implements anInterface 200 { 201 static int newVar = 0; 202 203 public void eventDispatched(AWTEvent e) 204 { 205 //Counting events to see if we get enough 206 eventCount++; 207 208 if( eventCount == 20 ) 209 { 210 //got enough events, so pass 211 212 ManualMainTest.pass(); 213 } 214 else if( tries == 20 ) 215 { 216 //tried too many times without getting enough events so fail 217 218 ManualMainTest.fail(); 219 } 220 221 }// eventDispatched() 222 223 }// NewClass class 224 225 */ 226 227 228 //************** End classes defined for the test ******************* 229 230 231 232 233 /**************************************************** 234 Standard Test Machinery 235 DO NOT modify anything below -- it's a standard 236 chunk of code whose purpose is to make user 237 interaction uniform, and thereby make it simpler 238 to read and understand someone else's test. 239 ****************************************************/ 240 241 /** 242 This is part of the standard test machinery. 243 It creates a dialog (with the instructions), and is the interface 244 for sending text messages to the user. 245 To print the instructions, send an array of strings to Sysout.createDialog 246 WithInstructions method. Put one line of instructions per array entry. 247 To display a message for the tester to see, simply call Sysout.println 248 with the string to be displayed. 249 This mimics System.out.println but works within the test harness as well 250 as standalone. 251 */ 252 253 class Sysout 254 { 255 private static TestDialog dialog; 256 private static boolean numbering = false; 257 private static int messageNumber = 0; 258 259 public static void createDialogWithInstructions( String[] instructions ) 260 { 261 dialog = new TestDialog( new Frame(), "Instructions" ); 262 dialog.printInstructions( instructions ); 263 dialog.setVisible(true); 264 println( "Any messages for the tester will display here." ); 265 } 266 267 public static void createDialog( ) 268 { 269 dialog = new TestDialog( new Frame(), "Instructions" ); 270 String[] defInstr = { "Instructions will appear here. ", "" } ; 271 dialog.printInstructions( defInstr ); 272 dialog.setVisible(true); 273 println( "Any messages for the tester will display here." ); 274 } 275 276 277 /* Enables message counting for the tester. */ 278 public static void enableNumbering(boolean enable){ 279 numbering = enable; 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 if (numbering) { 291 messageIn = "" + messageNumber + " " + messageIn; 292 messageNumber++; 293 } 294 dialog.displayMessage( messageIn ); 295 } 296 297 }// Sysout class 298 299 /** 300 This is part of the standard test machinery. It provides a place for the 301 test instructions to be displayed, and a place for interactive messages 302 to the user to be displayed. 303 To have the test instructions displayed, see Sysout. 304 To have a message to the user be displayed, see Sysout. 305 Do not call anything in this dialog directly. 306 */ 307 class TestDialog extends Dialog implements ActionListener 308 { 309 310 TextArea instructionsText; 311 TextArea messageText; 312 int maxStringLength = 80; 313 Panel buttonP = new Panel(); 314 Button passB = new Button( "pass" ); 315 Button failB = new Button( "fail" ); 316 317 //DO NOT call this directly, go through Sysout 318 public TestDialog( Frame frame, String name ) 319 { 320 super( frame, name ); 321 int scrollBoth = TextArea.SCROLLBARS_BOTH; 322 instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth ); 323 add( "North", instructionsText ); 324 325 messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); 326 add("Center", messageText); 327 328 passB = new Button( "pass" ); 329 passB.setActionCommand( "pass" ); 330 passB.addActionListener( this ); 331 buttonP.add( "East", passB ); 332 333 failB = new Button( "fail" ); 334 failB.setActionCommand( "fail" ); 335 failB.addActionListener( this ); 336 buttonP.add( "West", failB ); 337 338 add( "South", buttonP ); 339 pack(); 340 341 setVisible(true); 342 }// TestDialog() 343 344 //DO NOT call this directly, go through Sysout 345 public void printInstructions( String[] instructions ) 346 { 347 //Clear out any current instructions 348 instructionsText.setText( "" ); 349 350 //Go down array of instruction strings 351 352 String printStr, remainingStr; 353 for( int i=0; i < instructions.length; i++ ) 354 { 355 //chop up each into pieces maxSringLength long 356 remainingStr = instructions[ i ]; 357 while( remainingStr.length() > 0 ) 358 { 359 //if longer than max then chop off first max chars to print 360 if( remainingStr.length() >= maxStringLength ) 361 { 362 //Try to chop on a word boundary 363 int posOfSpace = remainingStr. 364 lastIndexOf( ' ', maxStringLength - 1 ); 365 366 if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; 367 368 printStr = remainingStr.substring( 0, posOfSpace + 1 ); 369 remainingStr = remainingStr.substring( posOfSpace + 1 ); 370 } 371 //else just print 372 else 373 { 374 printStr = remainingStr; 375 remainingStr = ""; 376 } 377 378 instructionsText.append( printStr + "\n" ); 379 380 }// while 381 382 }// for 383 384 }//printInstructions() 385 386 //DO NOT call this directly, go through Sysout 387 public void displayMessage( String messageIn ) 388 { 389 messageText.append( messageIn + "\n" ); 390 System.out.println(messageIn); 391 } 392 393 //catch presses of the passed and failed buttons. 394 //simply call the standard pass() or fail() static methods of 395 //ManualMainTest 396 public void actionPerformed( ActionEvent e ) 397 { 398 if( e.getActionCommand() == "pass" ) 399 { 400 Test.pass(); 401 } 402 else 403 { 404 Test.fail(); 405 } 406 } 407 408 }// TestDialog class