From 917ec9490e5ef7a8943e8b0ad74f20c48cea4f3b Mon Sep 17 00:00:00 2001 From: Alexander Jipa Date: Mon, 28 Mar 2016 23:35:41 -0400 Subject: [PATCH] fixes #7: Create a new undocked DockNode making it possible to create a previously non-docked floating DockNode, removing DockNode's internal BorderPane min width/height augmentation as it result is visual artifacts for floating nodes (looks like it was calculated wrong too), providing a unit test and a rule to test JavaFX components --- .gitignore | 1 + pom.xml | 10 ++ src/main/java/org/dockfx/DockNode.java | 13 ++- src/main/java/org/dockfx/demo/DockFX.java | 10 +- src/test/java/floating/FloatingDock.java | 21 ++++ src/test/java/utils/JavaFXThreadingRule.java | 102 +++++++++++++++++++ 6 files changed, 152 insertions(+), 5 deletions(-) create mode 100644 src/test/java/floating/FloatingDock.java create mode 100644 src/test/java/utils/JavaFXThreadingRule.java diff --git a/.gitignore b/.gitignore index cb0209d..36280e8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ dockfx.jar dockfxdemo.jar *.jar *.db +.idea/ .git/modules /bin target \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1bd0e58..b056602 100644 --- a/pom.xml +++ b/pom.xml @@ -11,6 +11,7 @@ https://github.com/RobertBColton/DockFX.git + 4.12 1.8 1.8 true @@ -18,6 +19,15 @@ java, properties, xml + + + junit + junit + ${junit.version} + test + + + diff --git a/src/main/java/org/dockfx/DockNode.java b/src/main/java/org/dockfx/DockNode.java index 3dc097d..29f4fb1 100644 --- a/src/main/java/org/dockfx/DockNode.java +++ b/src/main/java/org/dockfx/DockNode.java @@ -262,9 +262,17 @@ public void setFloating(boolean floating, Point2D translation) { if (this.isDecorated()) { Window owner = stage.getOwner(); stagePosition = floatScene.add(new Point2D(owner.getX(), owner.getY())); - } else { + } else if (floatScreen != null) { + // using coordinates the component was previously in (if available) stagePosition = floatScreen; + } else { + // using the center of the screen if no relative position is available + Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds(); + double centerX = (primScreenBounds.getWidth() - Math.max(getWidth(), getMinWidth())) / 2; + double centerY = (primScreenBounds.getHeight() - Math.max(getHeight(), getMinHeight())) / 2; + stagePosition = new Point2D(centerX, centerY); } + if (translation != null) { stagePosition = stagePosition.add(translation); } @@ -296,9 +304,6 @@ public void setFloating(boolean floating, Point2D translation) { stage.setX(stagePosition.getX() - insetsDelta.getLeft()); stage.setY(stagePosition.getY() - insetsDelta.getTop()); - stage.setMinWidth(borderPane.minWidth(this.getHeight()) + insetsWidth); - stage.setMinHeight(borderPane.minHeight(this.getWidth()) + insetsHeight); - borderPane.setPrefSize(this.getWidth() + insetsWidth, this.getHeight() + insetsHeight); stage.setScene(scene); diff --git a/src/main/java/org/dockfx/demo/DockFX.java b/src/main/java/org/dockfx/demo/DockFX.java index 6810fff..86385fe 100644 --- a/src/main/java/org/dockfx/demo/DockFX.java +++ b/src/main/java/org/dockfx/demo/DockFX.java @@ -26,6 +26,9 @@ import java.nio.file.Paths; import java.util.Random; +import javafx.application.Platform; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; import org.dockfx.DockNode; import org.dockfx.DockPane; import org.dockfx.DockPos; @@ -67,7 +70,7 @@ public void start(Stage primaryStage) { } // empty tabs ensure that dock node has its own background color when floating - tabs.getTabs().addAll(new Tab("Tab 1", htmlEditor), new Tab("Tab 2"), new Tab("Tab 3")); + tabs.getTabs().addAll(new Tab("Tab 1"), new Tab("Tab 2"), new Tab("Tab 3")); TableView tableView = new TableView(); // this is why @SupressWarnings is used above @@ -122,6 +125,11 @@ public void start(Stage primaryStage) { // https://bugs.openjdk.java.net/browse/JDK-8132900 DockPane.initializeDefaultUserAgentStylesheet(); + DockNode welcomeDock = new DockNode(htmlEditor, "Welcome", new ImageView(dockImage)); + welcomeDock.setMinWidth(600); + welcomeDock.setMinHeight(400); + welcomeDock.setFloating(true); + // TODO: after this feel free to apply your own global stylesheet using the StyleManager class } diff --git a/src/test/java/floating/FloatingDock.java b/src/test/java/floating/FloatingDock.java new file mode 100644 index 0000000..aa47e31 --- /dev/null +++ b/src/test/java/floating/FloatingDock.java @@ -0,0 +1,21 @@ +package floating; + +import javafx.scene.control.Label; +import org.dockfx.DockNode; +import org.junit.Rule; +import org.junit.Test; +import utils.JavaFXThreadingRule; + +import static org.junit.Assert.assertTrue; + +public class FloatingDock { + @Rule + public JavaFXThreadingRule javafxRule = new JavaFXThreadingRule(); + + @Test + public void canCreateFloatingDock() { + final DockNode testDock = new DockNode(new Label(), "Some Label"); + testDock.setFloating(true); + assertTrue(testDock.isFloating()); + } +} diff --git a/src/test/java/utils/JavaFXThreadingRule.java b/src/test/java/utils/JavaFXThreadingRule.java new file mode 100644 index 0000000..43ecfe5 --- /dev/null +++ b/src/test/java/utils/JavaFXThreadingRule.java @@ -0,0 +1,102 @@ +package utils; + +import java.util.concurrent.CountDownLatch; + +import javax.swing.SwingUtilities; + +import javafx.application.Platform; +import javafx.embed.swing.JFXPanel; + +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * A JUnit {@link Rule} for running tests on the JavaFX thread and performing + * JavaFX initialisation. To include in your test case, add the following code: + * + *
+ * {@literal @}Rule
+ * public JavaFXThreadingRule jfxRule = new JavaFXThreadingRule();
+ * 
+ * + * @author Andy Till + * + */ +public class JavaFXThreadingRule implements TestRule { + + /** + * Flag for setting up the JavaFX, we only need to do this once for all tests. + */ + private static boolean jfxIsSetup; + + @Override + public Statement apply(Statement statement, Description description) { + + return new OnJFXThreadStatement(statement); + } + + private static class OnJFXThreadStatement extends Statement { + + private final Statement statement; + + public OnJFXThreadStatement(Statement aStatement) { + statement = aStatement; + } + + private Throwable rethrownException = null; + + @Override + public void evaluate() throws Throwable { + + if(!jfxIsSetup) { + setupJavaFX(); + + jfxIsSetup = true; + } + + final CountDownLatch countDownLatch = new CountDownLatch(1); + + Platform.runLater(new Runnable() { + @Override + public void run() { + try { + statement.evaluate(); + } catch (Throwable e) { + rethrownException = e; + } + countDownLatch.countDown(); + }}); + + countDownLatch.await(); + + // if an exception was thrown by the statement during evaluation, + // then re-throw it to fail the test + if(rethrownException != null) { + throw rethrownException; + } + } + + protected void setupJavaFX() throws InterruptedException { + + long timeMillis = System.currentTimeMillis(); + + final CountDownLatch latch = new CountDownLatch(1); + + SwingUtilities.invokeLater(new Runnable() { + public void run() { + // initializes JavaFX environment + new JFXPanel(); + + latch.countDown(); + } + }); + + System.out.println("javafx initialising..."); + latch.await(); + System.out.println("javafx is initialised in " + (System.currentTimeMillis() - timeMillis) + "ms"); + } + + } +} \ No newline at end of file