1 /* 2 * Copyright (c) 2011, 2017, 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; 27 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.List; 31 32 import javafx.beans.InvalidationListener; 33 import javafx.beans.property.IntegerProperty; 34 import javafx.beans.property.ObjectProperty; 35 import javafx.beans.property.ObjectPropertyBase; 36 import javafx.beans.value.ChangeListener; 37 import javafx.beans.value.WritableValue; 38 import javafx.css.CssMetaData; 39 import javafx.css.StyleableIntegerProperty; 40 import javafx.css.StyleableObjectProperty; 41 import javafx.css.StyleableProperty; 42 import javafx.event.ActionEvent; 43 import javafx.event.EventHandler; 44 import javafx.geometry.Pos; 45 import javafx.scene.AccessibleRole; 46 47 import com.sun.javafx.binding.ExpressionHelper; 48 import javafx.css.converter.EnumConverter; 49 import javafx.css.converter.SizeConverter; 50 import javafx.scene.control.skin.TextFieldSkin; 51 52 import javafx.css.Styleable; 53 54 55 /** 56 * Text input component that allows a user to enter a single line of 57 * unformatted text. Unlike in previous releases of JavaFX, support for multi-line 58 * input is not available as part of the TextField control, however this is 59 * the sole-purpose of the {@link TextArea} control. Additionally, if you want 60 * a form of rich-text editing, there is also the 61 * {@link javafx.scene.web.HTMLEditor HTMLEditor} control. 62 * 63 * <p>TextField supports the notion of showing {@link #promptTextProperty() prompt text} 64 * to the user when there is no {@link #textProperty() text} already in the 65 * TextField (either via the user, or set programmatically). This is a useful 66 * way of informing the user as to what is expected in the text field, without 67 * having to resort to {@link Tooltip tooltips} or on-screen {@link Label labels}. 68 * 69 * @see TextArea 70 * @since JavaFX 2.0 71 */ 72 public class TextField extends TextInputControl { 73 // Text field content 74 private static final class TextFieldContent implements Content { 75 private ExpressionHelper<String> helper = null; 76 private StringBuilder characters = new StringBuilder(); 77 78 @Override public String get(int start, int end) { 79 return characters.substring(start, end); 80 } 81 82 @Override public void insert(int index, String text, boolean notifyListeners) { 83 text = TextInputControl.filterInput(text, true, true); 84 if (!text.isEmpty()) { 85 characters.insert(index, text); 86 if (notifyListeners) { 87 ExpressionHelper.fireValueChangedEvent(helper); 88 } 89 } 90 } 91 92 @Override public void delete(int start, int end, boolean notifyListeners) { 93 if (end > start) { 94 characters.delete(start, end); 95 if (notifyListeners) { 96 ExpressionHelper.fireValueChangedEvent(helper); 97 } 98 } 99 } 100 101 @Override public int length() { 102 return characters.length(); 103 } 104 105 @Override public String get() { 106 return characters.toString(); 107 } 108 109 @Override public void addListener(ChangeListener<? super String> changeListener) { 110 helper = ExpressionHelper.addListener(helper, this, changeListener); 111 } 112 113 @Override public void removeListener(ChangeListener<? super String> changeListener) { 114 helper = ExpressionHelper.removeListener(helper, changeListener); 115 } 116 117 @Override public String getValue() { 118 return get(); 119 } 120 121 @Override public void addListener(InvalidationListener listener) { 122 helper = ExpressionHelper.addListener(helper, this, listener); 123 } 124 125 @Override public void removeListener(InvalidationListener listener) { 126 helper = ExpressionHelper.removeListener(helper, listener); 127 } 128 } 129 130 /** 131 * The default value for {@link #prefColumnCountProperty() prefColumnCount}. 132 */ 133 public static final int DEFAULT_PREF_COLUMN_COUNT = 12; 134 135 /** 136 * Creates a {@code TextField} with empty text content. 137 */ 138 public TextField() { 139 this(""); 140 } 141 142 /** 143 * Creates a {@code TextField} with initial text content. 144 * 145 * @param text A string for text content. 146 */ 147 public TextField(String text) { 148 super(new TextFieldContent()); 149 getStyleClass().add("text-field"); 150 setAccessibleRole(AccessibleRole.TEXT_FIELD); 151 setText(text); 152 } 153 154 /** 155 * Returns the character sequence backing the text field's content. 156 * @return the character sequence backing the text field's content 157 */ 158 public CharSequence getCharacters() { 159 return ((TextFieldContent)getContent()).characters; 160 } 161 162 163 /*************************************************************************** 164 * * 165 * Properties * 166 * * 167 **************************************************************************/ 168 169 /** 170 * The preferred number of text columns. This is used for 171 * calculating the {@code TextField}'s preferred width. 172 */ 173 private IntegerProperty prefColumnCount = new StyleableIntegerProperty(DEFAULT_PREF_COLUMN_COUNT) { 174 175 private int oldValue = get(); 176 177 @Override 178 protected void invalidated() { 179 int value = get(); 180 if (value < 0) { 181 if (isBound()) { 182 unbind(); 183 } 184 set(oldValue); 185 throw new IllegalArgumentException("value cannot be negative."); 186 } 187 oldValue = value; 188 } 189 190 @Override public CssMetaData<TextField,Number> getCssMetaData() { 191 return StyleableProperties.PREF_COLUMN_COUNT; 192 } 193 194 @Override 195 public Object getBean() { 196 return TextField.this; 197 } 198 199 @Override 200 public String getName() { 201 return "prefColumnCount"; 202 } 203 }; 204 public final IntegerProperty prefColumnCountProperty() { return prefColumnCount; } 205 public final int getPrefColumnCount() { return prefColumnCount.getValue(); } 206 public final void setPrefColumnCount(int value) { prefColumnCount.setValue(value); } 207 208 209 /** 210 * The action handler associated with this text field, or 211 * {@code null} if no action handler is assigned. 212 * 213 * The action handler is normally called when the user types the ENTER key. 214 */ 215 private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() { 216 @Override 217 protected void invalidated() { 218 setEventHandler(ActionEvent.ACTION, get()); 219 } 220 221 @Override 222 public Object getBean() { 223 return TextField.this; 224 } 225 226 @Override 227 public String getName() { 228 return "onAction"; 229 } 230 }; 231 public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; } 232 public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); } 233 public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); } 234 235 /** 236 * Specifies how the text should be aligned when there is empty 237 * space within the TextField. 238 * @return the alignment property 239 * @since JavaFX 2.1 240 */ 241 public final ObjectProperty<Pos> alignmentProperty() { 242 if (alignment == null) { 243 alignment = new StyleableObjectProperty<Pos>(Pos.CENTER_LEFT) { 244 245 @Override public CssMetaData<TextField,Pos> getCssMetaData() { 246 return StyleableProperties.ALIGNMENT; 247 } 248 249 @Override public Object getBean() { 250 return TextField.this; 251 } 252 253 @Override public String getName() { 254 return "alignment"; 255 } 256 }; 257 } 258 return alignment; 259 } 260 private ObjectProperty<Pos> alignment; 261 public final void setAlignment(Pos value) { alignmentProperty().set(value); } 262 public final Pos getAlignment() { return alignment == null ? Pos.CENTER_LEFT : alignment.get(); } 263 264 /*************************************************************************** 265 * * 266 * Methods * 267 * * 268 **************************************************************************/ 269 270 /** {@inheritDoc} */ 271 @Override protected Skin<?> createDefaultSkin() { 272 return new TextFieldSkin(this); 273 } 274 275 /*************************************************************************** 276 * * 277 * Stylesheet Handling * 278 * * 279 **************************************************************************/ 280 281 private static class StyleableProperties { 282 private static final CssMetaData<TextField, Pos> ALIGNMENT = 283 new CssMetaData<TextField, Pos>("-fx-alignment", 284 new EnumConverter<Pos>(Pos.class), Pos.CENTER_LEFT ) { 285 286 @Override public boolean isSettable(TextField n) { 287 return (n.alignment == null || !n.alignment.isBound()); 288 } 289 290 @Override public StyleableProperty<Pos> getStyleableProperty(TextField n) { 291 return (StyleableProperty<Pos>)(WritableValue<Pos>)n.alignmentProperty(); 292 } 293 }; 294 295 private static final CssMetaData<TextField,Number> PREF_COLUMN_COUNT = 296 new CssMetaData<TextField,Number>("-fx-pref-column-count", 297 SizeConverter.getInstance(), DEFAULT_PREF_COLUMN_COUNT) { 298 299 @Override 300 public boolean isSettable(TextField n) { 301 return n.prefColumnCount == null || !n.prefColumnCount.isBound(); 302 } 303 304 @Override 305 public StyleableProperty<Number> getStyleableProperty(TextField n) { 306 return (StyleableProperty<Number>)(WritableValue<Number>)n.prefColumnCountProperty(); 307 } 308 }; 309 310 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 311 static { 312 final List<CssMetaData<? extends Styleable, ?>> styleables = 313 new ArrayList<CssMetaData<? extends Styleable, ?>>(TextInputControl.getClassCssMetaData()); 314 styleables.add(ALIGNMENT); 315 styleables.add(PREF_COLUMN_COUNT); 316 STYLEABLES = Collections.unmodifiableList(styleables); 317 } 318 } 319 320 /** 321 * @return The CssMetaData associated with this class, which may include the 322 * CssMetaData of its superclasses. 323 * @since JavaFX 8.0 324 */ 325 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 326 return StyleableProperties.STYLEABLES; 327 } 328 329 /** 330 * {@inheritDoc} 331 * @since JavaFX 8.0 332 */ 333 @Override 334 public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { 335 return getClassCssMetaData(); 336 } 337 }