1 /*
   2  * Copyright (c) 2015, 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 package com.sun.javafx.scene.control.behavior;
  26 
  27 import com.sun.javafx.scene.traversal.Direction;
  28 import javafx.event.EventTarget;
  29 import javafx.scene.Node;
  30 import com.sun.javafx.scene.control.inputmap.InputMap;
  31 import com.sun.javafx.scene.control.inputmap.KeyBinding;
  32 import javafx.scene.input.KeyEvent;
  33 
  34 import java.util.ArrayList;
  35 import java.util.List;
  36 
  37 import static com.sun.javafx.scene.control.inputmap.InputMap.*;
  38 import static javafx.scene.input.KeyCode.DOWN;
  39 import static javafx.scene.input.KeyCode.LEFT;
  40 import static javafx.scene.input.KeyCode.RIGHT;
  41 import static javafx.scene.input.KeyCode.TAB;
  42 import static javafx.scene.input.KeyCode.UP;
  43 
  44 public class FocusTraversalInputMap<N extends Node> {
  45 
  46     private static final List<InputMap.Mapping<?>> mappings = new ArrayList<>();
  47     static {
  48         mappings.add(new KeyMapping(UP, e -> traverseUp(e)));
  49         mappings.add(new KeyMapping(DOWN, e -> traverseDown(e)));
  50         mappings.add(new KeyMapping(LEFT, e -> traverseLeft(e)));
  51         mappings.add(new KeyMapping(RIGHT, e -> traverseRight(e)));
  52         mappings.add(new KeyMapping(TAB, e -> traverseNext(e)));
  53         mappings.add(new KeyMapping(new KeyBinding(TAB).shift(), e -> traversePrevious(e)));
  54 
  55         mappings.add(new KeyMapping(new KeyBinding(UP).shift().alt().ctrl(), e -> traverseUp(e)));
  56         mappings.add(new KeyMapping(new KeyBinding(DOWN).shift().alt().ctrl(), e -> traverseDown(e)));
  57         mappings.add(new KeyMapping(new KeyBinding(LEFT).shift().alt().ctrl(), e -> traverseLeft(e)));
  58         mappings.add(new KeyMapping(new KeyBinding(RIGHT).shift().alt().ctrl(), e -> traverseRight(e)));
  59         mappings.add(new KeyMapping(new KeyBinding(TAB).shift().alt().ctrl(), e -> traverseNext(e)));
  60         mappings.add(new KeyMapping(new KeyBinding(TAB).alt().ctrl(), e -> traversePrevious(e)));
  61     }
  62 
  63     private FocusTraversalInputMap() {
  64         // no-op, just forcing use of static method
  65     }
  66 
  67     public static InputMap.Mapping<?>[] getFocusTraversalMappings() {
  68         return mappings.toArray(new InputMap.Mapping[mappings.size()]);
  69     }
  70 
  71     public static <N extends Node> InputMap<N> createInputMap(N node) {
  72         InputMap<N> inputMap = new InputMap<>(node);
  73         inputMap.getMappings().addAll(getFocusTraversalMappings());
  74         return inputMap;
  75     }
  76 
  77 
  78 
  79     /***************************************************************************
  80      * Focus Traversal methods                                                 *
  81      **************************************************************************/
  82 
  83     /**
  84      * Called by any of the BehaviorBase traverse methods to actually effect a
  85      * traversal of the focus. The default behavior of this method is to simply
  86      * call impl_traverse on the given node, passing the given direction. A
  87      * subclass may override this method.
  88      *
  89      * @param node The node to call impl_traverse on
  90      * @param dir The direction to traverse
  91      */
  92     public static void traverse(final Node node, final Direction dir) {
  93         if (node == null) {
  94             throw new IllegalArgumentException("Attempting to traverse on a null Node. " +
  95                     "Most probably a KeyEvent has been fired with a null target specified.");
  96         }
  97         node.impl_traverse(dir);
  98     }
  99 
 100     /**
 101      * Calls the focus traversal engine and indicates that traversal should
 102      * go the next focusTraversable Node above the current one.
 103      */
 104     public static final void traverseUp(KeyEvent e) {
 105         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.UP);
 106     }
 107 
 108     /**
 109      * Calls the focus traversal engine and indicates that traversal should
 110      * go the next focusTraversable Node below the current one.
 111      */
 112     public static final void traverseDown(KeyEvent e) {
 113         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.DOWN);
 114     }
 115 
 116     /**
 117      * Calls the focus traversal engine and indicates that traversal should
 118      * go the next focusTraversable Node left of the current one.
 119      */
 120     public static final void traverseLeft(KeyEvent e) {
 121         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.LEFT);
 122     }
 123 
 124     /**
 125      * Calls the focus traversal engine and indicates that traversal should
 126      * go the next focusTraversable Node right of the current one.
 127      */
 128     public static final void traverseRight(KeyEvent e) {
 129         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.RIGHT);
 130     }
 131 
 132     /**
 133      * Calls the focus traversal engine and indicates that traversal should
 134      * go the next focusTraversable Node in the focus traversal cycle.
 135      */
 136     public static final void traverseNext(KeyEvent e) {
 137         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.NEXT);
 138     }
 139 
 140     /**
 141      * Calls the focus traversal engine and indicates that traversal should
 142      * go the previous focusTraversable Node in the focus traversal cycle.
 143      */
 144     public static final void traversePrevious(KeyEvent e) {
 145         traverse(getNode(e), com.sun.javafx.scene.traversal.Direction.PREVIOUS);
 146     }
 147 
 148     private static Node getNode(KeyEvent e) {
 149         EventTarget target = e.getTarget();
 150         if (target instanceof Node) {
 151             return (Node) target;
 152         }
 153         return null;
 154     }
 155 }