1 /*
   2  * Copyright (c) 2011, 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 test.com.sun.javafx.scene.traversal;
  27 
  28 import com.sun.javafx.scene.traversal.Algorithm;
  29 import com.sun.javafx.scene.traversal.ContainerTabOrder;
  30 import com.sun.javafx.scene.traversal.ContainerTabOrderShim;
  31 import com.sun.javafx.scene.traversal.Direction;
  32 import com.sun.javafx.scene.traversal.ParentTraversalEngine;
  33 import com.sun.javafx.scene.traversal.TopMostTraversalEngine;
  34 import com.sun.javafx.scene.traversal.TopMostTraversalEngineShim;
  35 import com.sun.javafx.scene.traversal.TraversalContext;
  36 import javafx.scene.Group;
  37 import javafx.scene.Node;
  38 import javafx.scene.Parent;
  39 import javafx.scene.ParentShim;
  40 import javafx.scene.shape.Rectangle;
  41 import org.junit.Before;
  42 import org.junit.Test;
  43 
  44 import static org.junit.Assert.assertEquals;
  45 import static org.junit.Assert.fail;
  46 
  47 public class TopMostTraversalEngineTest {
  48     private TopMostTraversalEngineShim engine;
  49     private Group root;
  50 
  51     @Before
  52     public void setUp() {
  53         root = new Group();
  54         engine = new TopMostTraversalEngineShim(new ContainerTabOrderShim()) {
  55             @Override
  56             protected Parent getRoot() {
  57                 return root;
  58             }
  59         };
  60     }
  61 
  62     @Test
  63     public void selectFirst() {
  64         final Node focusableNode = createFocusableNode();
  65         Group g = new Group(focusableNode, createFocusableNode());
  66         ParentShim.getChildren(root).add(g);
  67 
  68         assertEquals(focusableNode, engine.selectFirst());
  69     }
  70 
  71     @Test
  72     public void selectFirstSkipInvisible() {
  73         final Node n1 = createFocusableDisabledNode();
  74         final Node n2 = createFocusableNode();
  75         ParentShim.getChildren(root).addAll(n1, n2);
  76 
  77         assertEquals(n2, engine.selectFirst());
  78     }
  79 
  80     @Test
  81     public void selectFirstUseParentEngine() {
  82         Group g = new Group(createFocusableNode());
  83         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
  84             @Override
  85             public Node select(Node owner, Direction dir, TraversalContext context) {
  86                 return null;
  87             }
  88 
  89             @Override
  90             public Node selectFirst(TraversalContext context) {
  91                 return null;
  92             }
  93 
  94             @Override
  95             public Node selectLast(TraversalContext context) {
  96                 return null;
  97             }
  98         }));
  99         g.setDisable(true);
 100         ParentShim.getChildren(root).add(g);
 101 
 102         final Node focusableNode = createFocusableNode();
 103         g = new Group(createFocusableNode(), focusableNode, createFocusableNode());
 104         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 105             @Override
 106             public Node select(Node owner, Direction dir, TraversalContext context) {
 107                 fail();
 108                 return null;
 109             }
 110 
 111             @Override
 112             public Node selectFirst(TraversalContext context) {
 113                 return focusableNode;
 114             }
 115 
 116             @Override
 117             public Node selectLast(TraversalContext context) {
 118                 fail();
 119                 return null;
 120             }
 121         }));
 122 
 123         ParentShim.getChildren(root).add(g);
 124 
 125         assertEquals(focusableNode, engine.selectFirst());
 126     }
 127 
 128     @Test
 129     public void selectFirstFocusableParent() {
 130         Group g = new Group(createFocusableNode(), createFocusableNode());
 131         g.setFocusTraversable(true);
 132         ParentShim.getChildren(root).add(g);
 133 
 134         assertEquals(g, engine.selectFirst());
 135     }
 136 
 137     @Test
 138     public void selectFirstTraverseOverride() {
 139         Group g = new Group(createFocusableNode(), createFocusableNode());
 140         g.setFocusTraversable(true);
 141         final ParentTraversalEngine pEngine = new ParentTraversalEngine(g);
 142         pEngine.setOverriddenFocusTraversability(false);
 143         g.setImpl_traversalEngine(pEngine);
 144 
 145         ParentShim.getChildren(root).add(g);
 146 
 147         assertEquals(ParentShim.getChildren(g).get(0), engine.selectFirst());
 148     }
 149 
 150 
 151     @Test
 152     public void selectLast() {
 153         final Node focusableNode = createFocusableNode();
 154         Group g = new Group(createFocusableNode(), focusableNode);
 155         ParentShim.getChildren(root).add(g);
 156 
 157         assertEquals(focusableNode, engine.selectLast());
 158     }
 159 
 160     @Test
 161     public void selectLastSkipInvisible() {
 162         final Node n1 = createFocusableNode();
 163         final Node n2 = createFocusableDisabledNode();
 164         ParentShim.getChildren(root).addAll(n1, n2);
 165 
 166         assertEquals(n1, engine.selectFirst());
 167     }
 168 
 169     @Test
 170     public void selectLastUseParentEngine() {
 171         final Node focusableNode = createFocusableNode();
 172         Group g = new Group(createFocusableNode(), focusableNode, createFocusableNode());
 173         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 174             @Override
 175             public Node select(Node owner, Direction dir, TraversalContext context) {
 176                 fail();
 177                 return null;
 178             }
 179 
 180             @Override
 181             public Node selectFirst(TraversalContext context) {
 182                 fail();
 183                 return null;
 184             }
 185 
 186             @Override
 187             public Node selectLast(TraversalContext context) {
 188                 return focusableNode;
 189             }
 190         }));
 191 
 192         ParentShim.getChildren(root).add(g);
 193 
 194 
 195         g = new Group(createFocusableNode());
 196         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 197             @Override
 198             public Node select(Node owner, Direction dir, TraversalContext context) {
 199                 return null;
 200             }
 201 
 202             @Override
 203             public Node selectFirst(TraversalContext context) {
 204                 return null;
 205             }
 206 
 207             @Override
 208             public Node selectLast(TraversalContext context) {
 209                 return null;
 210             }
 211         }));
 212         g.setDisable(true);
 213         ParentShim.getChildren(root).add(g);
 214 
 215 
 216         assertEquals(focusableNode, engine.selectLast());
 217     }
 218 
 219     @Test
 220     public void selectLastFocusableParent() {
 221         final Node focusableNode = createFocusableNode();
 222         Group g = new Group(createFocusableNode(), focusableNode);
 223         g.setFocusTraversable(true);
 224         ParentShim.getChildren(root).add(g);
 225 
 226         assertEquals(focusableNode, engine.selectLast());
 227     }
 228 
 229     @Test
 230     public void selectLastFocusableParent_2() {
 231         Group g = new Group(new Rectangle());
 232         g.setFocusTraversable(true);
 233         ParentShim.getChildren(root).add(g);
 234 
 235         assertEquals(g, engine.selectLast());
 236     }
 237 
 238     @Test
 239     public void selectLastTraverseOverride() {
 240         Group g = new Group();
 241         g.setFocusTraversable(true);
 242         final ParentTraversalEngine pEngine = new ParentTraversalEngine(g);
 243         pEngine.setOverriddenFocusTraversability(false);
 244         g.setImpl_traversalEngine(pEngine);
 245 
 246         Node focusableNode = createFocusableNode();
 247 
 248         ParentShim.getChildren(root).addAll(focusableNode, g);
 249 
 250         assertEquals(focusableNode, engine.selectLast());
 251     }
 252 
 253     @Test
 254     public void selectNext() {
 255         Node n1 = createFocusableNode();
 256         Node n2 = createFocusableNode();
 257         Group g = new Group(createFocusableNode(), n1, new Rectangle(), n2, createFocusableNode());
 258 
 259         ParentShim.getChildren(root).addAll(g);
 260 
 261         assertEquals(n2, engine.trav(n1, Direction.NEXT));
 262     }
 263 
 264     @Test
 265     public void selectNextFromParent() {
 266         Node ng1 = createFocusableNode();
 267         Node n1 = new Group(new Rectangle(), createFocusableDisabledNode(), ng1, createFocusableNode());
 268         Node n2 = createFocusableNode();
 269         Group g = new Group(createFocusableNode(), n1, new Rectangle(), n2, createFocusableNode());
 270 
 271         ParentShim.getChildren(root).addAll(g);
 272 
 273         assertEquals(ng1, engine.trav(n1, Direction.NEXT));
 274     }
 275 
 276     @Test
 277     public void selectNextFromParent_2() {
 278         Node n1 = new Group(createFocusableDisabledNode(), createFocusableDisabledNode());
 279         Node n2 = createFocusableNode();
 280         Group g = new Group(createFocusableNode(), n1, new Rectangle(), n2, createFocusableNode());
 281 
 282         ParentShim.getChildren(root).addAll(g);
 283 
 284         assertEquals(n2, engine.trav(n1, Direction.NEXT));
 285     }
 286 
 287     @Test
 288     public void selectNextInParentSibling() {
 289         Node n1 = createFocusableNode();
 290         final Node n2 = createFocusableNode();
 291 
 292         ParentShim.getChildren(root).addAll(createFocusableNode(), new Group(new Group(n1, createFocusableDisabledNode(), createFocusableDisabledNode()),
 293                 new Group(createFocusableDisabledNode())), new Group(n2));
 294 
 295         assertEquals(n2, engine.trav(n1, Direction.NEXT));
 296     }
 297 
 298     @Test
 299     public void selectNextFocusableParent() {
 300         Node n1 = createFocusableNode();
 301         Group g = new Group(createFocusableNode());
 302         g.setFocusTraversable(true);
 303 
 304         ParentShim.getChildren(root).addAll(new Group(createFocusableNode(), n1, createFocusableDisabledNode(), g));
 305 
 306         assertEquals(g, engine.trav(n1, Direction.NEXT));
 307     }
 308 
 309     @Test
 310     public void selectNextInOverridenAlgorithm() {
 311         Node n1 = createFocusableNode();
 312         Node n2 = createFocusableNode();
 313         Group g = new Group(n1, createFocusableNode(), n2);
 314         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 315             @Override
 316             public Node select(Node owner, Direction dir, TraversalContext context) {
 317                 assertEquals(Direction.NEXT, dir);
 318                 return n2;
 319             }
 320 
 321             @Override
 322             public Node selectFirst(TraversalContext context) {
 323                 fail();
 324                 return null;
 325             }
 326 
 327             @Override
 328             public Node selectLast(TraversalContext context) {
 329                 fail();
 330                 return null;
 331             }
 332         }));
 333 
 334         ParentShim.getChildren(root).add(g);
 335 
 336         assertEquals(n2, engine.trav(n1, Direction.NEXT));
 337     }
 338 
 339 
 340     @Test
 341     public void selectNextInOverridenAlgorithm_NothingSelected() {
 342         Node n1 = createFocusableNode();
 343         Node n2 = createFocusableNode();
 344         Group g = new Group(n1, createFocusableNode(), n2);
 345         g.setFocusTraversable(true);
 346         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 347             @Override
 348             public Node select(Node owner, Direction dir, TraversalContext context) {
 349                 assertEquals(Direction.NEXT, dir);
 350                 return null;
 351             }
 352 
 353             @Override
 354             public Node selectFirst(TraversalContext context) {
 355                 fail();
 356                 return null;
 357             }
 358 
 359             @Override
 360             public Node selectLast(TraversalContext context) {
 361                 fail();
 362                 return null;
 363             }
 364         }));
 365 
 366         final Node n3 = createFocusableNode();
 367         ParentShim.getChildren(root).addAll(g, n3);
 368 
 369         assertEquals(n3, engine.trav(n1, Direction.NEXT));
 370     }
 371 
 372     @Test
 373     public void selectNextInLine() {
 374         Node n1 = new Group(createFocusableNode(), createFocusableNode());
 375         n1.setFocusTraversable(true);
 376         Node n2 = createFocusableNode();
 377         Group g = new Group(createFocusableNode(), n1, new Rectangle(), n2, createFocusableNode());
 378 
 379         ParentShim.getChildren(root).addAll(g);
 380 
 381         assertEquals(n2, engine.trav(n1, Direction.NEXT_IN_LINE));
 382     }
 383 
 384 
 385     @Test
 386     public void selectPrevious() {
 387         Node n1 = createFocusableNode();
 388         Node n2 = createFocusableNode();
 389         Group g = new Group(createFocusableNode(), n2, new Rectangle(), n1, createFocusableNode());
 390 
 391         ParentShim.getChildren(root).addAll(g);
 392 
 393         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 394     }
 395 
 396     @Test
 397     public void selectPreviousFromParent() {
 398         Node ng1 = createFocusableNode();
 399         Node n1 = new Group(new Rectangle(), createFocusableDisabledNode(), ng1, createFocusableNode());
 400         Node n2 = createFocusableNode();
 401         Group g = new Group(createFocusableNode(), n2, new Rectangle(), n1, createFocusableNode());
 402 
 403         ParentShim.getChildren(root).addAll(g);
 404 
 405         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 406     }
 407 
 408     @Test
 409     public void selectPreviousFromParent_2() {
 410         Node n1 = new Group(createFocusableDisabledNode(), createFocusableDisabledNode());
 411         Node n2 = createFocusableNode();
 412         Group g = new Group(createFocusableNode(), n2, new Rectangle(), n1, createFocusableNode());
 413 
 414         ParentShim.getChildren(root).addAll(g);
 415 
 416         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 417     }
 418 
 419     @Test
 420     public void selectPreviousInParentSibling() {
 421         Node n1 = createFocusableNode();
 422         final Node n2 = createFocusableNode();
 423 
 424         ParentShim.getChildren(root).addAll(new Group(n2), new Group(createFocusableDisabledNode()),
 425                 new Group(new Group(createFocusableDisabledNode(), n1, createFocusableDisabledNode())),
 426                  createFocusableNode());
 427 
 428         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 429     }
 430 
 431     @Test
 432     public void selectPreviousFocusableParentsNode() {
 433         Node n1 = createFocusableNode();
 434         final Node n2 = createFocusableNode();
 435         Group g = new Group(n2);
 436         g.setFocusTraversable(true);
 437 
 438         ParentShim.getChildren(root).addAll(new Group(createFocusableNode(), g, n1, createFocusableDisabledNode()));
 439 
 440         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 441     }
 442 
 443     @Test
 444     public void selectPreviousFocusableParent() {
 445         Node n1 = createFocusableNode();
 446         final Node n2 = createFocusableNode();
 447         Group g = new Group(createFocusableDisabledNode(), n2);
 448         g.setFocusTraversable(true);
 449 
 450         ParentShim.getChildren(root).addAll(new Group(createFocusableNode(), n1, g, createFocusableDisabledNode()));
 451 
 452         assertEquals(g, engine.trav(n2, Direction.PREVIOUS));
 453     }
 454 
 455     @Test
 456     public void selectNextToLast() {
 457         Node n1 = createFocusableNode();
 458         Node n2 = createFocusableNode();
 459 
 460         ParentShim.getChildren(root).addAll(new Group(n2), new Group(createFocusableNode(), n1));
 461 
 462         assertEquals(n2, engine.trav(n1, Direction.NEXT));
 463     }
 464 
 465 
 466     @Test
 467     public void selectPreviousToFirst() {
 468         Node n1 = createFocusableNode();
 469         Node n2 = createFocusableNode();
 470 
 471         ParentShim.getChildren(root).addAll(new Group(n1, createFocusableNode()), new Group(n2));
 472 
 473         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 474     }
 475 
 476 
 477     @Test
 478     public void selectPreviousInOverridenAlgorithm() {
 479         Node n1 = createFocusableNode();
 480         Node n2 = createFocusableNode();
 481         Group g = new Group(n2, createFocusableNode(), n1);
 482         g.setImpl_traversalEngine(new ParentTraversalEngine(g, new Algorithm() {
 483             @Override
 484             public Node select(Node owner, Direction dir, TraversalContext context) {
 485                 assertEquals(Direction.PREVIOUS, dir);
 486                 return n2;
 487             }
 488 
 489             @Override
 490             public Node selectFirst(TraversalContext context) {
 491                 fail();
 492                 return null;
 493             }
 494 
 495             @Override
 496             public Node selectLast(TraversalContext context) {
 497                 fail();
 498                 return null;
 499             }
 500         }));
 501 
 502         ParentShim.getChildren(root).add(g);
 503 
 504         assertEquals(n2, engine.trav(n1, Direction.PREVIOUS));
 505     }
 506 
 507     private Node createFocusableNode() {
 508         Node n =  new Rectangle();
 509         n.setFocusTraversable(true);
 510         return n;
 511     }
 512 
 513     private Node createFocusableDisabledNode() {
 514         Node n = createFocusableNode();
 515         n.setDisable(true);
 516         return n;
 517     }
 518 }