package bluej.utility;

import bluej.utility.javafx.BetterVBox;
import bluej.utility.javafx.HangingFlowPane;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.canvas.Canvas;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import static org.junit.Assert.assertEquals;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;


| Tests the HangingFlowPane class, specifically its layout algorithm. | public class TestHangingFlowPane { @Rule public TestRule runOnFXThreadRule = new TestRule() { boolean initialised = false; @Override public Statement apply(Statement base, Description d) { if (!initialised) { new JFXPanel(); initialised = true; } return new Statement() { @Override public void evaluate() throws Throwable { CompletableFuture<Throwable> thrown = new CompletableFuture<>(); Platform.runLater(() -> { try { base.evaluate(); thrown.complete(null); } catch (Throwable throwable) { thrown.complete(throwable); } }); Throwable t = thrown.get(); if (t != null) throw t; } }; } };
| Helper class for testing: a Node with a fixed size. | private static class FixedSizeNode extends Canvas { private final Optional<Double> baseline; public FixedSizeNode(double width, double height) { super(width, height); baseline = Optional.empty(); } public FixedSizeNode(double width, double height, double baseline) { super(width, height); this.baseline = Optional.of(baseline); } @Override public double getBaselineOffset() { if (baseline.isPresent()) return baseline.get(); else{ return super.getBaselineOffset(); } } }
| Helper for constructing a HangingFlowPane with the given nodes. | Also performs the layout. | protected HangingFlowPane make(float width, float height, List<Node> ns) { return make(width, height, ns.toArray(new Node[0])); }
| Helper for constructing a HangingFlowPane with the given nodes. | Also performs the layout. | protected HangingFlowPane make(float width, float height, Node... ns) { HangingFlowPane p = new HangingFlowPane(ns); p.setRowValignment(VPos.BASELINE); p.resize(width, height); p.requestLayout(); p.layout(); return p; } @Test public void testSingleFixed() { final FixedSizeNode n = new FixedSizeNode(100.0, 50.0); HangingFlowPane p = make(500, 500, n); assertLayout(n, 0, 0, 100, 50); } @Test public void testTripleFixed() { final FixedSizeNode n0 = new FixedSizeNode(100.0, 40.0); final FixedSizeNode n1 = new FixedSizeNode(90.0, 60.0); final FixedSizeNode n2 = new FixedSizeNode(120.0, 50.0); HangingFlowPane p = make(500, 500, n0, n1, n2); assertLayout(n0, 0, 20, 100, 40); assertLayout(n1, 100, 0, 90, 60); assertLayout(n2, 190, 10, 120, 50); } @Test public void testTripleFixedBaseline() { final FixedSizeNode n0 = new FixedSizeNode(100.0, 40.0, 35); final FixedSizeNode n1 = new FixedSizeNode(90.0, 60.0, 40); final FixedSizeNode n2 = new FixedSizeNode(120.0, 50.0, 20); HangingFlowPane p = make(500, 500, n0, n1, n2); assertLayout(n0, 0, 5, 100, 40); assertLayout(n1, 100, 0, 90, 60); assertLayout(n2, 190, 20, 120, 50); }
| Helper class wrapping a 50 high FixedSizeNode that remembers its width | and expected X position. Can be right-aligned. | private static class TestNodeInfo { private final double width; private final double expectedX; private final FixedSizeNode node; public TestNodeInfo(double width, double expectedX) { this(width, expectedX, 50.0); } public TestNodeInfo(double width, double expectedX, double height) { this.width = width; this.expectedX = expectedX; this.node = new FixedSizeNode(width, height); } public TestNodeInfo(double width, double expectedX, double height, double baseline) { this.width = width; this.expectedX = expectedX; this.node = new FixedSizeNode(width, height, baseline); } Node getNode() { return node; } } private TestNodeInfo n(float width, float expectedX) { return new TestNodeInfo(width, expectedX); } private TestNodeInfo nr(float width, float expectedX) { TestNodeInfo tni = new TestNodeInfo(width, expectedX); HangingFlowPane.setAlignment(tni.getNode(), HangingFlowPane.FlowAlignment.RIGHT); return tni; } private TestNodeInfo nb(float width, float expectedX) { TestNodeInfo tni = n(width, expectedX); HangingFlowPane.setBreakBefore(tni.getNode(), false); return tni; } private <T> List<T> l(T... xs) { return Arrays.asList(xs); }
| Tests given nodes on a flow pane with width 500 | @param hang The amount of hanging indent on lines after the first. | @param nodes The list of lists is a list of expected rows. These are flattened | and passed to the HangingFLowPane, then we check if we get back the rows | we expected. | private void testRows500(double hang, List<List<TestNodeInfo>> nodes) { HangingFlowPane p = make(500, 500, nodes.stream().flatMap(ns -> ns.stream().map(TestNodeInfo::getNode)).collect(Collectors.toList())); p.setHangingIndent(hang); p.requestLayout(); p.layout(); double y = 0; for (List<TestNodeInfo> row : nodes) { for (TestNodeInfo n : row) { assertLayout(n.getNode(), n.expectedX, y, n.width, 50); } y += 50; } } @Test public void testRowsNoHang() { testRows500(0, l( l(n(240, 0), n(260, 240)), l(n(40, 0)) )); testRows500(0, l( l(n(240, 0), n(259, 240)), l(n(40, 0)) )); testRows500(0, l( l(n(240, 0)), l(n(261, 0), n(40, 261)) )); } @Test public void testRowsHang() { testRows500(20, l( l(n(240, 0), n(260, 240)), l(n(40, 20)) )); testRows500(20, l( l(n(240, 0)), l(n(261, 20), n(40, 281)) )); testRows500(20, l( l(n(501, 0)) )); testRows500(20, l( l(n(1, 0)), l(n(501, 20)) )); testRows500(20, l( l(n(1, 0)), l(n(501, 20)), l(n(1, 20)) )); } @Test public void testRightAlign() { testRows500(20.0, l(l(n(100, 0), nr(100, 400)))); testRows500(20.0, l(l(n(300, 0)), l(nr(300, 200)))); } private static double e = 0.000001; private static void assertLayout(Node n, double x, double y, double width, double height) { assertEquals("X", x, n.getLayoutX(), e); assertEquals("Y", y, n.getLayoutY(), e); assertEquals("Width", width, n.getLayoutBounds().getWidth(), e); assertEquals("Height", height, n.getLayoutBounds().getHeight(), e); } @Test public void testFixedNoBreak() { final FixedSizeNode n0 = new FixedSizeNode(100.0, 40.0); final FixedSizeNode n1 = new FixedSizeNode(90.0, 60.0); final FixedSizeNode n2 = new FixedSizeNode(80.0, 50.0); final FixedSizeNode n3 = new FixedSizeNode(70.0, 70.0); HangingFlowPane.setBreakBefore(n2, false); HangingFlowPane p = make(200, 500, n0, n1, n2, n3); assertLayout(n0, 0, 0, 100, 40); assertLayout(n1, 0, 40, 90, 60); assertLayout(n2, 90, 40 + 10, 80, 50); assertLayout(n3, 0, 40 + 60, 70, 70); } @Test public void testNoBreak() { testRows500(0, l( l(n(300, 0)), l(n(100, 0), nb(200, 100)) )); testRows500(20, l( l(n(300, 0)), l(n(100, 20), nb(200, 120)), l(n(110, 20), nb(210, 130)), l(n(400, 20)), l(n(110, 20), nb(210, 130), n(50, 340)), l(n(400, 20)) )); testRows500(0, l( l(n(300, 0)), l(n(100, 0), nb(200, 100)), l(nb(400, 0)) )); } @Test public void testHeight() { checkHeight(0); checkHeight(0, new TestNodeInfo(10, 0, 0)); checkHeight(17, new TestNodeInfo(10, 0, 0, 17)); checkHeight(50, n(10, 0), n(20, 10)); checkHeight(50, n(300, 0)); checkHeight(50, n(300, 0), n(100, 300)); checkHeight(50, n(300, 0), n(199, 300)); checkHeight(50, n(300, 0), n(200, 300)); checkHeight(100, n(300, 0), n(201, 0)); checkHeight(100, n(300, 0), n(300, 0)); checkHeight(50, n(300, 0), n(198, 300), n(1, 498)); checkHeight(50, n(300, 0), n(199, 300), n(1, 499)); checkHeight(100, n(300, 0), n(200, 300), n(1, 0)); } private static class TestBetterVBox extends BetterVBox { public TestBetterVBox(double minWidth) { super(minWidth); } public double computePrefHeight(double width) { return super.computePrefHeight(width); } } private void checkHeight(double expectedHeight, TestNodeInfo... content) { TestBetterVBox surround = new TestBetterVBox(0) { @Override public double getLeftMarginFor(Node n) { return 3; } @Override public double getRightMarginFor(Node n) { return 2; } }; HangingFlowPane hfp = new HangingFlowPane(); surround.getChildren().add(hfp); surround.resize(505, 1000); hfp.setRowValignment(VPos.BASELINE); hfp.getChildren().setAll(Arrays.stream(content).map(TestNodeInfo::getNode).collect(Collectors.toList())); surround.requestLayout(); surround.layout(); assertEquals("Checking height", expectedHeight, hfp.getHeight(), 0.001); assertEquals("Checking height", expectedHeight, surround.computePrefHeight(505), 0.001); } }
top, use, map, class TestHangingFlowPane

.   apply
.   evaluate

top, use, map, class FixedSizeNode

.   FixedSizeNode
.   FixedSizeNode
.   getBaselineOffset
.   make
.   make
.   testSingleFixed
.   testTripleFixed
.   testTripleFixedBaseline

top, use, map, class TestNodeInfo

.   TestNodeInfo
.   TestNodeInfo
.   TestNodeInfo
.   n
.   nr
.   nb
.   testRows500
.   testRowsNoHang
.   testRowsHang
.   testRightAlign
.   assertLayout
.   testFixedNoBreak
.   testNoBreak
.   testHeight

top, use, map, class TestBetterVBox

.   TestBetterVBox
.   computePrefHeight
.   checkHeight
.   getLeftMarginFor
.   getRightMarginFor




503 neLoCode + 13 LoComm