1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.scene.traversal; 27 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertSame; 30 import static org.junit.Assert.assertTrue; 31 32 import java.util.Arrays; 33 import java.util.Collection; 34 35 import javafx.geometry.Bounds; 36 import javafx.scene.Group; 37 import javafx.scene.Node; 38 import javafx.scene.Scene; 39 import javafx.scene.shape.Rectangle; 40 import javafx.stage.Stage; 41 42 import org.junit.After; 43 import org.junit.Before; 44 import org.junit.Test; 45 import org.junit.runner.RunWith; 46 import org.junit.runners.Parameterized; 47 import org.junit.runners.Parameterized.Parameters; 48 49 /** 50 * Tests for TraversalEngine with the default ContainerTabOrder algorithm, 51 * tests if using the WeightedClosestCorner algorithm have been 52 * left in comments. 53 */ 54 @RunWith(Parameterized.class) 55 public final class TraversalTest { 56 private final int fromNumber; 57 private final Direction direction; 58 private final int toNumber; 59 private final int toNumberTransformed; 60 61 private Stage stage; 62 private Scene scene; 63 /** 64 * 3x3 keypad. 65 * <p> 66 * Untransformed keypad: 67 * <ul> 68 * <li>1 2 3</li> 69 * <li>4 5 6</li> 70 * <li>7 8 9</li> 71 * </ul> 72 * <p> 73 * Transformed keypad: 74 * <ul> 75 * <li>7 4 1</li> 76 * <li>8 5 2</li> 77 * <li>9 6 3</li> 78 * </ul> 79 */ 80 private Node[] keypadNodes; 81 private SceneTraversalEngine traversalEngine; 82 83 /* 84 * Parameters: [fromNumber], [direction], [toNumber], [toNumberTransformed] 85 */ 86 @Parameters 87 public static Collection data() { 88 return Arrays.asList(new Object[][] { 89 /* traversal from center */ 90 { 5, Direction.LEFT, 4, 8 }, 91 { 5, Direction.RIGHT, 6, 2 }, 92 { 5, Direction.UP, 2, 4 }, 93 { 5, Direction.DOWN, 8, 6 }, 94 95 // using WeightedClosestCorner, target varies according to transform 96 //{ 5, Direction.PREVIOUS, 4, 8 }, 97 //{ 5, Direction.NEXT, 6, 2 }, 98 99 // using ContainerTabOrder, target is always the same 100 { 5, Direction.PREVIOUS, 4, 4 }, 101 { 5, Direction.NEXT, 6, 6 }, 102 103 /* traversal from borders (untransformed) */ 104 { 4, Direction.LEFT, 4, 7 }, 105 { 6, Direction.RIGHT, 6, 3 }, 106 { 2, Direction.UP, 2, 1 }, 107 { 8, Direction.DOWN, 8, 9 }, 108 109 // using WeightedClosestCorner, target varies according to transform 110 //{ 4, Direction.PREVIOUS, 3, 7 }, 111 //{ 1, Direction.PREVIOUS, 9, 4 }, 112 //{ 6, Direction.NEXT, 7, 3 }, 113 //{ 9, Direction.NEXT, 1, 6 }, 114 115 // using ContainerTabOrder, target always the same 116 { 4, Direction.PREVIOUS, 3, 3 }, 117 { 1, Direction.PREVIOUS, 9, 9 }, 118 { 6, Direction.NEXT, 7, 7 }, 119 { 9, Direction.NEXT, 1, 1 }, 120 121 /* traversal from borders (transformed) */ 122 { 2, Direction.RIGHT, 3, 2 }, 123 { 8, Direction.LEFT, 7, 8 }, 124 { 4, Direction.UP, 1, 4 }, 125 { 6, Direction.DOWN, 9, 6 }, 126 127 // using WeightedClosestCorner, target varies according to transform 128 //{ 8, Direction.PREVIOUS, 7, 1 }, 129 //{ 7, Direction.PREVIOUS, 6, 3 }, 130 //{ 2, Direction.NEXT, 3, 9 }, 131 //{ 3, Direction.NEXT, 4, 7 } 132 133 // using ContainerTabOrder, target always the same 134 { 8, Direction.PREVIOUS, 7, 7 }, 135 { 7, Direction.PREVIOUS, 6, 6 }, 136 { 2, Direction.NEXT, 3, 3 }, 137 { 3, Direction.NEXT, 4, 4 } 138 }); 139 } 140 141 public TraversalTest(final int fromNumber, 142 final Direction direction, 143 final int toNumber, 144 final int toNumberTransformed) { 145 this.fromNumber = fromNumber; 146 this.direction = direction; 147 this.toNumber = toNumber; 148 this.toNumberTransformed = toNumberTransformed; 149 } 150 151 @Before 152 public void setUp() { 153 stage = new Stage(); 154 scene = new Scene(new Group(), 500, 500); 155 stage.setScene(scene); 156 157 traversalEngine = new SceneTraversalEngine(scene); 158 159 keypadNodes = createKeypadNodesInScene(scene, traversalEngine); 160 161 stage.show(); 162 stage.requestFocus(); 163 } 164 165 @After 166 public void tearDown() { 167 stage = null; 168 scene = null; 169 keypadNodes = null; 170 traversalEngine = null; 171 } 172 173 @Test 174 public void untransformedTraversalTest() { 175 keypadNodes[fromNumber - 1].requestFocus(); 176 traversalEngine.trav(keypadNodes[fromNumber - 1], direction); 177 assertTrue(keypadNodes[toNumber - 1].isFocused()); 178 } 179 180 @Test 181 public void transformedTraversalTest() { 182 scene.getRoot().setRotate(90); 183 keypadNodes[fromNumber - 1].requestFocus(); 184 traversalEngine.trav(keypadNodes[fromNumber - 1], direction); 185 assertTrue(keypadNodes[toNumberTransformed - 1].isFocused()); 186 } 187 188 @Test 189 public void traverseListenerTest() { 190 final TraverseListenerImpl traverseListener = 191 new TraverseListenerImpl(); 192 traversalEngine.addTraverseListener(traverseListener); 193 keypadNodes[fromNumber - 1].requestFocus(); 194 traversalEngine.trav(keypadNodes[fromNumber - 1], direction); 195 if (fromNumber != toNumber) { 196 assertEquals(1, traverseListener.getCallCounter()); 197 assertSame(keypadNodes[toNumber - 1], 198 traverseListener.getLastNode()); 199 } else { 200 assertEquals(0, traverseListener.getCallCounter()); 201 } 202 } 203 204 private static Node[] createKeypadNodesInScene( 205 final Scene scene, 206 final TraversalEngine traversalEngine) { 207 final Node[] keypad = new Node[9]; 208 209 int index = 0; 210 for (int row = 0; row < 3; ++row) { 211 for (int column = 0; column < 3; ++column) { 212 final Node keyNode = new Rectangle(10 + column * 50, 213 10 + row * 50, 214 40, 40); 215 keyNode.setFocusTraversable(true); 216 217 keypad[index++] = keyNode; 218 ((Group)scene.getRoot()).getChildren().add(keyNode); 219 } 220 } 221 222 return keypad; 223 } 224 225 private static final class TraverseListenerImpl 226 implements TraverseListener { 227 private int callCounter; 228 private Node lastNode; 229 230 public int getCallCounter() { 231 return callCounter; 232 } 233 234 public Node getLastNode() { 235 return lastNode; 236 } 237 238 @Override 239 public void onTraverse(final Node node, final Bounds bounds) { 240 ++callCounter; 241 lastNode = node; 242 } 243 } 244 }