1 /* 2 * Copyright (c) 2010, 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 26 package javafx.scene.control.skin; 27 28 import com.sun.javafx.scene.NodeHelper; 29 import com.sun.javafx.scene.control.behavior.BehaviorBase; 30 import com.sun.javafx.scene.control.skin.Utils; 31 import javafx.scene.Node; 32 import javafx.scene.Scene; 33 import javafx.scene.control.Button; 34 import javafx.scene.control.ContextMenu; 35 import com.sun.javafx.scene.control.behavior.ButtonBehavior; 36 import javafx.scene.control.Control; 37 import javafx.scene.input.KeyCode; 38 import javafx.scene.input.KeyCodeCombination; 39 40 /** 41 * Default skin implementation for the {@link Button} control. 42 * 43 * @see Button 44 * @since 9 45 */ 46 public class ButtonSkin extends LabeledSkinBase<Button> { 47 48 /*************************************************************************** 49 * * 50 * Private fields * 51 * * 52 **************************************************************************/ 53 54 private KeyCodeCombination defaultAcceleratorKeyCodeCombination; 55 private KeyCodeCombination cancelAcceleratorKeyCodeCombination; 56 private final BehaviorBase<Button> behavior; 57 58 59 60 /*************************************************************************** 61 * * 62 * Listeners * 63 * * 64 **************************************************************************/ 65 66 Runnable defaultButtonRunnable = () -> { 67 if (getSkinnable().getScene() != null && NodeHelper.isTreeVisible(getSkinnable()) && !getSkinnable().isDisabled()) { 68 getSkinnable().fire(); 69 } 70 }; 71 72 Runnable cancelButtonRunnable = () -> { 73 if (getSkinnable().getScene() != null && NodeHelper.isTreeVisible(getSkinnable()) && !getSkinnable().isDisabled()) { 74 getSkinnable().fire(); 75 } 76 }; 77 78 79 80 /*************************************************************************** 81 * * 82 * Constructors * 83 * * 84 **************************************************************************/ 85 86 /** 87 * Creates a new ButtonSkin instance, installing the necessary child 88 * nodes into the Control {@link Control#getChildren() children} list, as 89 * well as the necessary input mappings for handling key, mouse, etc events. 90 * 91 * @param control The control that this skin should be installed onto. 92 */ 93 public ButtonSkin(Button control) { 94 super(control); 95 96 // install default input map for the Button control 97 behavior = new ButtonBehavior<>(control); 98 // control.setInputMap(behavior.getInputMap()); 99 100 // Register listeners 101 registerChangeListener(control.defaultButtonProperty(), o -> setDefaultButton(getSkinnable().isDefaultButton())); 102 registerChangeListener(control.cancelButtonProperty(), o -> setCancelButton(getSkinnable().isCancelButton())); 103 registerChangeListener(control.focusedProperty(), o -> { 104 if (!getSkinnable().isFocused()) { 105 ContextMenu cm = getSkinnable().getContextMenu(); 106 if (cm != null) { 107 if (cm.isShowing()) { 108 cm.hide(); 109 Utils.removeMnemonics(cm, getSkinnable().getScene()); 110 } 111 } 112 } 113 }); 114 registerChangeListener(control.parentProperty(), o -> { 115 if (getSkinnable().getParent() == null && getSkinnable().getScene() != null) { 116 if (getSkinnable().isDefaultButton()) { 117 getSkinnable().getScene().getAccelerators().remove(defaultAcceleratorKeyCodeCombination); 118 } 119 if (getSkinnable().isCancelButton()) { 120 getSkinnable().getScene().getAccelerators().remove(cancelAcceleratorKeyCodeCombination); 121 } 122 } 123 }); 124 125 // set visuals 126 if (getSkinnable().isDefaultButton()) { 127 /* 128 ** were we already the defaultButton, before the listener was added? 129 ** don't laugh, it can happen.... 130 */ 131 setDefaultButton(true); 132 } 133 134 if (getSkinnable().isCancelButton()) { 135 /* 136 ** were we already the defaultButton, before the listener was added? 137 ** don't laugh, it can happen.... 138 */ 139 setCancelButton(true); 140 } 141 } 142 143 144 145 /*************************************************************************** 146 * * 147 * Public API * 148 * * 149 **************************************************************************/ 150 151 /** {@inheritDoc} */ 152 @Override public void dispose() { 153 super.dispose(); 154 155 if (behavior != null) { 156 behavior.dispose(); 157 } 158 } 159 160 161 162 /*************************************************************************** 163 * * 164 * Private implementation * 165 * * 166 **************************************************************************/ 167 168 private void setDefaultButton(boolean value) { 169 Scene scene = getSkinnable().getScene(); 170 if (scene != null) { 171 KeyCode acceleratorCode = KeyCode.ENTER; 172 defaultAcceleratorKeyCodeCombination = new KeyCodeCombination(acceleratorCode); 173 174 Runnable oldDefault = scene.getAccelerators().get(defaultAcceleratorKeyCodeCombination); 175 if (!value) { 176 /** 177 * first check of there's a default button already 178 */ 179 if (defaultButtonRunnable.equals(oldDefault)) { 180 /** 181 * is it us? 182 */ 183 scene.getAccelerators().remove(defaultAcceleratorKeyCodeCombination); 184 } 185 } 186 else { 187 if (!defaultButtonRunnable.equals(oldDefault)) { 188 scene.getAccelerators().remove(defaultAcceleratorKeyCodeCombination); 189 scene.getAccelerators().put(defaultAcceleratorKeyCodeCombination, defaultButtonRunnable); 190 } 191 } 192 } 193 } 194 195 private void setCancelButton(boolean value) { 196 Scene scene = getSkinnable().getScene(); 197 if (scene != null) { 198 KeyCode acceleratorCode = KeyCode.ESCAPE; 199 cancelAcceleratorKeyCodeCombination = new KeyCodeCombination(acceleratorCode); 200 201 Runnable oldCancel = scene.getAccelerators().get(cancelAcceleratorKeyCodeCombination); 202 if (!value) { 203 /** 204 * first check of there's a cancel button already 205 */ 206 if (cancelButtonRunnable.equals(oldCancel)) { 207 /** 208 * is it us? 209 */ 210 scene.getAccelerators().remove(cancelAcceleratorKeyCodeCombination); 211 } 212 } 213 else { 214 if (!cancelButtonRunnable.equals(oldCancel)) { 215 scene.getAccelerators().remove(cancelAcceleratorKeyCodeCombination); 216 scene.getAccelerators().put(cancelAcceleratorKeyCodeCombination, cancelButtonRunnable); 217 } 218 } 219 } 220 } 221 }