Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.scene.control;
027
028import java.util.ArrayList;
029import java.util.Collections;
030import java.util.List;
031import javafx.beans.InvalidationListener;
032import javafx.beans.property.IntegerProperty;
033import javafx.beans.property.ObjectProperty;
034import javafx.beans.property.ObjectPropertyBase;
035import javafx.beans.value.ChangeListener;
036import javafx.css.CssMetaData;
037import javafx.css.StyleableIntegerProperty;
038import javafx.css.StyleableObjectProperty;
039import javafx.css.StyleableProperty;
040import javafx.event.ActionEvent;
041import javafx.event.EventHandler;
042import javafx.geometry.Pos;
043import com.sun.javafx.binding.ExpressionHelper;
044import com.sun.javafx.css.converters.EnumConverter;
045import com.sun.javafx.css.converters.SizeConverter;
046import com.sun.javafx.scene.control.skin.TextFieldSkin;
047import javafx.css.Styleable;
048
049
050/**
051 * Text input component that allows a user to enter a single line of
052 * unformatted text. Unlike in previous releases of JavaFX, support for multi-line
053 * input is not available as part of the TextField control, however this is 
054 * the sole-purpose of the {@link TextArea} control. Additionally, if you want
055 * a form of rich-text editing, there is also the
056 * {@link javafx.scene.web.HTMLEditor HTMLEditor} control.
057 * 
058 * <p>TextField supports the notion of showing {@link #promptTextProperty() prompt text}
059 * to the user when there is no {@link #textProperty() text} already in the 
060 * TextField (either via the user, or set programmatically). This is a useful
061 * way of informing the user as to what is expected in the text field, without
062 * having to resort to {@link Tooltip tooltips} or on-screen {@link Label labels}.
063 * 
064 * @see TextArea
065 */
066public class TextField extends TextInputControl {
067    // Text field content
068    private static final class TextFieldContent implements Content {
069        private ExpressionHelper<String> helper = null;
070        private StringBuilder characters = new StringBuilder();
071
072        @Override public String get(int start, int end) {
073            return characters.substring(start, end);
074        }
075
076        @Override public void insert(int index, String text, boolean notifyListeners) {
077            text = TextInputControl.filterInput(text, true, true);
078            if (!text.isEmpty()) {
079                characters.insert(index, text);
080                if (notifyListeners) {
081                    ExpressionHelper.fireValueChangedEvent(helper);
082                }
083            }
084        }
085
086        @Override public void delete(int start, int end, boolean notifyListeners) {
087            if (end > start) {
088                characters.delete(start, end);
089                if (notifyListeners) {
090                    ExpressionHelper.fireValueChangedEvent(helper);
091                }
092            }
093        }
094
095        @Override public int length() {
096            return characters.length();
097        }
098
099        @Override public String get() {
100            return characters.toString();
101        }
102
103        @Override public void addListener(ChangeListener<? super String> changeListener) {
104            helper = ExpressionHelper.addListener(helper, this, changeListener);
105        }
106
107        @Override public void removeListener(ChangeListener<? super String> changeListener) {
108            helper = ExpressionHelper.removeListener(helper, changeListener);
109        }
110
111        @Override public String getValue() {
112            return get();
113        }
114
115        @Override public void addListener(InvalidationListener listener) {
116            helper = ExpressionHelper.addListener(helper, this, listener);
117        }
118
119        @Override public void removeListener(InvalidationListener listener) {
120            helper = ExpressionHelper.removeListener(helper, listener);
121        }
122    }
123
124    /**
125     * The default value for {@link #prefColumnCount}.
126     */
127    public static final int DEFAULT_PREF_COLUMN_COUNT = 12;
128
129    /**
130     * Creates a {@code TextField} with empty text content.
131     */
132    public TextField() {
133        this("");
134    }
135
136    /**
137     * Creates a {@code TextField} with initial text content.
138     *
139     * @param text A string for text content.
140     */
141    public TextField(String text) {
142        super(new TextFieldContent());
143        getStyleClass().add("text-field");
144        setText(text);
145    }
146
147    /**
148     * Returns the character sequence backing the text field's content.
149     */
150    public CharSequence getCharacters() {
151        return ((TextFieldContent)getContent()).characters;
152    }
153
154
155    /***************************************************************************
156     *                                                                         *
157     * Properties                                                              *
158     *                                                                         *
159     **************************************************************************/
160
161    /**
162     * The preferred number of text columns. This is used for
163     * calculating the {@code TextField}'s preferred width.
164     */
165    private IntegerProperty prefColumnCount = new StyleableIntegerProperty(DEFAULT_PREF_COLUMN_COUNT) {
166        @Override
167        public void set(int value) {
168            if (value < 0) {
169                throw new IllegalArgumentException("value cannot be negative.");
170            }
171
172            super.set(value);
173        }
174
175        @Override public CssMetaData<TextField,Number> getCssMetaData() {
176            return StyleableProperties.PREF_COLUMN_COUNT;
177        }
178
179        @Override
180        public Object getBean() {
181            return TextField.this;
182        }
183
184        @Override
185        public String getName() {
186            return "prefColumnCount";
187        }
188    };
189    public final IntegerProperty prefColumnCountProperty() { return prefColumnCount; }
190    public final int getPrefColumnCount() { return prefColumnCount.getValue(); }
191    public final void setPrefColumnCount(int value) { prefColumnCount.setValue(value); }
192
193
194    /**
195     * The action handler associated with this text field, or
196     * <tt>null</tt> if no action handler is assigned.
197     *
198     * The action handler is normally called when the user types the ENTER key.
199     */
200    private ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<EventHandler<ActionEvent>>() {
201        @Override
202        protected void invalidated() {
203            setEventHandler(ActionEvent.ACTION, get());
204        }
205
206        @Override
207        public Object getBean() {
208            return TextField.this;
209        }
210
211        @Override
212        public String getName() {
213            return "onAction";
214        }
215    };
216    public final ObjectProperty<EventHandler<ActionEvent>> onActionProperty() { return onAction; }
217    public final EventHandler<ActionEvent> getOnAction() { return onActionProperty().get(); }
218    public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set(value); }
219
220    /**
221     * Specifies how the text should be aligned when there is empty
222     * space within the TextField.
223     */
224    public final ObjectProperty<Pos> alignmentProperty() {
225        if (alignment == null) {
226            alignment = new StyleableObjectProperty<Pos>(Pos.CENTER_LEFT) {
227
228                @Override public CssMetaData<TextField,Pos> getCssMetaData() {
229                    return StyleableProperties.ALIGNMENT;
230                }
231
232                @Override public Object getBean() {
233                    return TextField.this;
234                }
235
236                @Override public String getName() {
237                    return "alignment";
238                }
239            };
240        }
241        return alignment;
242    }
243    private ObjectProperty<Pos> alignment;
244    public final void setAlignment(Pos value) { alignmentProperty().set(value); }
245    public final Pos getAlignment() { return alignment == null ? Pos.CENTER_LEFT : alignment.get(); }
246
247    /***************************************************************************
248     *                                                                         *
249     * Methods                                                                 *
250     *                                                                         *
251     **************************************************************************/
252
253    /** {@inheritDoc} */
254    @Override protected Skin<?> createDefaultSkin() {
255        return new TextFieldSkin(this);
256    }
257
258    /***************************************************************************
259     *                                                                         *
260     * Stylesheet Handling                                                     *
261     *                                                                         *
262     **************************************************************************/
263
264     /**
265      * @treatAsPrivate implementation detail
266      */
267    private static class StyleableProperties {
268        private static final CssMetaData<TextField, Pos> ALIGNMENT =
269            new CssMetaData<TextField, Pos>("-fx-alignment",
270                new EnumConverter<Pos>(Pos.class), Pos.CENTER_LEFT ) {
271
272            @Override public boolean isSettable(TextField n) {
273                return (n.alignment == null || !n.alignment.isBound());
274            }
275
276            @Override public StyleableProperty<Pos> getStyleableProperty(TextField n) {
277                return (StyleableProperty<Pos>)n.alignmentProperty();
278            }
279        };
280
281        private static final CssMetaData<TextField,Number> PREF_COLUMN_COUNT =
282            new CssMetaData<TextField,Number>("-fx-pref-column-count",
283                SizeConverter.getInstance(), DEFAULT_PREF_COLUMN_COUNT) {
284
285            @Override
286            public boolean isSettable(TextField n) {
287                return n.prefColumnCount == null || !n.prefColumnCount.isBound();
288            }
289
290            @Override
291            public StyleableProperty<Number> getStyleableProperty(TextField n) {
292                return (StyleableProperty<Number>)n.prefColumnCountProperty();
293            }
294        };
295
296        private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
297        static {
298            final List<CssMetaData<? extends Styleable, ?>> styleables =
299                new ArrayList<CssMetaData<? extends Styleable, ?>>(TextInputControl.getClassCssMetaData());
300            styleables.add(ALIGNMENT);
301            styleables.add(PREF_COLUMN_COUNT);
302            STYLEABLES = Collections.unmodifiableList(styleables);
303        }
304    }
305
306    /**
307     * @return The CssMetaData associated with this class, which may include the
308     * CssMetaData of its super classes.
309     */
310    public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
311        return StyleableProperties.STYLEABLES;
312    }
313
314    /**
315     * {@inheritDoc}
316     */
317    @Override
318    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
319        return getClassCssMetaData();
320    }
321}