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 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 #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 */ 157 public CharSequence getCharacters() { 158 return ((TextFieldContent)getContent()).characters; 159 } 160 161 162 /*************************************************************************** 163 * * 164 * Properties * 165 * * 166 **************************************************************************/ 167 168 /** 169 * The preferred number of text columns. This is used for 170 * calculating the {@code TextField}'s preferred width. 171 */ 172 private IntegerProperty prefColumnCount = new StyleableIntegerProperty(DEFAULT_PREF_COLUMN_COUNT) { 173 174 private int oldValue = get(); 175 176 @Override 177 protected void invalidated() { 178 int value = get(); 179 if (value < 0) { 180 if (isBound()) { 181 unbind(); 182 } 183 set(oldValue); 184 throw new IllegalArgumentException("value cannot be negative."); 185 } 186 oldValue = value; 187 } 188 189 @Override public CssMetaData<TextField,Number> getCssMetaData() { 190 return StyleableProperties.PREF_COLUMN_COUNT; 191 } 192 193 @Override 194 public Object getBean() { 195 return TextField.this; 196 } 197 198 @Override 199 public String getName() { 200 return "prefColumnCount"; 201 } 202 }; 203 public final IntegerProperty prefColumnCountProperty() { return prefColumnCount; } 204 public final int getPrefColumnCount() { return prefColumnCount.getValue(); } 205 public final void setPrefColumnCount(int value) { prefColumnCount.setValue(value); } 206 207 208 /** 209 * The action handler associated with this text field, or 210 * <tt>null</tt> if no action handler is assigned. 211 * 212 * The action handler is normally called when the user types the ENTER key. 213 */ 214 private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() { 215 @Override 216 protected void invalidated() { 217 setEventHandler(ActionEvent.ACTION, get()); 218 } 219 220 @Override 221 public Object getBean() { 222 return TextField.this; 223 } 224 225 @Override 226 public String getName() { 227 return "onAction"; 228 } 229 }; 230 public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; } 231 public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); } 232 public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); } 233 234 /** 235 * Specifies how the text should be aligned when there is empty 236 * space within the TextField. 237 * @since JavaFX 2.1 238 */ 239 public final ObjectProperty<Pos> alignmentProperty() { 240 if (alignment == null) { 241 alignment = new StyleableObjectProperty<Pos>(Pos.CENTER_LEFT) { 242 243 @Override public CssMetaData<TextField,Pos> getCssMetaData() { 244 return StyleableProperties.ALIGNMENT; 245 } 246 247 @Override public Object getBean() { 248 return TextField.this; 249 } 250 251 @Override public String getName() { 252 return "alignment"; 253 } 254 }; 255 } 256 return alignment; 257 } 258 private ObjectProperty<Pos> alignment; 259 public final void setAlignment(Pos value) { alignmentProperty().set(value); } 260 public final Pos getAlignment() { return alignment == null ? Pos.CENTER_LEFT : alignment.get(); } 261 262 /*************************************************************************** 263 * * 264 * Methods * 265 * * 266 **************************************************************************/ 267 268 /** {@inheritDoc} */ 269 @Override protected Skin<?> createDefaultSkin() { 270 return new TextFieldSkin(this); 271 } 272 273 /*************************************************************************** 274 * * 275 * Stylesheet Handling * 276 * * 277 **************************************************************************/ 278 279 /** 280 * @treatAsPrivate implementation detail 281 */ 282 private static class StyleableProperties { 283 private static final CssMetaData<TextField, Pos> ALIGNMENT = 284 new CssMetaData<TextField, Pos>("-fx-alignment", 285 new EnumConverter<Pos>(Pos.class), Pos.CENTER_LEFT ) { 286 287 @Override public boolean isSettable(TextField n) { 288 return (n.alignment == null || !n.alignment.isBound()); 289 } 290 291 @Override public StyleableProperty<Pos> getStyleableProperty(TextField n) { 292 return (StyleableProperty<Pos>)(WritableValue<Pos>)n.alignmentProperty(); 293 } 294 }; 295 296 private static final CssMetaData<TextField,Number> PREF_COLUMN_COUNT = 297 new CssMetaData<TextField,Number>("-fx-pref-column-count", 298 SizeConverter.getInstance(), DEFAULT_PREF_COLUMN_COUNT) { 299 300 @Override 301 public boolean isSettable(TextField n) { 302 return n.prefColumnCount == null || !n.prefColumnCount.isBound(); 303 } 304 305 @Override 306 public StyleableProperty<Number> getStyleableProperty(TextField n) { 307 return (StyleableProperty<Number>)(WritableValue<Number>)n.prefColumnCountProperty(); 308 } 309 }; 310 311 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 312 static { 313 final List<CssMetaData<? extends Styleable, ?>> styleables = 314 new ArrayList<CssMetaData<? extends Styleable, ?>>(TextInputControl.getClassCssMetaData()); 315 styleables.add(ALIGNMENT); 316 styleables.add(PREF_COLUMN_COUNT); 317 STYLEABLES = Collections.unmodifiableList(styleables); 318 } 319 } 320 321 /** 322 * @return The CssMetaData associated with this class, which may include the 323 * CssMetaData of its super classes. 324 * @since JavaFX 8.0 325 */ 326 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 327 return StyleableProperties.STYLEABLES; 328 } 329 330 /** 331 * {@inheritDoc} 332 * @since JavaFX 8.0 333 */ 334 @Override 335 public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() { 336 return getClassCssMetaData(); 337 } 338 }