< prev index next >

modules/controls/src/main/java/javafx/scene/control/skin/TextFieldSkin.java

Print this page

        

*** 1,7 **** /* ! * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this --- 1,7 ---- /* ! * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 26,36 **** package javafx.scene.control.skin; import com.sun.javafx.scene.control.behavior.BehaviorBase; import com.sun.javafx.scene.control.behavior.TextAreaBehavior; import com.sun.javafx.scene.control.behavior.TextInputControlBehavior; - import com.sun.javafx.scene.control.skin.Utils; import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.DoubleBinding; import javafx.beans.binding.ObjectBinding; import javafx.beans.binding.StringBinding; import javafx.beans.property.DoubleProperty; --- 26,35 ----
*** 57,70 **** import javafx.scene.paint.Paint; import javafx.scene.shape.Path; import javafx.scene.shape.PathElement; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; import java.util.List; import com.sun.javafx.scene.control.behavior.TextFieldBehavior; import com.sun.javafx.scene.control.behavior.PasswordFieldBehavior; - import com.sun.javafx.scene.text.HitInfo; /** * Default skin implementation for the {@link TextField} control. * * @see TextField --- 56,69 ---- import javafx.scene.paint.Paint; import javafx.scene.shape.Path; import javafx.scene.shape.PathElement; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; + import javafx.scene.text.HitInfo; import java.util.List; import com.sun.javafx.scene.control.behavior.TextFieldBehavior; import com.sun.javafx.scene.control.behavior.PasswordFieldBehavior; /** * Default skin implementation for the {@link TextField} control. * * @see TextField
*** 210,220 **** @Override protected String computeValue() { return maskText(control.textProperty().getValueSafe()); } }); textNode.fillProperty().bind(textFillProperty()); ! textNode.impl_selectionFillProperty().bind(new ObjectBinding<Paint>() { { bind(highlightTextFillProperty(), textFillProperty(), control.focusedProperty()); } @Override protected Paint computeValue() { return control.isFocused() ? highlightTextFillProperty().get() : textFillProperty().get(); } }); --- 209,219 ---- @Override protected String computeValue() { return maskText(control.textProperty().getValueSafe()); } }); textNode.fillProperty().bind(textFillProperty()); ! textNode.selectionFillProperty().bind(new ObjectBinding<Paint>() { { bind(highlightTextFillProperty(), textFillProperty(), control.focusedProperty()); } @Override protected Paint computeValue() { return control.isFocused() ? highlightTextFillProperty().get() : textFillProperty().get(); } });
*** 228,238 **** selectionHighlightPath.setManaged(false); selectionHighlightPath.setStroke(null); selectionHighlightPath.layoutXProperty().bind(textTranslateX); selectionHighlightPath.visibleProperty().bind(control.anchorProperty().isNotEqualTo(control.caretPositionProperty()).and(control.focusedProperty())); selectionHighlightPath.fillProperty().bind(highlightFillProperty()); ! textNode.impl_selectionShapeProperty().addListener(observable -> { updateSelection(); }); // Add caret caretPath.setManaged(false); --- 227,237 ---- selectionHighlightPath.setManaged(false); selectionHighlightPath.setStroke(null); selectionHighlightPath.layoutXProperty().bind(textTranslateX); selectionHighlightPath.visibleProperty().bind(control.anchorProperty().isNotEqualTo(control.caretPositionProperty()).and(control.focusedProperty())); selectionHighlightPath.fillProperty().bind(highlightFillProperty()); ! textNode.selectionShapeProperty().addListener(observable -> { updateSelection(); }); // Add caret caretPath.setManaged(false);
*** 247,258 **** @Override protected double computeValue() { return caretVisibleProperty().get() ? 1.0 : 0.0; } }); caretPath.layoutXProperty().bind(textTranslateX); ! textNode.impl_caretShapeProperty().addListener(observable -> { ! caretPath.getElements().setAll(textNode.impl_caretShapeProperty().get()); if (caretPath.getElements().size() == 0) { // The caret pos is invalid. updateTextNodeCaretPos(control.getCaretPosition()); } else if (caretPath.getElements().size() == 4) { // The caret is split. Ignore and keep the previous width value. --- 246,257 ---- @Override protected double computeValue() { return caretVisibleProperty().get() ? 1.0 : 0.0; } }); caretPath.layoutXProperty().bind(textTranslateX); ! textNode.caretShapeProperty().addListener(observable -> { ! caretPath.getElements().setAll(textNode.caretShapeProperty().get()); if (caretPath.getElements().size() == 0) { // The caret pos is invalid. updateTextNodeCaretPos(control.getCaretPosition()); } else if (caretPath.getElements().size() == 4) { // The caret is split. Ignore and keep the previous width value.
*** 329,360 **** selectionHandle2.setOnMousePressed(handlePressHandler); caretHandle.setOnMouseDragged(e -> { Point2D p = new Point2D(caretHandle.getLayoutX() + e.getX() + pressX - textNode.getLayoutX(), caretHandle.getLayoutY() + e.getY() - pressY - 6); ! HitInfo hit = textNode.impl_hitTestChar(p); positionCaret(hit, false); e.consume(); }); selectionHandle1.setOnMouseDragged(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { TextField control = getSkinnable(); Point2D tp = textNode.localToScene(0, 0); Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle1.getWidth() / 2, e.getSceneY() - tp.getY() - pressY - 6); ! HitInfo hit = textNode.impl_hitTestChar(p); ! int pos = hit.getCharIndex(); if (control.getAnchor() < control.getCaretPosition()) { // Swap caret and anchor control.selectRange(control.getCaretPosition(), control.getAnchor()); } if (pos >= 0) { if (pos >= control.getAnchor() - 1) { ! hit.setCharIndex(Math.max(0, control.getAnchor() - 1)); } ! positionCaret(hit, true); } e.consume(); } }); --- 328,359 ---- selectionHandle2.setOnMousePressed(handlePressHandler); caretHandle.setOnMouseDragged(e -> { Point2D p = new Point2D(caretHandle.getLayoutX() + e.getX() + pressX - textNode.getLayoutX(), caretHandle.getLayoutY() + e.getY() - pressY - 6); ! HitInfo hit = textNode.hitTest(p); positionCaret(hit, false); e.consume(); }); selectionHandle1.setOnMouseDragged(new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent e) { TextField control = getSkinnable(); Point2D tp = textNode.localToScene(0, 0); Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle1.getWidth() / 2, e.getSceneY() - tp.getY() - pressY - 6); ! HitInfo hit = textNode.hitTest(p); if (control.getAnchor() < control.getCaretPosition()) { // Swap caret and anchor control.selectRange(control.getCaretPosition(), control.getAnchor()); } + int pos = hit.getInsertionIndex(); if (pos >= 0) { if (pos >= control.getAnchor() - 1) { ! pos = Math.max(0, control.getAnchor() - 1); } ! positionCaret(pos, hit.isLeading(), true); } e.consume(); } });
*** 362,382 **** @Override public void handle(MouseEvent e) { TextField control = getSkinnable(); Point2D tp = textNode.localToScene(0, 0); Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle2.getWidth() / 2, e.getSceneY() - tp.getY() - pressY - 6); ! HitInfo hit = textNode.impl_hitTestChar(p); ! int pos = hit.getCharIndex(); if (control.getAnchor() > control.getCaretPosition()) { // Swap caret and anchor control.selectRange(control.getCaretPosition(), control.getAnchor()); } if (pos > 0) { if (pos <= control.getAnchor()) { ! hit.setCharIndex(Math.min(control.getAnchor() + 1, control.getLength())); } ! positionCaret(hit, true); } e.consume(); } }); } --- 361,381 ---- @Override public void handle(MouseEvent e) { TextField control = getSkinnable(); Point2D tp = textNode.localToScene(0, 0); Point2D p = new Point2D(e.getSceneX() - tp.getX() + 10/*??*/ - pressX + selectionHandle2.getWidth() / 2, e.getSceneY() - tp.getY() - pressY - 6); ! HitInfo hit = textNode.hitTest(p); if (control.getAnchor() > control.getCaretPosition()) { // Swap caret and anchor control.selectRange(control.getCaretPosition(), control.getAnchor()); } + int pos = hit.getInsertionIndex(); if (pos > 0) { if (pos <= control.getAnchor()) { ! pos = Math.min(control.getAnchor() + 1, control.getLength()); } ! positionCaret(pos, hit.isLeading(), true); } e.consume(); } }); }
*** 476,517 **** /** * Performs a hit test, mapping point to index in the content. * * @param x the x coordinate of the point. * @param y the y coordinate of the point. ! * @return a {@code TextPosInfo} object describing the index and forward bias. */ ! public TextPosInfo getIndex(double x, double y) { // adjust the event to be in the same coordinate space as the // text content of the textInputControl Point2D p = new Point2D(x - textTranslateX.get() - snappedLeftInset(), y - snappedTopInset()); ! return new TextPosInfo(textNode.impl_hitTestChar(p)); } // Public for behavior /** * Moves the caret to the specified position. * * @param hit the new position and forward bias of the caret. * @param select whether to extend selection to the new position. */ ! public void positionCaret(TextPosInfo hit, boolean select) { ! TextField textField = getSkinnable(); ! int pos = Utils.getHitInsertionIndex(hit, textField.textProperty().getValueSafe()); if (select) { textField.selectPositionCaret(pos); } else { textField.positionCaret(pos); } ! ! setForwardBias(hit.isLeading()); ! } ! ! private void positionCaret(HitInfo hit, boolean select) { ! positionCaret(new TextPosInfo(hit), select); } /** {@inheritDoc} */ @Override public Rectangle2D getCharacterBounds(int index) { double x, y; --- 475,513 ---- /** * Performs a hit test, mapping point to index in the content. * * @param x the x coordinate of the point. * @param y the y coordinate of the point. ! * @return a {@code HitInfo} object describing the index and forward bias. */ ! public HitInfo getIndex(double x, double y) { // adjust the event to be in the same coordinate space as the // text content of the textInputControl Point2D p = new Point2D(x - textTranslateX.get() - snappedLeftInset(), y - snappedTopInset()); ! return textNode.hitTest(p); } // Public for behavior /** * Moves the caret to the specified position. * * @param hit the new position and forward bias of the caret. * @param select whether to extend selection to the new position. */ ! public void positionCaret(HitInfo hit, boolean select) { ! positionCaret(hit.getInsertionIndex(), hit.isLeading(), select); ! } + private void positionCaret(int pos, boolean leading, boolean select) { + TextField textField = getSkinnable(); if (select) { textField.selectPositionCaret(pos); } else { textField.positionCaret(pos); } ! setForwardBias(leading); } /** {@inheritDoc} */ @Override public Rectangle2D getCharacterBounds(int index) { double x, y;
*** 522,532 **** y = 0; width = 0; height = textNodeBounds.getMaxY(); } else { characterBoundingPath.getElements().clear(); ! characterBoundingPath.getElements().addAll(textNode.impl_getRangeShape(index, index + 1)); characterBoundingPath.setLayoutX(textNode.getLayoutX()); characterBoundingPath.setLayoutY(textNode.getLayoutY()); Bounds bounds = characterBoundingPath.getBoundsInLocal(); --- 518,528 ---- y = 0; width = 0; height = textNodeBounds.getMaxY(); } else { characterBoundingPath.getElements().clear(); ! characterBoundingPath.getElements().addAll(textNode.rangeShape(index, index + 1)); characterBoundingPath.setLayoutX(textNode.getLayoutX()); characterBoundingPath.setLayoutY(textNode.getLayoutY()); Bounds bounds = characterBoundingPath.getBoundsInLocal();
*** 543,558 **** y + textBounds.getMinY(), width, height); } /** {@inheritDoc} */ @Override protected PathElement[] getUnderlineShape(int start, int end) { ! return textNode.impl_getUnderlineShape(start, end); } /** {@inheritDoc} */ @Override protected PathElement[] getRangeShape(int start, int end) { ! return textNode.impl_getRangeShape(start, end); } /** {@inheritDoc} */ @Override protected void addHighlight(List<? extends Node> nodes, int start) { textGroup.getChildren().addAll(nodes); --- 539,554 ---- y + textBounds.getMinY(), width, height); } /** {@inheritDoc} */ @Override protected PathElement[] getUnderlineShape(int start, int end) { ! return textNode.underlineShape(start, end); } /** {@inheritDoc} */ @Override protected PathElement[] getRangeShape(int start, int end) { ! return textNode.rangeShape(start, end); } /** {@inheritDoc} */ @Override protected void addHighlight(List<? extends Node> nodes, int start) { textGroup.getChildren().addAll(nodes);
*** 595,611 **** // See RT-25465. caretBounds = new Path(caretPath.getElements().get(0), caretPath.getElements().get(1)).getLayoutBounds(); } double hitX = moveRight ? caretBounds.getMaxX() : caretBounds.getMinX(); double hitY = (caretBounds.getMinY() + caretBounds.getMaxY()) / 2; ! HitInfo hit = textNode.impl_hitTestChar(new Point2D(hitX, hitY)); ! Path charShape = new Path(textNode.impl_getRangeShape(hit.getCharIndex(), hit.getCharIndex() + 1)); if ((moveRight && charShape.getLayoutBounds().getMaxX() > caretBounds.getMaxX()) || (!moveRight && charShape.getLayoutBounds().getMinX() < caretBounds.getMinX())) { ! hit.setLeading(!hit.isLeading()); } ! positionCaret(hit, false); } /** {@inheritDoc} */ @Override protected void layoutChildren(final double x, final double y, final double w, final double h) { --- 591,608 ---- // See RT-25465. caretBounds = new Path(caretPath.getElements().get(0), caretPath.getElements().get(1)).getLayoutBounds(); } double hitX = moveRight ? caretBounds.getMaxX() : caretBounds.getMinX(); double hitY = (caretBounds.getMinY() + caretBounds.getMaxY()) / 2; ! HitInfo hit = textNode.hitTest(new Point2D(hitX, hitY)); ! boolean leading = hit.isLeading(); ! Path charShape = new Path(textNode.rangeShape(hit.getCharIndex(), hit.getCharIndex() + 1)); if ((moveRight && charShape.getLayoutBounds().getMaxX() > caretBounds.getMaxX()) || (!moveRight && charShape.getLayoutBounds().getMinX() < caretBounds.getMinX())) { ! leading = !leading; } ! positionCaret(hit.getInsertionIndex(), leading, false); } /** {@inheritDoc} */ @Override protected void layoutChildren(final double x, final double y, final double w, final double h) {
*** 714,728 **** return behavior; } private void updateTextNodeCaretPos(int pos) { if (pos == 0 || isForwardBias()) { ! textNode.setImpl_caretPosition(pos); } else { ! textNode.setImpl_caretPosition(pos - 1); } ! textNode.impl_caretBiasProperty().set(isForwardBias()); } private void createPromptNode() { if (promptNode != null || !usePromptText.get()) return; --- 711,725 ---- return behavior; } private void updateTextNodeCaretPos(int pos) { if (pos == 0 || isForwardBias()) { ! textNode.setCaretPosition(pos); } else { ! textNode.setCaretPosition(pos - 1); } ! textNode.caretBiasProperty().set(isForwardBias()); } private void createPromptNode() { if (promptNode != null || !usePromptText.get()) return;
*** 741,760 **** private void updateSelection() { TextField textField = getSkinnable(); IndexRange newValue = textField.getSelection(); if (newValue == null || newValue.getLength() == 0) { ! textNode.impl_selectionStartProperty().set(-1); ! textNode.impl_selectionEndProperty().set(-1); } else { ! textNode.impl_selectionStartProperty().set(newValue.getStart()); // This intermediate value is needed to force selection shape layout. ! textNode.impl_selectionEndProperty().set(newValue.getStart()); ! textNode.impl_selectionEndProperty().set(newValue.getEnd()); } ! PathElement[] elements = textNode.impl_selectionShapeProperty().get(); if (elements == null) { selectionHighlightPath.getElements().clear(); } else { selectionHighlightPath.getElements().setAll(elements); } --- 738,757 ---- private void updateSelection() { TextField textField = getSkinnable(); IndexRange newValue = textField.getSelection(); if (newValue == null || newValue.getLength() == 0) { ! textNode.selectionStartProperty().set(-1); ! textNode.selectionEndProperty().set(-1); } else { ! textNode.selectionStartProperty().set(newValue.getStart()); // This intermediate value is needed to force selection shape layout. ! textNode.selectionEndProperty().set(newValue.getStart()); ! textNode.selectionEndProperty().set(newValue.getEnd()); } ! PathElement[] elements = textNode.selectionShapeProperty().get(); if (elements == null) { selectionHighlightPath.getElements().clear(); } else { selectionHighlightPath.getElements().setAll(elements); }
< prev index next >