changeset 11094:a3e180fb1506

Merge
author kcr
date Fri, 03 Aug 2018 05:52:01 -0700
parents ece2be9fd8ff 8451c9f32969
children 4bc2221b491a af0653a867d6
files
diffstat 13 files changed, 700 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Jul 19 11:08:53 2018 +0530
+++ b/.hgtags	Fri Aug 03 05:52:01 2018 -0700
@@ -504,3 +504,4 @@
 26175843fce0ae1710b26f156ac4d6b073f8d08b 11+18
 3617ee7f12416485e113741ce8bca516f67fe7e2 11+19
 21b47529863d9817c2ece0ce1a397eedd10f57ea 11+20
+3527ff907f43f6f0779a70acd23d4e8defa33734 11+21
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/MultipleSelectionModelBase.java	Fri Aug 03 05:52:01 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -751,7 +751,8 @@
                 } else if (size == 1) {
                     _beginChange();
                     int _index = sortedNewIndices.get(0);
-                    _nextAdd(_index, _index + 1);
+                    int indicesIndex = indexOf(_index);
+                    _nextAdd(indicesIndex, indicesIndex + 1);
                     _endChange();
                 } else {
                     _beginChange();
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ColorPickerSkin.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ColorPickerSkin.java	Fri Aug 03 05:52:01 2018 -0700
@@ -129,6 +129,10 @@
 
         pickerColorBox.getChildren().add(colorRect);
         displayNode.setGraphic(pickerColorBox);
+
+        if (control.isShowing()) {
+            show();
+        }
     }
 
 
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxListViewSkin.java	Fri Aug 03 05:52:01 2018 -0700
@@ -34,6 +34,7 @@
 import javafx.beans.WeakInvalidationListener;
 import javafx.beans.property.BooleanProperty;
 import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.value.ObservableValue;
 import javafx.collections.FXCollections;
 import javafx.collections.ListChangeListener;
 import javafx.collections.ObservableList;
@@ -190,6 +191,11 @@
         if (comboBox.isShowing()) {
             show();
         }
+        comboBox.sceneProperty().addListener(o -> {
+            if (((ObservableValue)o).getValue() == null) {
+                comboBox.hide();
+            }
+        });
     }
 
 
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxPopupControl.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxPopupControl.java	Fri Aug 03 05:52:01 2018 -0700
@@ -501,6 +501,8 @@
         getSkinnable().sceneProperty().addListener(o -> {
             if (((ObservableValue)o).getValue() == null) {
                 hide();
+            } else if (getSkinnable().isShowing()) {
+                show();
             }
         });
 
--- a/modules/javafx.controls/src/main/java/javafx/scene/control/skin/DatePickerSkin.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/main/java/javafx/scene/control/skin/DatePickerSkin.java	Fri Aug 03 05:52:01 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -147,6 +147,10 @@
                 hide();
             }
         });
+
+        if (control.isShowing()) {
+            show();
+        }
     }
 
 
--- a/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.controls/src/test/java/test/javafx/scene/control/ListViewTest.java	Fri Aug 03 05:52:01 2018 -0700
@@ -1947,4 +1947,32 @@
 
         sl.dispose();
     }
+
+    @Test
+    public void testEventIndicesOnSelectRange() {
+        ObservableList<String> listItems = FXCollections.observableArrayList("zero", "one", "two", "three");
+        final ListView<String> lv = new ListView<>();
+        lv.setItems(listItems);
+        MultipleSelectionModel<String> sm = lv.getSelectionModel();
+
+        int selected = 1;
+        sm.setSelectionMode(SelectionMode.MULTIPLE);
+        sm.select(selected);
+        sm.getSelectedIndices().addListener((ListChangeListener<Integer>) ch -> {
+            if (ch.next()) {
+                assertEquals("Two items should be selected.", 2, ch.getList().size());
+                assertEquals("Selection range should be from index 1 ", 1, ch.getFrom());
+                assertEquals("Selection range should be till index 2 ", 2, ch.getTo());
+            } else {
+                fail("Change event is expected when selection is changed.");
+            }
+        });
+        int focus = lv.getFocusModel().getFocusedIndex();
+        assertEquals("Selected item should be focused.", selected, focus);
+        // Select the next element
+        sm.selectRange(selected, focus + 2);
+        assertEquals("Two items should be selected.", 2, sm.getSelectedIndices().size());
+        assertEquals("List item at index 1 should be selected", 1, (int) sm.getSelectedIndices().get(0));
+        assertEquals("List item at index 2 should be selected", 2, (int) sm.getSelectedIndices().get(1));
+    }
 }
--- a/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java	Fri Aug 03 05:52:01 2018 -0700
@@ -3041,34 +3041,18 @@
         return Class.forName(className, true, getDefaultClassLoader());
     }
 
-    private static boolean needsClassLoaderPermissionCheck(ClassLoader from, ClassLoader to) {
-        if (from == to) {
+    private static boolean needsClassLoaderPermissionCheck(Class caller) {
+        if (caller == null) {
             return false;
         }
-        if (from == null) {
-            return false;
-        }
-        if (to == null) {
-            return true;
-        }
-        ClassLoader acl = to;
-        do {
-            acl = acl.getParent();
-            if (from == acl) {
-                return false;
-            }
-        } while (acl != null);
-        return true;
+        return !FXMLLoader.class.getModule().equals(caller.getModule());
     }
 
     private static ClassLoader getDefaultClassLoader(Class caller) {
         if (defaultClassLoader == null) {
             final SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
-                final ClassLoader callerClassLoader = (caller != null) ?
-                        caller.getClassLoader() :
-                        null;
-                if (needsClassLoaderPermissionCheck(callerClassLoader, FXMLLoader.class.getClassLoader())) {
+                if (needsClassLoaderPermissionCheck(caller)) {
                     sm.checkPermission(GET_CLASSLOADER_PERMISSION);
                 }
             }
--- a/modules/javafx.graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java	Fri Aug 03 05:52:01 2018 -0700
@@ -197,7 +197,7 @@
                     boolean hasdep = installLibraryFromResource(dep, null, caller, false);
                 }
             }
-            String reallib = "/"+libPrefix+libraryName+libSuffix;
+            String reallib = "/"+System.mapLibraryName(libraryName);
             InputStream is = caller.getResourceAsStream(reallib);
             if (is != null) {
                 String fp = cacheLibrary(is, reallib, caller);
--- a/modules/javafx.swt/src/main/java/javafx/embed/swt/FXCanvas.java	Thu Jul 19 11:08:53 2018 +0530
+++ b/modules/javafx.swt/src/main/java/javafx/embed/swt/FXCanvas.java	Fri Aug 03 05:52:01 2018 -0700
@@ -368,6 +368,21 @@
         Platform.runLater(()-> Application.GetApplication().setName(name));
     }
 
+    // Work around because SWT does not send reparent events but Control#setParent
+    // calls reskin(SWT.ALL) so this implementation detail can be used to update
+    // the current x/y position of the embedded stage
+    //
+    // There are other situations where reskin() is called but they are not frequent
+    // and the only harm is that we potentially recompute the location although it did
+    // not change in reality
+    @Override
+    public void reskin(int flags) {
+        super.reskin(flags);
+        if (flags == SWT.ALL) {
+            sendMoveEventToFX();
+        }
+    }
+
     static ArrayList<DropTarget> targets = new ArrayList<>();
 
     DropTarget getDropTarget() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/robot/javafx/scene/ColorPickerTest.java	Fri Aug 03 05:52:01 2018 -0700
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.robot.javafx.scene;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.control.ColorPicker;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.VBox;
+import javafx.scene.robot.Robot;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.stage.WindowEvent;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.fail;
+
+import test.util.Util;
+
+public class ColorPickerTest {
+
+    static CountDownLatch startupLatch = new CountDownLatch(1);
+    static Robot robot;
+    static volatile Stage stage;
+    static volatile Scene scene;
+    static final int SCENE_WIDTH = 250;
+    static final int SCENE_HEIGHT = SCENE_WIDTH;
+    static VBox root;
+    int onShownCount = 0;
+    int onActionCount = 0;
+    ColorPicker colorPicker;
+    CountDownLatch onShownLatch;
+    CountDownLatch onActionLatch;
+
+    private void mouseClick(double x, double y) {
+        Util.runAndWait(() -> {
+            robot.mouseMove((int) (scene.getWindow().getX() + scene.getX() + x),
+                    (int) (scene.getWindow().getY() + scene.getY() + y));
+            robot.mousePress(MouseButton.PRIMARY);
+            robot.mouseRelease(MouseButton.PRIMARY);
+        });
+    }
+
+    private void showColorPickerPalette() throws Exception {
+        onShownLatch = new CountDownLatch(1);
+        mouseClick(colorPicker.getLayoutX() + colorPicker.getWidth() - 15,
+                    colorPicker.getLayoutY() + colorPicker.getHeight() / 2);
+        Thread.sleep(400); // ColorPicker takes some time to display the color palette.
+        waitForLatch(onShownLatch, 10, "Failed to show color palette.");
+    }
+
+    private void clickColorPickerPalette(int yFactor) throws Exception {
+        onActionLatch = new CountDownLatch(1);
+        mouseClick(colorPicker.getLayoutX() + colorPicker.getWidth() / 2,
+                    colorPicker.getLayoutY() + colorPicker.getHeight() * yFactor);
+        Thread.sleep(400);
+        waitForLatch(onActionLatch, 10, "Failed to receive onAction callback.");
+    }
+
+    // This test is for verifying a specific behavior.
+    // 1. Remove ColorPicker, call ColorPicker.show() & add back ColorPicker.
+    // 2. Verify that the ColorPicker palette is shown using onShown,
+    // 2.1 Confirm that color palette is shown, using listener onAction.
+    // 3. Click on ColorPicker, color palette should get shown.
+    // 4. Repeat step 2.
+    // 4.1 Repeat step 2.1
+    // 5. Click on ColorPicker, color palette should get shown.
+    // 6. Remove & add back ColorPicker, color palette should get shown.
+    // 7. Confirm that color palette is shown, using listener onAction.
+
+    @Test
+    public void testColorPickerSceneChange() throws Exception {
+        Thread.sleep(1000); // Wait for stage to layout
+
+        // 1.
+        onShownLatch = new CountDownLatch(1);
+        Util.runAndWait(() -> {
+            root.getChildren().clear();
+            colorPicker.show();
+            root.getChildren().add(colorPicker);
+        });
+        waitForLatch(onShownLatch, 10, "Failed to show color palette.");
+        Thread.sleep(400); // ColorPicker takes some time to display the color palette.
+        // 2.
+        Assert.assertEquals("ColorPicker palette should be shown once.", 1, onShownCount);
+
+        // 2.1
+        clickColorPickerPalette(5);
+        Assert.assertEquals("ColorPicker palette should be clicked once.", 1, onActionCount);
+
+        // 3.
+        showColorPickerPalette();
+        // 4.
+        Assert.assertEquals("ColorPicker palette should have been shown two times.", 2, onShownCount);
+
+        // 4.1
+        clickColorPickerPalette(6);
+        Assert.assertEquals("ColorPicker palette have been clicked two times.", 2, onActionCount);
+
+        // 5.
+        showColorPickerPalette();
+        Assert.assertEquals("ColorPicker palette should have been shown three times.", 3, onShownCount);
+
+        // 6.
+        Util.runAndWait(() -> {
+            root.getChildren().clear();
+            root.getChildren().add(colorPicker);
+        });
+        Thread.sleep(400); // ColorPicker takes some time to display the color palette.
+
+        // 7.
+        clickColorPickerPalette(5);
+        Assert.assertEquals("ColorPicker palette should have been clicked three times.", 3, onActionCount);
+    }
+
+    @After
+    public void resetUI() {
+        Platform.runLater(() -> {
+            colorPicker.setOnShown(null);
+            colorPicker.setOnAction(null);
+            root.getChildren().clear();
+        });
+    }
+
+    @Before
+    public void setupUI() {
+        Platform.runLater(() -> {
+            colorPicker = new ColorPicker();
+            colorPicker.setOnShown(event -> {
+                onShownCount++;
+                onShownLatch.countDown();
+            });
+            colorPicker.setOnAction(event -> {
+                onActionCount++;
+                onActionLatch.countDown();
+            });
+            root.getChildren().add(colorPicker);
+        });
+    }
+
+    @BeforeClass
+    public static void initFX() throws Exception {
+        new Thread(() -> Application.launch(TestApp.class, (String[])null)).start();
+        waitForLatch(startupLatch, 10, "FX runtime failed to start.");
+    }
+
+    @AfterClass
+    public static void exit() {
+        Platform.runLater(() -> {
+            stage.hide();
+        });
+        Platform.exit();
+    }
+
+    public static class TestApp extends Application {
+        @Override
+        public void start(Stage primaryStage) {
+            robot = new Robot();
+            stage = primaryStage;
+            root = new VBox();
+            scene = new Scene(root, SCENE_WIDTH, SCENE_HEIGHT);
+            stage.setScene(scene);
+            stage.initStyle(StageStyle.UNDECORATED);
+            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e ->
+                    Platform.runLater(startupLatch::countDown));
+            stage.setAlwaysOnTop(true);
+            stage.show();
+        }
+    }
+
+    public static void waitForLatch(CountDownLatch latch, int seconds, String msg) throws Exception {
+        Assert.assertTrue("Timeout: " + msg, latch.await(seconds, TimeUnit.SECONDS));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/robot/javafx/scene/ComboBoxTest.java	Fri Aug 03 05:52:01 2018 -0700
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.robot.javafx.scene;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.beans.value.ChangeListener;
+import javafx.scene.control.ComboBox;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.VBox;
+import javafx.scene.robot.Robot;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.stage.WindowEvent;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.fail;
+
+import test.util.Util;
+
+public class ComboBoxTest {
+
+    static CountDownLatch startupLatch = new CountDownLatch(1);
+    static Robot robot;
+    static volatile Stage stage;
+    static volatile Scene scene;
+    static final int SCENE_WIDTH = 200;
+    static final int SCENE_HEIGHT = SCENE_WIDTH;
+    static VBox root;
+    int onShownCount = 0;
+    int onSelectedCount = 0;
+    final int ITEM_COUNT = 2;
+    ComboBox comboBox;
+    CountDownLatch showLatch;
+    CountDownLatch selectedLatch;
+
+    private void mouseClick(double x, double y) {
+        Util.runAndWait(() -> {
+            robot.mouseMove((int) (scene.getWindow().getX() + scene.getX() + x),
+                    (int) (scene.getWindow().getY() + scene.getY() + y));
+            robot.mousePress(MouseButton.PRIMARY);
+            robot.mouseRelease(MouseButton.PRIMARY);
+        });
+    }
+    // This test is for verifying a specific behavior.
+    // 1. Click ComboBox to show the popup list.
+    // 2. Click a choice to select.
+    // 3. Remove ComboBox and call ComboBox.show() and add it back to scene when a choice is selected.
+    // 4. Verify that the ComboBox functions correctly after adding back.
+    @Test
+    public void testComboBoxSceneChange1() throws Exception {
+        Thread.sleep(1000); // Wait for stage to layout
+        comboBox.setOnShown(event -> {
+            onShownCount++;
+            showLatch.countDown();
+        });
+        ChangeListener chListener = (observable, oldValue, newValue) -> {
+            onSelectedCount++;
+            root.getChildren().clear();
+            comboBox.show();
+            // Called ITEM_COUNT times.
+            root.getChildren().add(comboBox);
+            selectedLatch.countDown();
+        };
+        comboBox.getSelectionModel().selectedItemProperty().addListener(chListener);
+        showLatch = new CountDownLatch(1);
+
+        // Show ComboBox popup list. popup list shown once by mouse click. (ITEM_COUNT + 1)
+        mouseClick(comboBox.getLayoutX() + comboBox.getWidth() / 2,
+                    comboBox.getLayoutY() + comboBox.getHeight() / 2);
+
+        for (int i = 0; i < ITEM_COUNT; i++) {
+            Thread.sleep(300); // ComboBox is removed and added back. Time for layout.
+            waitForLatch(showLatch, 10, "Failed to show ComboBox popup list. " + i);
+            showLatch = new CountDownLatch(1);
+            selectedLatch = new CountDownLatch(1);
+            final int k = i;
+            // Select a choice.
+            mouseClick(comboBox.getLayoutX() + comboBox.getWidth() / 2,
+                        comboBox.getLayoutY() + comboBox.getHeight() * (k + 1.2f));
+
+            waitForLatch(selectedLatch, 10, "Failed to select " + i + "th choice.");
+        }
+        Assert.assertEquals("ComboBox popup list should have been displayed " +
+            (ITEM_COUNT + 1) + " times.", (ITEM_COUNT + 1), onShownCount);
+        Assert.assertEquals("ComboBox choice should have been selected " +
+            ITEM_COUNT + " times.", ITEM_COUNT, onSelectedCount);
+    }
+
+    // This test is for verifying a specific behavior.
+    // 1. Click ComboBox to show the popup list.
+    // 2. Click a choice to select.
+    // 3. Remove ComboBox and add it back to scene when a choice is selected.
+    // 4. Verify that the ComboBox functions correctly after adding back.
+    @Test
+    public void testComboBoxSceneChange2() throws Exception {
+        Thread.sleep(1000); // Wait for stage to layout
+        comboBox.setOnShown(event -> {
+            onShownCount++;
+            showLatch.countDown();
+        });
+        ChangeListener chListener = (observable, oldValue, newValue) -> {
+            onSelectedCount++;
+            root.getChildren().clear();
+            root.getChildren().add(comboBox);
+            selectedLatch.countDown();
+        };
+        comboBox.getSelectionModel().selectedItemProperty().addListener(chListener);
+        for (int i = 0; i < ITEM_COUNT; i++) {
+            Thread.sleep(300); // ComboBox is removed and added back. Time for layout.
+            showLatch = new CountDownLatch(1);
+            selectedLatch = new CountDownLatch(1);
+
+            // Show ComboBox popup list.
+            mouseClick(comboBox.getLayoutX() + comboBox.getWidth() / 2,
+                    comboBox.getLayoutY() + comboBox.getHeight() / 2);
+
+            Thread.sleep(200); // ComboBox takes some time to display the popup list.
+            waitForLatch(showLatch, 10, "Failed to show ComboBox popup list. " + i);
+            final int k = i;
+            // Select a choice.
+            mouseClick(comboBox.getLayoutX() + comboBox.getWidth() / 2,
+                        comboBox.getLayoutY() + comboBox.getHeight() * (k + 1.2f));
+
+            waitForLatch(selectedLatch, 10, "Failed to select " + i + "th choice.");
+        }
+        Assert.assertEquals("ComboBox popup list should be displayed " +
+            ITEM_COUNT + " times.", ITEM_COUNT, onShownCount);
+        Assert.assertEquals("ComboBox choice should have been selected " +
+            ITEM_COUNT + " times.", ITEM_COUNT, onSelectedCount);
+    }
+
+    @After
+    public void resetUI() {
+        Util.runAndWait(() -> {
+            root.getChildren().clear();
+        });
+    }
+
+    @Before
+    public void setupUI() {
+        Util.runAndWait(() -> {
+            comboBox = new ComboBox();
+            for (int i = 0; i < ITEM_COUNT; i++) {
+                comboBox.getItems().add("Op" + i);
+            }
+            root.getChildren().add(comboBox);
+            onShownCount = 0;
+            onSelectedCount = 0;
+        });
+    }
+
+    @BeforeClass
+    public static void initFX() throws Exception {
+        new Thread(() -> Application.launch(TestApp.class, (String[])null)).start();
+        waitForLatch(startupLatch, 10, "FX runtime failed to start.");
+    }
+
+    @AfterClass
+    public static void exit() {
+        Util.runAndWait(() -> {
+            stage.hide();
+        });
+        Platform.exit();
+    }
+
+    public static class TestApp extends Application {
+        @Override
+        public void start(Stage primaryStage) {
+            robot = new Robot();
+            stage = primaryStage;
+            root = new VBox();
+            scene = new Scene(root, SCENE_WIDTH, SCENE_HEIGHT);
+            stage.setScene(scene);
+            stage.initStyle(StageStyle.UNDECORATED);
+            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e ->
+                    Platform.runLater(startupLatch::countDown));
+            stage.setAlwaysOnTop(true);
+            stage.show();
+        }
+    }
+
+    public static void waitForLatch(CountDownLatch latch, int seconds, String msg) throws Exception {
+        Assert.assertTrue("Timeout: " + msg, latch.await(seconds, TimeUnit.SECONDS));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/system/src/test/java/test/robot/javafx/scene/DatePickerTest.java	Fri Aug 03 05:52:01 2018 -0700
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test.robot.javafx.scene;
+
+import com.sun.javafx.PlatformUtil;
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.scene.Scene;
+import javafx.scene.control.DatePicker;
+import javafx.scene.input.MouseButton;
+import javafx.scene.layout.VBox;
+import javafx.scene.robot.Robot;
+import javafx.stage.Stage;
+import javafx.stage.StageStyle;
+import javafx.stage.WindowEvent;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import test.util.Util;
+
+public class DatePickerTest {
+
+    static CountDownLatch startupLatch = new CountDownLatch(1);
+    static Robot robot;
+    static volatile Stage stage;
+    static volatile Scene scene;
+    static final int SCENE_WIDTH = 250;
+    static final int SCENE_HEIGHT = SCENE_WIDTH;
+    static VBox root;
+    int onShownCount = 0;
+    int onActionCount = 0;
+    DatePicker datePicker;
+    CountDownLatch onShownLatch;
+    CountDownLatch onActionLatch;
+
+    private void mouseClick(double x, double y) {
+        Util.runAndWait(() -> {
+            robot.mouseMove((int) (scene.getWindow().getX() + scene.getX() + x),
+                    (int) (scene.getWindow().getY() + scene.getY() + y));
+            robot.mousePress(MouseButton.PRIMARY);
+            robot.mouseRelease(MouseButton.PRIMARY);
+        });
+    }
+
+    private void showDatePickerCalendarPopup() throws Exception {
+        onShownLatch = new CountDownLatch(1);
+        mouseClick(datePicker.getLayoutX() + datePicker.getWidth() - 15,
+                    datePicker.getLayoutY() + datePicker.getHeight() / 2);
+        Thread.sleep(400); // DatePicker takes some time to display the calendar popup.
+        waitForLatch(onShownLatch, 10, "Failed to show Calendar popup.");
+    }
+
+    private void clickDatePickerCalendarPopup(int yFactor) throws Exception {
+        onActionLatch = new CountDownLatch(1);
+        mouseClick(datePicker.getLayoutX() + datePicker.getWidth() / 2,
+                    datePicker.getLayoutY() + datePicker.getHeight() * yFactor);
+        Thread.sleep(400);
+        waitForLatch(onActionLatch, 10, "Failed to receive onAction call.");
+    }
+
+    // This test is for verifying a specific behavior.
+    // 1. Remove DatePicker, call DatePicker.show() & add back DatePicker.
+    // 2. Verify that the DatePicker calendar popup is shown using onShown,
+    // 2.1 Confirm that calendar popup is shown, using listener onAction.
+    // 3. Click on DatePicker, calendar popup should get shown.
+    // 4. Repeat step 2.
+    // 4.1 Repeat step 2.1
+    // 5. Click on DatePicker, calendar popup should get shown.
+    // 6. Remove & add back DatePicker, calendar popup should get shown.
+    // 7. Confirm that calendar popup is shown, using listener onAction.
+
+    @Test
+    public void testDatePickerSceneChange() throws Exception {
+        // Disable on mac untill JDK-8208523 is fixed.
+        assumeTrue(!PlatformUtil.isMac());
+        Thread.sleep(1000); // Wait for stage to layout
+
+        // 1.
+        onShownLatch = new CountDownLatch(1);
+        Util.runAndWait(() -> {
+            root.getChildren().clear();
+            datePicker.show();
+            root.getChildren().add(datePicker);
+        });
+        waitForLatch(onShownLatch, 10, "Failed to show calendar popup.");
+        Thread.sleep(400); // DatePicker takes some time to display the calendar popup.
+        // 2.
+        Assert.assertEquals("DatePicker calendar popup should be shown once.", 1, onShownCount);
+
+        // 2.1
+        clickDatePickerCalendarPopup(5);
+        Assert.assertEquals("DatePicker calendar popup should be clicked once.", 1, onActionCount);
+
+        // 3.
+        showDatePickerCalendarPopup();
+        // 4.
+        Assert.assertEquals("DatePicker calendar popup should have been shown two times.", 2, onShownCount);
+
+        // 4.1
+        clickDatePickerCalendarPopup(6);
+        Assert.assertEquals("DatePicker calendar popup have been clicked two times.", 2, onActionCount);
+
+        // 5.
+        showDatePickerCalendarPopup();
+        Assert.assertEquals("DatePicker calendar popup should have been shown three times.", 3, onShownCount);
+
+        // 6.
+        Util.runAndWait(() -> {
+            root.getChildren().clear();
+            root.getChildren().add(datePicker);
+        });
+        Thread.sleep(400); // DatePicker takes some time to display the calendar popup.
+
+        // 7.
+        clickDatePickerCalendarPopup(5);
+        Assert.assertEquals("DatePicker calendar popup should have been clicked three times.", 3, onActionCount);
+    }
+
+    @After
+    public void resetUI() {
+        Platform.runLater(() -> {
+            datePicker.setOnShown(null);
+            datePicker.setOnAction(null);
+            root.getChildren().clear();
+        });
+    }
+
+    @Before
+    public void setupUI() {
+        Platform.runLater(() -> {
+            datePicker = new DatePicker();
+            datePicker.setOnShown(event -> {
+                onShownCount++;
+                onShownLatch.countDown();
+            });
+            datePicker.setOnAction(event -> {
+                onActionCount++;
+                onActionLatch.countDown();
+            });
+            root.getChildren().add(datePicker);
+        });
+    }
+
+    @BeforeClass
+    public static void initFX() throws Exception {
+        new Thread(() -> Application.launch(TestApp.class, (String[])null)).start();
+        waitForLatch(startupLatch, 10, "FX runtime failed to start.");
+    }
+
+    @AfterClass
+    public static void exit() {
+        Platform.runLater(() -> {
+            stage.hide();
+        });
+        Platform.exit();
+    }
+
+    public static class TestApp extends Application {
+        @Override
+        public void start(Stage primaryStage) {
+            robot = new Robot();
+            stage = primaryStage;
+            root = new VBox();
+            scene = new Scene(root, SCENE_WIDTH, SCENE_HEIGHT);
+            stage.setScene(scene);
+            stage.initStyle(StageStyle.UNDECORATED);
+            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e ->
+                    Platform.runLater(startupLatch::countDown));
+            stage.setAlwaysOnTop(true);
+            stage.show();
+        }
+    }
+
+    public static void waitForLatch(CountDownLatch latch, int seconds, String msg) throws Exception {
+        Assert.assertTrue("Timeout: " + msg, latch.await(seconds, TimeUnit.SECONDS));
+    }
+}