1 /*
  2  * Copyright (c) 2019, 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 package test.javafx.embed.swing;
 26 
 27 import com.sun.javafx.PlatformUtil;
 28 import org.junit.Assume;
 29 import org.junit.Assert;
 30 import org.junit.BeforeClass;
 31 import org.junit.AfterClass;
 32 import org.junit.Test;
 33 import junit.framework.AssertionFailedError;
 34 
 35 import javax.swing.JFrame;
 36 import javax.swing.JMenu;
 37 import javax.swing.JMenuItem;
 38 import javax.swing.JMenuBar;
 39 import javax.swing.JPanel;
 40 import javax.swing.SwingUtilities;
 41 import javafx.application.Application;
 42 import javafx.application.Platform;
 43 import javafx.embed.swing.JFXPanel;
 44 import javafx.stage.Stage;
 45 import javafx.scene.Group;
 46 import javafx.scene.Scene;
 47 import java.awt.Dimension;
 48 import java.awt.event.InputEvent;
 49 import java.awt.event.MouseEvent;
 50 import java.util.concurrent.CountDownLatch;
 51 import java.util.concurrent.TimeUnit;
 52 
 53 public class JFXPanelTest {
 54     // Used to launch the application before running any test
 55     private static final CountDownLatch launchLatch = new CountDownLatch(1);
 56 
 57     // Application class. An instance is created and initialized before running
 58     // the first test, and it lives through the execution of all tests.
 59     public static class MyApp extends Application {
 60         @Override
 61         public void start(Stage primaryStage) throws Exception {
 62             Platform.setImplicitExit(false);
 63             Assert.assertTrue(Platform.isFxApplicationThread());
 64             Assert.assertNotNull(primaryStage);
 65 
 66             launchLatch.countDown();
 67         }
 68     }
 69 
 70     @BeforeClass
 71     public static void doSetupOnce() throws Exception {
 72         // Start the Application
 73         new Thread(() -> Application.launch(MyApp.class, (String[]) null)).start();
 74 
 75         if (!launchLatch.await(5000, TimeUnit.MILLISECONDS)) {
 76             throw new AssertionFailedError("Timeout waiting for Application to launch");
 77         }
 78 
 79         Assert.assertEquals(0, launchLatch.getCount());
 80     }
 81 
 82     @AfterClass
 83     public static void doTeardownOnce() {
 84         Platform.exit();
 85     }
 86 
 87     static class TestFXPanel extends JFXPanel {
 88         protected void processMouseEventPublic(MouseEvent e) {
 89             processMouseEvent(e);
 90         }
 91     };
 92 
 93     @Test
 94     public void testNoDoubleClickOnFirstClick() throws Exception {
 95 
 96         CountDownLatch firstPressedEventLatch = new CountDownLatch(1);
 97 
 98         // It's an array, so we can mutate it inside of lambda statement
 99         int[] pressedEventCounter = {0};
100 
101         SwingUtilities.invokeLater(() -> {
102             TestFXPanel dummyFXPanel = new TestFXPanel();
103             dummyFXPanel.setPreferredSize(new Dimension(100, 100));
104             TestFXPanel fxPnl = new TestFXPanel();
105             fxPnl.setPreferredSize(new Dimension(100, 100));
106             JFrame jframe = new JFrame();
107             JPanel jpanel = new JPanel();
108             jpanel.add(dummyFXPanel);
109             jpanel.add(fxPnl);
110             jframe.setContentPane(jpanel);
111             jframe.pack();
112             jframe.setVisible(true);
113 
114             Platform.runLater(() -> {
115                 Scene dummyScene = new Scene(new Group());
116                 dummyFXPanel.setScene(dummyScene);
117                 Scene scene = new Scene(new Group());
118                 fxPnl.setScene(scene);
119 
120                 scene.addEventHandler(javafx.scene.input.MouseEvent.MOUSE_PRESSED, (event -> {
121                     pressedEventCounter[0] += 1;
122                     firstPressedEventLatch.countDown();
123                 }));
124 
125                 SwingUtilities.invokeLater(() -> {
126                     MouseEvent e = new MouseEvent(fxPnl, MouseEvent.MOUSE_PRESSED, 0, MouseEvent.BUTTON1_DOWN_MASK,
127                             5, 5, 1, false, MouseEvent.BUTTON1);
128 
129                     fxPnl.processMouseEventPublic(e);
130                 });
131             });
132         });
133 
134         Assert.assertTrue(firstPressedEventLatch.await(5000, TimeUnit.MILLISECONDS));
135 
136         Thread.sleep(500); // there should be no pressed event after the initial one. Let's wait for 0.5s and check again.
137 
138         Assert.assertEquals(1, pressedEventCounter[0]);
139     }
140 
141     @Test
142     public void testClickOnEmptyJFXPanel() throws Exception {
143         CountDownLatch firstPressedEventLatch = new CountDownLatch(1);
144 
145         SwingUtilities.invokeLater(() -> {
146             TestFXPanel fxPnl = new TestFXPanel();
147 
148             MouseEvent e = new MouseEvent(fxPnl, MouseEvent.MOUSE_PRESSED, 0, MouseEvent.BUTTON1_DOWN_MASK,
149                     5, 5, 1, false, MouseEvent.BUTTON1);
150 
151             fxPnl.processMouseEventPublic(e);
152 
153             firstPressedEventLatch.countDown();
154         });
155 
156         Assert.assertTrue(firstPressedEventLatch.await(5000, TimeUnit.MILLISECONDS));
157     }
158 }
159