1 /*
   2  * Copyright (c) 2014, 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 import java.awt.*;
  26 import java.awt.event.InputEvent;
  27 import javax.swing.*;
  28 import java.io.*;
  29 import test.java.awt.regtesthelpers.Util;
  30 
  31 /**
  32  * AWT/Swing overlapping test for Panel and JPanel behavior during resizing.
  33  * <p>See <a href="https://bugs.openjdk.java.net/browse/JDK-6786219">JDK-6786219</a> for details
  34  */
  35 /*
  36  * @test
  37  * @key headful
  38  * @bug 6786219
  39  * @summary Issues when resizing the frame after mixing of heavy weight & light weight components
  40  * @author sergey.grinev@oracle.com: area=awt.mixing
  41  * @library ../../regtesthelpers
  42  * @build Util
  43  * @build FrameBorderCounter
  44  * @run main MixingPanelsResizing
  45  */
  46 public class MixingPanelsResizing {
  47 
  48     static volatile boolean failed = false;
  49 
  50     private static JFrame frame;
  51     private static JButton jbutton;
  52     private static Button awtButton;
  53     private static JButton jbutton2;
  54     private static Button awtButton2;
  55     private static final Color jbColor = Color.RED;
  56     private static final Color awtColor = Color.ORANGE;
  57     private static final Color jb2Color = Color.BLUE;
  58     private static final Color awt2Color = Color.CYAN;
  59     private static final int ROBOT_DELAY = 500;
  60 
  61     private static Point lLoc;
  62     private static int borderShift;
  63 
  64     private static int frameBorderCounter() {
  65         String JAVA_HOME = System.getProperty("java.home");
  66         try {
  67             Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter");
  68             try {
  69                 p.waitFor();
  70             } catch (InterruptedException e) {
  71                 e.printStackTrace();
  72                 throw new RuntimeException(e);
  73             }
  74             if (p.exitValue() != 0) {
  75                 throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream()));
  76             }
  77             return Integer.parseInt(readInputStream(p.getInputStream()).trim());
  78         } catch (IOException e) {
  79             e.printStackTrace();
  80             throw new RuntimeException(e);
  81         }
  82     }
  83 
  84     private static String readInputStream(InputStream is) throws IOException {
  85         byte[] buffer = new byte[4096];
  86         int len = 0;
  87         StringBuilder sb = new StringBuilder();
  88         try (InputStreamReader isr = new InputStreamReader(is)) {
  89             while ((len = is.read(buffer)) > 0) {
  90                 sb.append(new String(buffer, 0, len));
  91             }
  92         }
  93         return sb.toString();
  94     }
  95 
  96     private static void init() throws Exception {
  97         //*** Create instructions for the user here ***
  98 
  99         borderShift = frameBorderCounter();
 100         borderShift = Math.abs(borderShift) == 1 ? borderShift : (borderShift / 2);
 101         String[] instructions = {
 102             "This is an AUTOMATIC test, simply wait until it is done.",
 103             "The result (passed or failed) will be shown in the",
 104             "message window below."
 105         };
 106         SwingUtilities.invokeAndWait(new Runnable() {
 107             public void run() {
 108                 Sysout.createDialog();
 109                 Sysout.printInstructions(instructions);
 110 
 111                 // prepare controls
 112 
 113                 frame = new JFrame();
 114 
 115                 Panel awtPanel = new Panel();
 116                 awtPanel.setBackground(Color.GREEN);
 117                 awtButton = new Button("AWTButton");
 118                 awtPanel.add(awtButton);
 119                 awtButton.setForeground(awtColor);
 120                 awtButton.setBackground(awtColor);
 121                 jbutton = new JButton("SwingButton");
 122                 awtPanel.add(jbutton);
 123                 jbutton.setForeground(jbColor);
 124                 jbutton.setBackground(jbColor);
 125 
 126                 JPanel jPanel = new JPanel();
 127                 jbutton2 = new JButton("SwingButton2");
 128                 jPanel.add(jbutton2);
 129                 jbutton2.setForeground(jb2Color);
 130                 jbutton2.setBackground(jb2Color);
 131                 awtButton2 = new Button("AWT Button2");
 132                 jPanel.add(awtButton2);
 133                 awtButton2.setForeground(awt2Color);
 134                 awtButton2.setBackground(awt2Color);
 135                 jPanel.setBackground(Color.YELLOW);
 136 
 137                 frame.add(awtPanel, BorderLayout.SOUTH);
 138                 frame.add(jPanel, BorderLayout.NORTH);
 139 
 140                 frame.pack();
 141                 frame.setVisible(true);
 142             }
 143         });
 144 
 145         /////////////////////////
 146 
 147         final Robot robot = Util.createRobot();
 148         robot.setAutoDelay(ROBOT_DELAY);
 149 
 150         Util.waitForIdle(robot);
 151 
 152         SwingUtilities.invokeAndWait(new Runnable() {
 153             public void run() {
 154                 lLoc = frame.getLocationOnScreen();
 155                 lLoc.translate(frame.getWidth() + borderShift, frame.getHeight() + borderShift);
 156             }
 157         });
 158 
 159         //grow
 160         robot.mouseMove(lLoc.x, lLoc.y);
 161         robot.mousePress(InputEvent.BUTTON1_MASK);
 162 
 163         Runnable test = new Runnable() {
 164 
 165             public void run() {
 166                 Point btnLoc = jbutton.getLocationOnScreen();
 167                 Color c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5);
 168                 if (!c.equals(jbColor)) {
 169                     fail("JButton was not redrawn properly on AWT Panel during move");
 170                 }
 171 
 172                 btnLoc = awtButton.getLocationOnScreen();
 173                 c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5);
 174                 if (!c.equals(awtColor)) {
 175                     fail("AWT Button was not redrawn properly on AWT Panel during move");
 176                 }
 177 
 178                 btnLoc = jbutton2.getLocationOnScreen();
 179                 c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5);
 180                 if (!c.equals(jb2Color)) {
 181                     fail("JButton was not redrawn properly on JPanel during move");
 182                 }
 183 
 184                 btnLoc = awtButton2.getLocationOnScreen();
 185                 c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5);
 186                 if (!c.equals(awt2Color)) {
 187                     fail("ATW Button was not redrawn properly on JPanel during move");
 188                 }
 189             }
 190         };
 191 
 192         for (int i = 0; i < 30; i++) {
 193             test.run();
 194             robot.mouseMove(lLoc.x + 20 * i, lLoc.y + 10 * i);
 195         }
 196         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 197 
 198         //back
 199         System.out.println("fast back");
 200         robot.mousePress(InputEvent.BUTTON1_MASK);
 201         for (int i = 5; i >= 0; i--) {
 202             test.run();
 203             robot.mouseMove(lLoc.x + 120 * i, lLoc.y + 60 * i);
 204         }
 205         robot.mouseRelease(InputEvent.BUTTON1_MASK);
 206 
 207         pass();
 208     }//End  init()
 209     /*****************************************************
 210      * Standard Test Machinery Section
 211      * DO NOT modify anything in this section -- it's a
 212      * standard chunk of code which has all of the
 213      * synchronisation necessary for the test harness.
 214      * By keeping it the same in all tests, it is easier
 215      * to read and understand someone else's test, as
 216      * well as insuring that all tests behave correctly
 217      * with the test harness.
 218      * There is a section following this for test-
 219      * classes
 220      ******************************************************/
 221     private static boolean theTestPassed = false;
 222     private static boolean testGeneratedInterrupt = false;
 223     private static String failureMessage = "";
 224     private static Thread mainThread = null;
 225     private static int sleepTime = 300000;
 226 
 227     // Not sure about what happens if multiple of this test are
 228     //  instantiated in the same VM.  Being static (and using
 229     //  static vars), it aint gonna work.  Not worrying about
 230     //  it for now.
 231     public static void main(String args[]) throws Exception {
 232         if (!Toolkit.getDefaultToolkit().isDynamicLayoutActive()) {
 233             System.out.println("Dynamic layout is not active. Test passes.");
 234             return;
 235         }
 236         mainThread = Thread.currentThread();
 237         try {
 238             init();
 239         } catch (TestPassedException e) {
 240             //The test passed, so just return from main and harness will
 241             // interepret this return as a pass
 242             return;
 243         }
 244         //At this point, neither test pass nor test fail has been
 245         // called -- either would have thrown an exception and ended the
 246         // test, so we know we have multiple threads.
 247 
 248         //Test involves other threads, so sleep and wait for them to
 249         // called pass() or fail()
 250         try {
 251             Thread.sleep(sleepTime);
 252             //Timed out, so fail the test
 253             throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds");
 254         } catch (InterruptedException e) {
 255             //The test harness may have interrupted the test.  If so, rethrow the exception
 256             // so that the harness gets it and deals with it.
 257             if (!testGeneratedInterrupt) {
 258                 throw e;
 259             }
 260 
 261             //reset flag in case hit this code more than once for some reason (just safety)
 262             testGeneratedInterrupt = false;
 263 
 264             if (theTestPassed == false) {
 265                 throw new RuntimeException(failureMessage);
 266             }
 267         }
 268 
 269     }//main
 270 
 271     public static synchronized void setTimeoutTo(int seconds) {
 272         sleepTime = seconds * 1000;
 273     }
 274 
 275     public static synchronized void pass() {
 276         Sysout.println("The test passed.");
 277         Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
 278         //first check if this is executing in main thread
 279         if (mainThread == Thread.currentThread()) {
 280             //Still in the main thread, so set the flag just for kicks,
 281             // and throw a test passed exception which will be caught
 282             // and end the test.
 283             theTestPassed = true;
 284             throw new TestPassedException();
 285         }
 286         theTestPassed = true;
 287         testGeneratedInterrupt = true;
 288         mainThread.interrupt();
 289     }//pass()
 290 
 291     public static synchronized void fail() {
 292         //test writer didn't specify why test failed, so give generic
 293         fail("it just plain failed! :-)");
 294     }
 295 
 296     public static synchronized void fail(String whyFailed) {
 297         Sysout.println("The test failed: " + whyFailed);
 298         Sysout.println("The test is over, hit  Ctl-C to stop Java VM");
 299         //check if this called from main thread
 300         if (mainThread == Thread.currentThread()) {
 301             //If main thread, fail now 'cause not sleeping
 302             throw new RuntimeException(whyFailed);
 303         }
 304         theTestPassed = false;
 305         testGeneratedInterrupt = true;
 306         failureMessage = whyFailed;
 307         mainThread.interrupt();
 308     }//fail()
 309 }// class JButtonInGlassPane
 310 class TestPassedException extends RuntimeException {
 311 }
 312 
 313 //*********** End Standard Test Machinery Section **********
 314 //************ Begin classes defined for the test ****************
 315 // if want to make listeners, here is the recommended place for them, then instantiate
 316 //  them in init()
 317 
 318 /* Example of a class which may be written as part of a test
 319 class NewClass implements anInterface
 320 {
 321 static int newVar = 0;
 322 
 323 public void eventDispatched(AWTEvent e)
 324 {
 325 //Counting events to see if we get enough
 326 eventCount++;
 327 
 328 if( eventCount == 20 )
 329 {
 330 //got enough events, so pass
 331 
 332 JButtonInGlassPane.pass();
 333 }
 334 else if( tries == 20 )
 335 {
 336 //tried too many times without getting enough events so fail
 337 
 338 JButtonInGlassPane.fail();
 339 }
 340 
 341 }// eventDispatched()
 342 
 343 }// NewClass class
 344 
 345  */
 346 //************** End classes defined for the test *******************
 347 /****************************************************
 348 Standard Test Machinery
 349 DO NOT modify anything below -- it's a standard
 350 chunk of code whose purpose is to make user
 351 interaction uniform, and thereby make it simpler
 352 to read and understand someone else's test.
 353  ****************************************************/
 354 /**
 355 This is part of the standard test machinery.
 356 It creates a dialog (with the instructions), and is the interface
 357 for sending text messages to the user.
 358 To print the instructions, send an array of strings to Sysout.createDialog
 359 WithInstructions method.  Put one line of instructions per array entry.
 360 To display a message for the tester to see, simply call Sysout.println
 361 with the string to be displayed.
 362 This mimics System.out.println but works within the test harness as well
 363 as standalone.
 364  */
 365 class Sysout {
 366 
 367     private static TestDialog dialog;
 368 
 369     public static void createDialogWithInstructions(String[] instructions) {
 370         dialog = new TestDialog(new Frame(), "Instructions");
 371         dialog.printInstructions(instructions);
 372         //dialog.setVisible(true);
 373         println("Any messages for the tester will display here.");
 374     }
 375 
 376     public static void createDialog() {
 377         dialog = new TestDialog(new Frame(), "Instructions");
 378         String[] defInstr = {"Instructions will appear here. ", ""};
 379         dialog.printInstructions(defInstr);
 380         //dialog.setVisible(true);
 381         println("Any messages for the tester will display here.");
 382     }
 383 
 384     public static void printInstructions(String[] instructions) {
 385         dialog.printInstructions(instructions);
 386     }
 387 
 388     public static void println(String messageIn) {
 389         dialog.displayMessage(messageIn);
 390         System.out.println(messageIn);
 391     }
 392 }// Sysout  class
 393 
 394 /**
 395 This is part of the standard test machinery.  It provides a place for the
 396 test instructions to be displayed, and a place for interactive messages
 397 to the user to be displayed.
 398 To have the test instructions displayed, see Sysout.
 399 To have a message to the user be displayed, see Sysout.
 400 Do not call anything in this dialog directly.
 401  */
 402 class TestDialog extends Dialog {
 403 
 404     TextArea instructionsText;
 405     TextArea messageText;
 406     int maxStringLength = 80;
 407 
 408     //DO NOT call this directly, go through Sysout
 409     public TestDialog(Frame frame, String name) {
 410         super(frame, name);
 411         int scrollBoth = TextArea.SCROLLBARS_BOTH;
 412         instructionsText = new TextArea("", 15, maxStringLength, scrollBoth);
 413         add("North", instructionsText);
 414 
 415         messageText = new TextArea("", 5, maxStringLength, scrollBoth);
 416         add("Center", messageText);
 417 
 418         pack();
 419 
 420         //setVisible(true);
 421     }// TestDialog()
 422 
 423     //DO NOT call this directly, go through Sysout
 424     public void printInstructions(String[] instructions) {
 425         //Clear out any current instructions
 426         instructionsText.setText("");
 427 
 428         //Go down array of instruction strings
 429 
 430         String printStr, remainingStr;
 431         for (int i = 0; i < instructions.length; i++) {
 432             //chop up each into pieces maxSringLength long
 433             remainingStr = instructions[i];
 434             while (remainingStr.length() > 0) {
 435                 //if longer than max then chop off first max chars to print
 436                 if (remainingStr.length() >= maxStringLength) {
 437                     //Try to chop on a word boundary
 438                     int posOfSpace = remainingStr.lastIndexOf(' ', maxStringLength - 1);
 439 
 440                     if (posOfSpace <= 0) {
 441                         posOfSpace = maxStringLength - 1;
 442                     }
 443 
 444                     printStr = remainingStr.substring(0, posOfSpace + 1);
 445                     remainingStr = remainingStr.substring(posOfSpace + 1);
 446                 } //else just print
 447                 else {
 448                     printStr = remainingStr;
 449                     remainingStr = "";
 450                 }
 451 
 452                 instructionsText.append(printStr + "\n");
 453 
 454             }// while
 455 
 456         }// for
 457 
 458     }//printInstructions()
 459 
 460     //DO NOT call this directly, go through Sysout
 461     public void displayMessage(String messageIn) {
 462         messageText.append(messageIn + "\n");
 463         System.out.println(messageIn);
 464     }
 465 }// TestDialog  class
 466