/*
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package com.sun.javafx.scene.traversal;
import com.sun.javafx.application.
PlatformImpl;
import javafx.scene.
Node;
import javafx.scene.
Parent;
/**
* This is the class for all top-level traversal engines in scenes and subscenes.
* These traversal engines are created automatically and can only have the default algorithm.
*
* These engines should be used by calling {@link #trav(javafx.scene.Node, Direction)}, {@link #traverseToFirst()} and
* {@link #traverseToLast()} methods. These methods do the actual traversal - selecting the Node that's should be focused next and
* focusing it. Also, listener calls are handled by top-most traversal engines.
* select* methods can be used as well, but will *not* transfer the focus to the result, they are just query methods.
*/
public abstract class
TopMostTraversalEngine extends
TraversalEngine{
protected
TopMostTraversalEngine() {
/*
* for 2d behaviour from TAB use :
* algorithm = new WeightedClosestCorner();
* for Container sequence TAB behaviour and 2d arrow behaviour use :
* algorithm = new ContainerTabOrder();
* for 2D arrow behaviour with a target bias and a stack use :
* algorithm = new Biased2DWithStack();
*/
super(
DEFAULT_ALGORITHM);
}
/**
* For testing purposes only!
*/
TopMostTraversalEngine(
Algorithm algorithm) {
super(
algorithm);
}
/**
* Traverse the focus to the next node in the specified direction.
*
* @param node The starting node to traverse from
* @param dir the traversal direction
* @return the new focus owner or null if none found (in that case old focus owner is still valid)
*/
public final
Node trav(
Node node,
Direction dir) {
Node newNode = null;
Parent p =
node.
getParent();
Node traverseNode =
node;
while (
p != null) {
// First find the nearest traversal engine override (i.e. a ParentTraversalEngine that is traversable)
ParentTraversalEngine engine =
p.
getImpl_traversalEngine();
if (
engine != null &&
engine.
canTraverse()) {
newNode =
engine.
select(
node,
dir);
if (
newNode != null) {
break;
} else {
// The inner traversal engine wasn't able to select anything in the specified direction.
// So now we try to traverse from the whole parent (associated with that traversal engine)
// by a traversal engine that's higher in the hierarchy
traverseNode =
p;
if (
dir ==
Direction.
NEXT) {
dir =
Direction.
NEXT_IN_LINE;
}
}
}
p =
p.
getParent();
}
// No engine override was able to find the Node in the specified direction, so
if (
newNode == null) {
newNode =
select(
traverseNode,
dir);
}
if (
newNode == null) {
if (
dir ==
Direction.
NEXT ||
dir ==
Direction.
NEXT_IN_LINE) {
newNode =
selectFirst();
} else if (
dir ==
Direction.
PREVIOUS) {
newNode =
selectLast();
}
}
if (
newNode != null) {
focusAndNotify(
newNode);
}
return
newNode;
}
private void
focusAndNotify(
Node newNode) {
newNode.
requestFocus();
notifyTreeTraversedTo(
newNode);
}
private void
notifyTreeTraversedTo(
Node newNode) {
Parent p =
newNode.
getParent();
while (
p != null) {
final
ParentTraversalEngine impl_traversalEngine =
p.
getImpl_traversalEngine();
if (
impl_traversalEngine != null) {
impl_traversalEngine.
notifyTraversedTo(
newNode);
}
p =
p.
getParent();
}
notifyTraversedTo(
newNode);
}
/**
* Set focus on the first Node in this context (if any)
* @return the first node or null if there's none
*/
public final
Node traverseToFirst() {
Node n =
selectFirst();
if (
n != null)
focusAndNotify(
n);
return
n;
}
/**
* Set focus on the last Node in this context (if any)
* @return the last node or null if there's none
*/
public final
Node traverseToLast() {
Node n =
selectLast();
if (
n != null)
focusAndNotify(
n);
return
n;
}
}