/*
* Copyright (c) 2010, 2014, 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.com.sun.javafx.scene.traversal;
import com.sun.javafx.scene.traversal.Direction;
import com.sun.javafx.scene.traversal.Direction;
import com.sun.javafx.scene.traversal.SceneTraversalEngine;
import com.sun.javafx.scene.traversal.SceneTraversalEngine;
import com.sun.javafx.scene.traversal.TraversalEngine;
import com.sun.javafx.scene.traversal.TraversalEngine;
import com.sun.javafx.scene.traversal.TraverseListener;
import com.sun.javafx.scene.traversal.TraverseListener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* Tests for TraversalEngine with the default ContainerTabOrder algorithm,
* tests if using the WeightedClosestCorner algorithm have been
* left in comments.
*/
@RunWith(Parameterized.class)
public final class TraversalTest {
private final int fromNumber;
private final Direction direction;
private final int toNumber;
private final int toNumberTransformed;
private Stage stage;
private Scene scene;
/**
* 3x3 keypad.
*
* Untransformed keypad:
*
* - 1 2 3
* - 4 5 6
* - 7 8 9
*
*
* Transformed keypad:
*
* - 7 4 1
* - 8 5 2
* - 9 6 3
*
*/
private Node[] keypadNodes;
private SceneTraversalEngine traversalEngine;
/*
* Parameters: [fromNumber], [direction], [toNumber], [toNumberTransformed]
*/
@Parameters
public static Collection data() {
return Arrays.asList(new Object[][] {
/* traversal from center */
{ 5, Direction.LEFT, 4, 8 },
{ 5, Direction.RIGHT, 6, 2 },
{ 5, Direction.UP, 2, 4 },
{ 5, Direction.DOWN, 8, 6 },
// using WeightedClosestCorner, target varies according to transform
//{ 5, Direction.PREVIOUS, 4, 8 },
//{ 5, Direction.NEXT, 6, 2 },
// using ContainerTabOrder, target is always the same
{ 5, Direction.PREVIOUS, 4, 4 },
{ 5, Direction.NEXT, 6, 6 },
/* traversal from borders (untransformed) */
{ 4, Direction.LEFT, 4, 7 },
{ 6, Direction.RIGHT, 6, 3 },
{ 2, Direction.UP, 2, 1 },
{ 8, Direction.DOWN, 8, 9 },
// using WeightedClosestCorner, target varies according to transform
//{ 4, Direction.PREVIOUS, 3, 7 },
//{ 1, Direction.PREVIOUS, 9, 4 },
//{ 6, Direction.NEXT, 7, 3 },
//{ 9, Direction.NEXT, 1, 6 },
// using ContainerTabOrder, target always the same
{ 4, Direction.PREVIOUS, 3, 3 },
{ 1, Direction.PREVIOUS, 9, 9 },
{ 6, Direction.NEXT, 7, 7 },
{ 9, Direction.NEXT, 1, 1 },
/* traversal from borders (transformed) */
{ 2, Direction.RIGHT, 3, 2 },
{ 8, Direction.LEFT, 7, 8 },
{ 4, Direction.UP, 1, 4 },
{ 6, Direction.DOWN, 9, 6 },
// using WeightedClosestCorner, target varies according to transform
//{ 8, Direction.PREVIOUS, 7, 1 },
//{ 7, Direction.PREVIOUS, 6, 3 },
//{ 2, Direction.NEXT, 3, 9 },
//{ 3, Direction.NEXT, 4, 7 }
// using ContainerTabOrder, target always the same
{ 8, Direction.PREVIOUS, 7, 7 },
{ 7, Direction.PREVIOUS, 6, 6 },
{ 2, Direction.NEXT, 3, 3 },
{ 3, Direction.NEXT, 4, 4 }
});
}
public TraversalTest(final int fromNumber,
final Direction direction,
final int toNumber,
final int toNumberTransformed) {
this.fromNumber = fromNumber;
this.direction = direction;
this.toNumber = toNumber;
this.toNumberTransformed = toNumberTransformed;
}
@Before
public void setUp() {
stage = new Stage();
scene = new Scene(new Group(), 500, 500);
stage.setScene(scene);
traversalEngine = new SceneTraversalEngine(scene);
keypadNodes = createKeypadNodesInScene(scene, traversalEngine);
stage.show();
stage.requestFocus();
}
@After
public void tearDown() {
stage = null;
scene = null;
keypadNodes = null;
traversalEngine = null;
}
@Test
public void untransformedTraversalTest() {
keypadNodes[fromNumber - 1].requestFocus();
traversalEngine.trav(keypadNodes[fromNumber - 1], direction);
assertTrue(keypadNodes[toNumber - 1].isFocused());
}
@Test
public void transformedTraversalTest() {
scene.getRoot().setRotate(90);
keypadNodes[fromNumber - 1].requestFocus();
traversalEngine.trav(keypadNodes[fromNumber - 1], direction);
assertTrue(keypadNodes[toNumberTransformed - 1].isFocused());
}
@Test
public void traverseListenerTest() {
final TraverseListenerImpl traverseListener =
new TraverseListenerImpl();
traversalEngine.addTraverseListener(traverseListener);
keypadNodes[fromNumber - 1].requestFocus();
traversalEngine.trav(keypadNodes[fromNumber - 1], direction);
if (fromNumber != toNumber) {
assertEquals(1, traverseListener.getCallCounter());
assertSame(keypadNodes[toNumber - 1],
traverseListener.getLastNode());
} else {
assertEquals(0, traverseListener.getCallCounter());
}
}
private static Node[] createKeypadNodesInScene(
final Scene scene,
final TraversalEngine traversalEngine) {
final Node[] keypad = new Node[9];
int index = 0;
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
final Node keyNode = new Rectangle(10 + column * 50,
10 + row * 50,
40, 40);
keyNode.setFocusTraversable(true);
keypad[index++] = keyNode;
((Group)scene.getRoot()).getChildren().add(keyNode);
}
}
return keypad;
}
private static final class TraverseListenerImpl
implements TraverseListener {
private int callCounter;
private Node lastNode;
public int getCallCounter() {
return callCounter;
}
public Node getLastNode() {
return lastNode;
}
@Override
public void onTraverse(final Node node, final Bounds bounds) {
++callCounter;
lastNode = node;
}
}
}