diff --git a/apps/experiments/ConferenceScheduleApp/src/main/java/com/javafx/experiments/scheduleapp/pages/SpeakersPage.java b/apps/experiments/ConferenceScheduleApp/src/main/java/com/javafx/experiments/scheduleapp/pages/SpeakersPage.java --- a/apps/experiments/ConferenceScheduleApp/src/main/java/com/javafx/experiments/scheduleapp/pages/SpeakersPage.java +++ b/apps/experiments/ConferenceScheduleApp/src/main/java/com/javafx/experiments/scheduleapp/pages/SpeakersPage.java @@ -140,9 +140,7 @@ // hardware layer support. This code will just move the keyboard out of the way. searchBox.focusedProperty().addListener(new InvalidationListener() { @Override public void invalidated(Observable observable) { - Iterator itr = Window.impl_getWindows(); - while (itr.hasNext()) { - Window win = itr.next(); + for (Window win : Window.getWindows()) { Object obj = win.getScene().getRoot().lookup(".fxvk"); if (obj instanceof FXVK) { FXVK keyboard = (FXVK) obj; diff --git a/apps/toys/Hello/src/main/java/hello/HelloPopup.java b/apps/toys/Hello/src/main/java/hello/HelloPopup.java --- a/apps/toys/Hello/src/main/java/hello/HelloPopup.java +++ b/apps/toys/Hello/src/main/java/hello/HelloPopup.java @@ -128,11 +128,10 @@ } nextPopup.show(popupParent, popupX, popupY); - - Iterator windows = Window.impl_getWindows(); - while (windows.hasNext()) { - System.out.println("W: " + windows.next().getClass().getName()); - } + + Window.getWindows().stream().forEach(window -> { + System.out.println("W: " + window.getClass().getName()); + }); } } diff --git a/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java b/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java --- a/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java +++ b/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java @@ -855,14 +855,12 @@ */ public void pauseScenes() { pauseScenesLatch = new CountDownLatch(1); - Iterator i = Window.impl_getWindows(); - while (i.hasNext()) { - final Window w = i.next(); - final Scene scene = w.getScene(); + Window.getWindows().stream().forEach(window -> { + final Scene scene = window.getScene(); if (scene != null) { this.removeSceneTkPulseListener(scene.impl_getScenePulseListener()); } - } + }); this.getMasterTimer().pause(); SceneHelper.setPaused(true); } @@ -874,14 +872,12 @@ public void resumeScenes() { SceneHelper.setPaused(false); this.getMasterTimer().resume(); - Iterator i = Window.impl_getWindows(); - while (i.hasNext()) { - final Window w = i.next(); - final Scene scene = w.getScene(); + Window.getWindows().stream().forEach(window -> { + final Scene scene = window.getScene(); if (scene != null) { this.addSceneTkPulseListener(scene.impl_getScenePulseListener()); } - } + }); pauseScenesLatch.countDown(); pauseScenesLatch = null; } diff --git a/modules/graphics/src/main/java/javafx/stage/Window.java b/modules/graphics/src/main/java/javafx/stage/Window.java --- a/modules/graphics/src/main/java/javafx/stage/Window.java +++ b/modules/graphics/src/main/java/javafx/stage/Window.java @@ -28,9 +28,12 @@ import java.security.AllPermission; import java.security.AccessControlContext; import java.security.AccessController; +import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection; import javafx.beans.property.DoubleProperty; import javafx.beans.property.DoublePropertyBase; import javafx.beans.property.ObjectProperty; @@ -43,6 +46,7 @@ import javafx.beans.property.ReadOnlyDoubleWrapper; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; +import javafx.collections.ObservableList; import javafx.collections.ObservableMap; import javafx.event.Event; import javafx.event.EventDispatchChain; @@ -77,9 +81,10 @@ public class Window implements EventTarget { /** - * A list of all the currently existing windows. This is only used by SQE for testing. + * A list of all the currently _showing_ windows. This is publicly accessible via the unmodifiableWindows wrapper. */ - private static WeakReferenceQueuewindowQueue = new WeakReferenceQueue(); + private static ObservableList windows = FXCollections.observableArrayList(); + private static ObservableList unmodifiableWindows = FXCollections.unmodifiableObservableList(windows); static { WindowHelper.setWindowAccessor( @@ -134,20 +139,20 @@ } /** - * Return all Windows + * Returns a list containing a reference to the currently showing JavaFX windows. The list is unmodifiable - + * attempting to modify this list will result in an {@link UnsupportedOperationException} being thrown at runtime. * - * @return Iterator of all Windows - * @treatAsPrivate implementation detail - * @deprecated This is an internal API that is not intended for use and will be removed in the next version + * @return A list containing all windows that are currently showing. + * @since 9 */ - @Deprecated - public static Iterator impl_getWindows() { + @ReturnsUnmodifiableCollection + public static ObservableList getWindows() { final SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new AllPermission()); } - return (Iterator) windowQueue.iterator(); + return unmodifiableWindows; } final AccessControlContext acc = AccessController.getContext(); @@ -824,9 +829,9 @@ impl_visibleChanging(newVisible); if (newVisible) { hasBeenVisible = true; - windowQueue.add(Window.this); + windows.add(Window.this); } else { - windowQueue.remove(Window.this); + windows.remove(Window.this); } Toolkit tk = Toolkit.getToolkit(); if (impl_peer != null) { diff --git a/modules/graphics/src/test/java/test/javafx/stage/WindowTest.java b/modules/graphics/src/test/java/test/javafx/stage/WindowTest.java --- a/modules/graphics/src/test/java/test/javafx/stage/WindowTest.java +++ b/modules/graphics/src/test/java/test/javafx/stage/WindowTest.java @@ -28,9 +28,12 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.assertNotNull; + +import javafx.beans.InvalidationListener; import javafx.beans.property.DoubleProperty; import javafx.beans.property.SimpleDoubleProperty; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -41,6 +44,8 @@ import javafx.stage.Stage; import javafx.stage.Window; +import java.util.concurrent.atomic.AtomicInteger; + public final class WindowTest { private StubToolkit toolkit; private Stage testWindow; @@ -51,6 +56,12 @@ testWindow = new Stage(); } + @After + public void afterTest() { + testWindow.hide(); + testWindow = null; + } + @Test public void testOpacityBind() { final DoubleProperty variable = new SimpleDoubleProperty(0.5); @@ -97,4 +108,60 @@ assertTrue(unkPeer instanceof StubStage); return (StubStage) unkPeer; } + + @Test public void testGetWindowsIsObservable() { + AtomicInteger windowCount = new AtomicInteger(0); + InvalidationListener listener = o -> windowCount.set(Window.getWindows().size()); + + Window.getWindows().addListener(listener); + + assertEquals(0, windowCount.get()); + + testWindow.show(); + assertEquals(1, windowCount.get()); + + Stage anotherTestWindow = new Stage(); + anotherTestWindow.show(); + assertEquals(2, windowCount.get()); + + testWindow.hide(); + assertEquals(1, windowCount.get()); + + anotherTestWindow.hide(); + assertEquals(0, windowCount.get()); + + Window.getWindows().removeListener(listener); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetWindowsIsUnmodifiable_add() { + Stage anotherTestWindow = new Stage(); + Window.getWindows().add(anotherTestWindow); + } + + @Test(expected = UnsupportedOperationException.class) + public void testGetWindowsIsUnmodifiable_removeShowingWindow() { + testWindow.show(); + Window.getWindows().remove(testWindow); + } + + // There is no UOE here because the window being removed is not in the list of windows, + // so no modification of the windows list occurs. + @Test public void testGetWindowsIsUnmodifiable_removeNonShowingWindow_emptyList() { + Stage anotherTestWindow = new Stage(); + Window.getWindows().remove(anotherTestWindow); + } + + // There is no UOE here because the window being removed is not in the list of windows, + // so no modification of the windows list occurs. + @Test public void testGetWindowsIsUnmodifiable_removeNonShowingWindow_nonEmptyList() { + testWindow.show(); + assertEquals(1, Window.getWindows().size()); + + Stage anotherTestWindow = new Stage(); + assertEquals(1, Window.getWindows().size()); + + Window.getWindows().remove(anotherTestWindow); + assertEquals(1, Window.getWindows().size()); + } } diff --git a/modules/jmx/src/main/java/com/oracle/javafx/jmx/SGMXBeanImpl.java b/modules/jmx/src/main/java/com/oracle/javafx/jmx/SGMXBeanImpl.java --- a/modules/jmx/src/main/java/com/oracle/javafx/jmx/SGMXBeanImpl.java +++ b/modules/jmx/src/main/java/com/oracle/javafx/jmx/SGMXBeanImpl.java @@ -362,12 +362,10 @@ private void importWindows() { int windowCount = 0; - final Iterator it = Window.impl_getWindows(); + final List windows = Window.getWindows(); jwindows = JSONDocument.createArray(); - while (it.hasNext()) { - final Window window = it.next(); - + for (Window window : windows) { windowMap.put(windowCount, window); final JSONDocument jwindow = JSONDocument.createObject(); diff --git a/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_sceneGraph_Test.java b/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_sceneGraph_Test.java --- a/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_sceneGraph_Test.java +++ b/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_sceneGraph_Test.java @@ -43,6 +43,7 @@ import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; public class SGMXBean_sceneGraph_Test { @@ -74,12 +75,10 @@ stage2.setScene(scene2); stage2.show(); - final Iterator it = Window.impl_getWindows(); + final List windows = Window.getWindows(); nodesCount = 0; - while (it.hasNext()) { - final Window w = it.next(); + for (Window w : windows) { nodesCount += countNodes(w.getScene().getRoot()); - } } diff --git a/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_windows_Test.java b/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_windows_Test.java --- a/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_windows_Test.java +++ b/modules/jmx/src/test/java/com/oracle/javafx/jmx/SGMXBean_windows_Test.java @@ -42,6 +42,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import java.util.List; public class SGMXBean_windows_Test { @@ -66,12 +67,8 @@ stage2.setScene(scene2); stage2.show(); - final Iterator it = Window.impl_getWindows(); - windowsCount = 0; - while (it.hasNext()) { - windowsCount++; - it.next(); - } + final List windows = Window.getWindows(); + windowsCount = windows.size(); } private static JSONDocument getJSONDocument(String source) { diff --git a/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java --- a/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java +++ b/tools/ios/Maven/NetBeansMobileCenter/src/main/java/com/sun/javafx/stage/WindowManager.java @@ -38,9 +38,7 @@ public static void closeApplicationWindows( final ClassLoader appClassLoader) { final List selectedWindows = new ArrayList(); - final Iterator allWindows = Window.impl_getWindows(); - while (allWindows.hasNext()) { - final Window window = allWindows.next(); + for (Window window : Window.getWindows()) { if (matches(window, appClassLoader)) { selectedWindows.add(window); }