1 /*
   2  * Copyright (c) 2014, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package test.renderlock;
  27 
  28 import com.sun.javafx.PlatformUtil;
  29 import java.util.concurrent.CountDownLatch;
  30 import java.util.concurrent.TimeUnit;
  31 import java.util.concurrent.atomic.AtomicReference;
  32 import javafx.animation.FillTransition;
  33 import javafx.animation.Timeline;
  34 import javafx.application.Application;
  35 import javafx.application.Platform;
  36 import javafx.scene.Group;
  37 import javafx.scene.Scene;
  38 import javafx.scene.control.Alert;
  39 import javafx.scene.control.Button;
  40 import javafx.scene.control.ButtonType;
  41 import javafx.scene.layout.VBox;
  42 import javafx.scene.paint.Color;
  43 import javafx.scene.shape.Rectangle;
  44 import javafx.stage.Stage;
  45 import javafx.util.Duration;
  46 import junit.framework.AssertionFailedError;
  47 import org.junit.AfterClass;
  48 import org.junit.BeforeClass;
  49 import test.util.Util;
  50 
  51 import static org.junit.Assert.*;
  52 import static org.junit.Assume.*;
  53 import static test.util.Util.TIMEOUT;
  54 
  55 /**
  56  * Common base class for testing snapshot.
  57  */
  58 public class RenderLockCommon {
  59 
  60     // Sleep time showing/hiding window in milliseconds
  61     private static final int SLEEP_TIME = 1000;
  62 
  63     // Used to launch the application before running any test
  64     private static final CountDownLatch launchLatch = new CountDownLatch(1);
  65 
  66     // Singleton Application instance
  67     static MyApp myApp;
  68 
  69     // Application class. An instance is created and initialized before running
  70     // the first test, and it lives through the execution of all tests.
  71     public static class MyApp extends Application {
  72         Stage primaryStage;
  73 
  74         @Override public void init() {
  75             RenderLockCommon.myApp = this;
  76         }
  77 
  78         @Override public void start(Stage primaryStage) throws Exception {
  79             assertTrue(Platform.isFxApplicationThread());
  80             primaryStage.setTitle("Primary stage");
  81             Rectangle rect = new Rectangle(100, 50);
  82             FillTransition trans = new FillTransition(Duration.millis(500),
  83                     rect, Color.BLUE, Color.VIOLET);
  84             trans.setCycleCount(Timeline.INDEFINITE);
  85             trans.setAutoReverse(true);
  86             trans.play();
  87             Group root = new Group(rect);
  88             Scene scene = new Scene(root);
  89             scene.setFill(Color.LIGHTYELLOW);
  90             primaryStage.setScene(scene);
  91             primaryStage.setX(0);
  92             primaryStage.setY(0);
  93             primaryStage.setWidth(210);
  94             primaryStage.setHeight(180);
  95             assertFalse(primaryStage.isShowing());
  96             primaryStage.show();
  97             assertTrue(primaryStage.isShowing());
  98 
  99             this.primaryStage = primaryStage;
 100             launchLatch.countDown();
 101         }
 102     }
 103 
 104     @BeforeClass
 105     public static void doSetupOnce() throws Exception {
 106         // These tests are only valid on Windows and Mac.
 107         // On Linux the closing of the window does not trigger a
 108         // focusLost event with the lock held
 109         assumeTrue(PlatformUtil.isMac() || PlatformUtil.isWindows());
 110 
 111         // Start the Application
 112         new Thread(() -> Application.launch(MyApp.class, (String[])null)).start();
 113 
 114         if (!launchLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
 115             fail("Timeout waiting for Application to launch");
 116         }
 117 
 118         assertEquals(0, launchLatch.getCount());
 119     }
 120 
 121     @AfterClass
 122     public static void doTeardownOnce() {
 123         Platform.exit();
 124     }
 125 
 126     // ========================== TEST CASES ==========================
 127 
 128     private Stage testStage;
 129 
 130     protected void doWindowCloseTest() throws Exception {
 131         final CountDownLatch alertDoneLatch = new CountDownLatch(1);
 132         final AtomicReference<ButtonType> alertResult = new AtomicReference<>();
 133 
 134         Util.runAndWait(() -> {
 135             Button button1 = new Button("The Button");
 136             button1.focusedProperty().addListener((obs, oldValue, newValue) -> {
 137                 if (!newValue) {
 138                     //System.err.println("lost focus");
 139                     final Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
 140                     Thread t = new Thread(() -> {
 141                         Util.sleep(SLEEP_TIME);
 142                         //System.err.println("scheduling runLater to hide alert");
 143                         Platform.runLater(() -> {
 144                             //System.err.println("Calling alert.hide");
 145                             alert.hide();
 146                         });
 147                     });
 148                     t.start();
 149                     ButtonType result = alert.showAndWait().get();
 150                     alertResult.set(result);
 151                     alertDoneLatch.countDown();
 152                     //System.err.println("result = " + result);
 153                     //System.err.println("focus listener exit");
 154                 }
 155             });
 156 
 157             Button button2 = new Button("Other Button");
 158 
 159             testStage = new Stage();
 160             testStage.setScene(new Scene(new VBox(button1, button2), 400, 300));
 161             button1.requestFocus();
 162             testStage.requestFocus();
 163             testStage.show();
 164         });
 165 
 166         Util.sleep(SLEEP_TIME);
 167         //System.err.println("scheduling runLater to hide otherStage");
 168         Platform.runLater(() -> {
 169             //System.err.println("Calling otherStage.hide");
 170             testStage.hide();
 171         });
 172 
 173         // Wait for results
 174         if (!alertDoneLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
 175             fail("Timeout waiting for alert to be hidden");
 176         }
 177 
 178         assertSame(ButtonType.CANCEL, alertResult.get());
 179     }
 180 
 181 }