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 com.sun.javafx.scene.control.behavior; 27 28 import javafx.event.Event; 29 import javafx.geometry.NodeOrientation; 30 import javafx.scene.Node; 31 import javafx.scene.Parent; 32 import javafx.scene.control.SelectionModel; 33 import javafx.scene.control.SingleSelectionModel; 34 import javafx.scene.control.Tab; 35 import javafx.scene.control.TabPane; 36 import javafx.scene.input.KeyCode; 37 import javafx.scene.input.MouseEvent; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 public class TabPaneBehavior extends BehaviorBase<TabPane> { 42 43 /************************************************************************** 44 * Setup KeyBindings * 45 *************************************************************************/ 46 private static final String HOME = "Home"; 47 private static final String END = "End"; 48 private static final String CTRL_PAGE_UP = "Ctrl_Page_Up"; 49 private static final String CTRL_PAGE_DOWN = "Ctrl_Page_Down"; 50 private static final String CTRL_TAB = "Ctrl_Tab"; 51 private static final String CTRL_SHIFT_TAB = "Ctrl_Shift_Tab"; 52 53 protected static final List<KeyBinding> TAB_PANE_BINDINGS = new ArrayList<>(); 54 static { 55 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.UP, "TraverseUp")); 56 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.DOWN, "TraverseDown")); 57 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.LEFT, "TraverseLeft")); 58 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.RIGHT, "TraverseRight")); 59 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.HOME, HOME)); 60 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.END, END)); 61 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.PAGE_UP, CTRL_PAGE_UP).ctrl()); 62 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.PAGE_DOWN, CTRL_PAGE_DOWN).ctrl()); 63 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.TAB, CTRL_TAB).ctrl()); 64 TAB_PANE_BINDINGS.add(new KeyBinding(KeyCode.TAB, CTRL_SHIFT_TAB).shift().ctrl()); 65 } 66 67 @Override protected void callAction(String name) { 68 boolean rtl = (getControl().getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT); 69 70 if (("TraverseLeft".equals(name) && !rtl) || 71 ("TraverseRight".equals(name) && rtl) || 72 "TraverseUp".equals(name)) { 73 if (getControl().isFocused()) { 74 selectPreviousTab(); 75 } 76 } else if (("TraverseRight".equals(name) && !rtl) || 77 ("TraverseLeft".equals(name) && rtl) || 78 "TraverseDown".equals(name)) { 79 if (getControl().isFocused()) { 80 selectNextTab(); 81 } 82 } else if (CTRL_TAB.equals(name) || CTRL_PAGE_DOWN.equals(name)) { 83 selectNextTab(); 84 } else if (CTRL_SHIFT_TAB.equals(name) || CTRL_PAGE_UP.equals(name)) { 85 selectPreviousTab(); 86 } else if (HOME.equals(name)) { 87 if (getControl().isFocused()) { 88 moveSelection(0, 1); 89 } 90 } else if (END.equals(name)) { 91 if (getControl().isFocused()) { 92 moveSelection(getControl().getTabs().size() - 1, -1); 93 } 94 } else { 95 super.callAction(name); 96 } 97 } 98 99 100 101 /*************************************************************************** 102 * * 103 * Mouse event handling * 104 * * 105 **************************************************************************/ 106 107 @Override public void mousePressed(MouseEvent e) { 108 super.mousePressed(e); 109 TabPane tp = getControl(); 110 tp.requestFocus(); 111 } 112 113 /************************************************************************** 114 * State and Functions * 115 *************************************************************************/ 116 117 public TabPaneBehavior(TabPane tabPane) { 118 super(tabPane, TAB_PANE_BINDINGS); 119 } 120 121 public void selectTab(Tab tab) { 122 getControl().getSelectionModel().select(tab); 123 } 124 125 public boolean canCloseTab(Tab tab) { 126 Event event = new Event(tab,tab,Tab.TAB_CLOSE_REQUEST_EVENT); 127 Event.fireEvent(tab, event); 128 return ! event.isConsumed(); 129 } 130 131 public void closeTab(Tab tab) { 132 TabPane tabPane = getControl(); 133 // only switch to another tab if the selected tab is the one we're closing 134 int index = tabPane.getTabs().indexOf(tab); 135 if (index != -1) { 136 tabPane.getTabs().remove(index); 137 } 138 if (tab.getOnClosed() != null) { 139 Event.fireEvent(tab, new Event(Tab.CLOSED_EVENT)); 140 } 141 } 142 143 // Find a tab after the currently selected that is not disabled. Loop around 144 // if no tabs are found after currently selected tab. 145 public void selectNextTab() { 146 moveSelection(1); 147 } 148 149 // Find a tab before the currently selected that is not disabled. 150 public void selectPreviousTab() { 151 moveSelection(-1); 152 } 153 154 private void moveSelection(int delta) { 155 moveSelection(getControl().getSelectionModel().getSelectedIndex(), delta); 156 } 157 158 private void moveSelection(int startIndex, int delta) { 159 final TabPane tabPane = getControl(); 160 int tabIndex = findValidTab(startIndex, delta); 161 if (tabIndex > -1) { 162 final SelectionModel<Tab> selectionModel = tabPane.getSelectionModel(); 163 selectionModel.select(tabIndex); 164 } 165 tabPane.requestFocus(); 166 } 167 168 private int findValidTab(int startIndex, int delta) { 169 final TabPane tabPane = getControl(); 170 final List<Tab> tabs = tabPane.getTabs(); 171 final int max = tabs.size(); 172 173 int index = startIndex; 174 do { 175 index = nextIndex(index + delta, max); 176 Tab tab = tabs.get(index); 177 if (tab != null && !tab.isDisable()) { 178 return index; 179 } 180 } while (index != startIndex); 181 182 return -1; 183 } 184 185 private int nextIndex(int value, int max) { 186 final int min = 0; 187 int r = value % max; 188 if (r > min && max < min) { 189 r = r + max - min; 190 } else if (r < min && max > min) { 191 r = r + max - min; 192 } 193 return r; 194 } 195 }