modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TextFieldBehavior.java
Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
*** 23,32 ****
--- 23,33 ----
* questions.
*/
package com.sun.javafx.scene.control.behavior;
+ import com.sun.javafx.scene.control.Properties;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.WeakChangeListener;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
*** 34,52 ****
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TextField;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Screen;
import javafx.stage.Window;
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.geom.transform.Affine3D;
! import com.sun.javafx.scene.control.skin.TextFieldSkin;
! import com.sun.javafx.scene.text.HitInfo;
import static com.sun.javafx.PlatformUtil.isMac;
import static com.sun.javafx.PlatformUtil.isWindows;
/**
* Text field behavior.
--- 35,55 ----
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TextField;
+ import javafx.scene.control.skin.TextFieldSkin;
+ import com.sun.javafx.scene.control.skin.Utils;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.Screen;
import javafx.stage.Window;
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.geom.transform.Affine3D;
!
! import static javafx.scene.control.skin.TextFieldSkin.TextPosInfo;
import static com.sun.javafx.PlatformUtil.isMac;
import static com.sun.javafx.PlatformUtil.isWindows;
/**
* Text field behavior.
*** 57,70 ****
private TwoLevelFocusBehavior tlFocus;
private ChangeListener<Scene> sceneListener;
private ChangeListener<Node> focusOwnerListener;
public TextFieldBehavior(final TextField textField) {
! super(textField, TEXT_INPUT_BINDINGS);
contextMenu = new ContextMenu();
! if (IS_TOUCH_SUPPORTED) {
contextMenu.getStyleClass().add("text-input-context-menu");
}
handleFocusChange();
--- 60,73 ----
private TwoLevelFocusBehavior tlFocus;
private ChangeListener<Scene> sceneListener;
private ChangeListener<Node> focusOwnerListener;
public TextFieldBehavior(final TextField textField) {
! super(textField);
contextMenu = new ContextMenu();
! if (Properties.IS_TOUCH_SUPPORTED) {
contextMenu.getStyleClass().add("text-input-context-menu");
}
handleFocusChange();
*** 101,122 ****
if (textField.getScene() != null) {
textField.getScene().focusOwnerProperty().addListener(weakFocusOwnerListener);
}
// Only add this if we're on an embedded platform that supports 5-button navigation
! if (com.sun.javafx.scene.control.skin.Utils.isTwoLevelFocus()) {
tlFocus = new TwoLevelFocusBehavior(textField); // needs to be last.
}
}
@Override public void dispose() {
if (tlFocus != null) tlFocus.dispose();
super.dispose();
}
private void handleFocusChange() {
! TextField textField = getControl();
if (textField.isFocused()) {
if (PlatformUtil.isIOS()) {
// special handling of focus on iOS is required to allow to
// control native keyboard, because nat. keyboard is poped-up only when native
--- 104,125 ----
if (textField.getScene() != null) {
textField.getScene().focusOwnerProperty().addListener(weakFocusOwnerListener);
}
// Only add this if we're on an embedded platform that supports 5-button navigation
! if (Utils.isTwoLevelFocus()) {
tlFocus = new TwoLevelFocusBehavior(textField); // needs to be last.
}
}
@Override public void dispose() {
if (tlFocus != null) tlFocus.dispose();
super.dispose();
}
private void handleFocusChange() {
! TextField textField = getNode();
if (textField.isFocused()) {
if (PlatformUtil.isIOS()) {
// special handling of focus on iOS is required to allow to
// control native keyboard, because nat. keyboard is poped-up only when native
*** 170,180 ****
public void setTextFieldSkin(TextFieldSkin skin) {
this.skin = skin;
}
@Override protected void fire(KeyEvent event) {
! TextField textField = getControl();
EventHandler<ActionEvent> onAction = textField.getOnAction();
ActionEvent actionEvent = new ActionEvent(textField, null);
textField.fireEvent(actionEvent);
textField.commitValue();
--- 173,183 ----
public void setTextFieldSkin(TextFieldSkin skin) {
this.skin = skin;
}
@Override protected void fire(KeyEvent event) {
! TextField textField = getNode();
EventHandler<ActionEvent> onAction = textField.getOnAction();
ActionEvent actionEvent = new ActionEvent(textField, null);
textField.fireEvent(actionEvent);
textField.commitValue();
*** 184,194 ****
}
}
@Override
protected void cancelEdit(KeyEvent event) {
! TextField textField = getControl();
if (textField.getTextFormatter() != null) {
textField.cancelEdit();
} else {
forwardToParent(event);
}
--- 187,197 ----
}
}
@Override
protected void cancelEdit(KeyEvent event) {
! TextField textField = getNode();
if (textField.getTextFormatter() != null) {
textField.cancelEdit();
} else {
forwardToParent(event);
}
*** 201,211 ****
@Override protected void replaceText(int start, int end, String txt) {
skin.replaceText(start, end, txt);
}
@Override protected void deleteFromLineStart() {
! TextField textField = getControl();
int end = textField.getCaretPosition();
if (end > 0) {
replaceText(0, end, "");
}
--- 204,214 ----
@Override protected void replaceText(int start, int end, String txt) {
skin.replaceText(start, end, txt);
}
@Override protected void deleteFromLineStart() {
! TextField textField = getNode();
int end = textField.getCaretPosition();
if (end > 0) {
replaceText(0, end, "");
}
*** 233,244 ****
private boolean focusGainedByMouseClick = false;
private boolean shiftDown = false;
private boolean deferClick = false;
@Override public void mousePressed(MouseEvent e) {
! TextField textField = getControl();
! super.mousePressed(e);
// We never respond to events if disabled
if (!textField.isDisabled()) {
// If the text field doesn't have focus, then we'll attempt to set
// the focus and we'll indicate that we gained focus by a mouse
// click, which will then NOT honor the selectOnFocus variable
--- 236,246 ----
private boolean focusGainedByMouseClick = false;
private boolean shiftDown = false;
private boolean deferClick = false;
@Override public void mousePressed(MouseEvent e) {
! TextField textField = getNode();
// We never respond to events if disabled
if (!textField.isDisabled()) {
// If the text field doesn't have focus, then we'll attempt to set
// the focus and we'll indicate that we gained focus by a mouse
// click, which will then NOT honor the selectOnFocus variable
*** 253,269 ****
// only if there is no selection should we see the caret
// setCaretOpacity(if (textInputControl.dot == textInputControl.mark) then 1.0 else 0.0);
// if the primary button was pressed
if (e.isPrimaryButtonDown() && !(e.isMiddleButtonDown() || e.isSecondaryButtonDown())) {
! HitInfo hit = skin.getIndex(e.getX(), e.getY());
String text = textField.textProperty().getValueSafe();
! int i = com.sun.javafx.scene.control.skin.Utils.getHitInsertionIndex(hit, text);
final int anchor = textField.getAnchor();
final int caretPosition = textField.getCaretPosition();
if (e.getClickCount() < 2 &&
! (IS_TOUCH_SUPPORTED ||
(anchor != caretPosition &&
((i > anchor && i < caretPosition) || (i < anchor && i > caretPosition))))) {
// if there is a selection, then we will NOT handle the
// press now, but will defer until the release. If you
// select some text and then press down, we change the
--- 255,271 ----
// only if there is no selection should we see the caret
// setCaretOpacity(if (textInputControl.dot == textInputControl.mark) then 1.0 else 0.0);
// if the primary button was pressed
if (e.isPrimaryButtonDown() && !(e.isMiddleButtonDown() || e.isSecondaryButtonDown())) {
! TextPosInfo hit = skin.getIndex(e.getX(), e.getY());
String text = textField.textProperty().getValueSafe();
! int i = Utils.getHitInsertionIndex(hit, text);
final int anchor = textField.getAnchor();
final int caretPosition = textField.getCaretPosition();
if (e.getClickCount() < 2 &&
! (Properties.IS_TOUCH_SUPPORTED ||
(anchor != caretPosition &&
((i > anchor && i < caretPosition) || (i < anchor && i > caretPosition))))) {
// if there is a selection, then we will NOT handle the
// press now, but will defer until the release. If you
// select some text and then press down, we change the
*** 305,315 ****
contextMenu.hide();
}
}
@Override public void mouseDragged(MouseEvent e) {
! final TextField textField = getControl();
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textField.isDisabled() && !deferClick) {
if (e.isPrimaryButtonDown() && !(e.isMiddleButtonDown() || e.isSecondaryButtonDown())) {
if (!(e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown())) {
--- 307,317 ----
contextMenu.hide();
}
}
@Override public void mouseDragged(MouseEvent e) {
! final TextField textField = getNode();
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textField.isDisabled() && !deferClick) {
if (e.isPrimaryButtonDown() && !(e.isMiddleButtonDown() || e.isSecondaryButtonDown())) {
if (!(e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown())) {
*** 318,329 ****
}
}
}
@Override public void mouseReleased(MouseEvent e) {
! final TextField textField = getControl();
! super.mouseReleased(e);
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textField.isDisabled()) {
setCaretAnimating(false);
if (deferClick) {
--- 320,330 ----
}
}
}
@Override public void mouseReleased(MouseEvent e) {
! final TextField textField = getNode();
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textField.isDisabled()) {
setCaretAnimating(false);
if (deferClick) {
*** 334,353 ****
setCaretAnimating(true);
}
}
@Override public void contextMenuRequested(ContextMenuEvent e) {
! final TextField textField = getControl();
if (contextMenu.isShowing()) {
contextMenu.hide();
} else if (textField.getContextMenu() == null) {
double screenX = e.getScreenX();
double screenY = e.getScreenY();
double sceneX = e.getSceneX();
! if (IS_TOUCH_SUPPORTED) {
Point2D menuPos;
if (textField.getSelection().getLength() == 0) {
skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false);
menuPos = skin.getMenuPosition();
} else {
--- 335,354 ----
setCaretAnimating(true);
}
}
@Override public void contextMenuRequested(ContextMenuEvent e) {
! final TextField textField = getNode();
if (contextMenu.isShowing()) {
contextMenu.hide();
} else if (textField.getContextMenu() == null) {
double screenX = e.getScreenX();
double screenY = e.getScreenY();
double sceneX = e.getSceneX();
! if (Properties.IS_TOUCH_SUPPORTED) {
Point2D menuPos;
if (textField.getSelection().getLength() == 0) {
skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false);
menuPos = skin.getMenuPosition();
} else {
*** 357,442 ****
menuPos = skin.getMenuPosition();
}
}
if (menuPos != null) {
! Point2D p = getControl().localToScene(menuPos);
! Scene scene = getControl().getScene();
Window window = scene.getWindow();
Point2D location = new Point2D(window.getX() + scene.getX() + p.getX(),
window.getY() + scene.getY() + p.getY());
screenX = location.getX();
sceneX = p.getX();
screenY = location.getY();
}
}
! skin.populateContextMenu(contextMenu);
double menuWidth = contextMenu.prefWidth(-1);
! double menuX = screenX - (IS_TOUCH_SUPPORTED ? (menuWidth / 2) : 0);
Screen currentScreen = com.sun.javafx.util.Utils.getScreenForPoint(screenX, 0);
Rectangle2D bounds = currentScreen.getBounds();
if (menuX < bounds.getMinX()) {
! getControl().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
! getControl().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
! contextMenu.show(getControl(), bounds.getMinX(), screenY);
} else if (screenX + menuWidth > bounds.getMaxX()) {
double leftOver = menuWidth - ( bounds.getMaxX() - screenX);
! getControl().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
! getControl().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
! contextMenu.show(getControl(), screenX - leftOver, screenY);
} else {
! getControl().getProperties().put("CONTEXT_MENU_SCREEN_X", 0);
! getControl().getProperties().put("CONTEXT_MENU_SCENE_X", 0);
! contextMenu.show(getControl(), menuX, screenY);
}
}
e.consume();
}
! // var hadFocus = false;
! // var focused = bind (skin.control as TextInputControl).focused on replace old {
! // if (focused) {
! // hadFocus = true;
! // focusChanged(true);
! // } else {
! // if (hadFocus) {
! // focusChanged(false);
! // }
! // hadFocus = false;
! // }
! // }
! //
! // protected function focusChanged(f:Boolean):Void {
! // def textInputControl = skin.control as TextInputControl;
! // if (f and textInputControl.selectOnFocus and not focusGainedByMouseClick) {
! // textInputControl.selectAll();
! // } else if (not f) {
! // textInputControl.commit();
! // focusGainedByMouseClick = false;
! // displaySoftwareKeyboard(false);
! // }
! // }
! //
! protected void mouseSingleClick(HitInfo hit) {
skin.positionCaret(hit, false);
}
! protected void mouseDoubleClick(HitInfo hit) {
! final TextField textField = getControl();
textField.previousWord();
if (isWindows()) {
textField.selectNextWord();
} else {
textField.selectEndOfNextWord();
}
}
! protected void mouseTripleClick(HitInfo hit) {
! getControl().selectAll();
}
// Enumeration of all types of text input that can be simulated on
// touch device, such as iPad. Type is passed to native code and
// native text component is shown. It's used as workaround for iOS
--- 358,419 ----
menuPos = skin.getMenuPosition();
}
}
if (menuPos != null) {
! Point2D p = getNode().localToScene(menuPos);
! Scene scene = getNode().getScene();
Window window = scene.getWindow();
Point2D location = new Point2D(window.getX() + scene.getX() + p.getX(),
window.getY() + scene.getY() + p.getY());
screenX = location.getX();
sceneX = p.getX();
screenY = location.getY();
}
}
! populateContextMenu(contextMenu);
double menuWidth = contextMenu.prefWidth(-1);
! double menuX = screenX - (Properties.IS_TOUCH_SUPPORTED ? (menuWidth / 2) : 0);
Screen currentScreen = com.sun.javafx.util.Utils.getScreenForPoint(screenX, 0);
Rectangle2D bounds = currentScreen.getBounds();
if (menuX < bounds.getMinX()) {
! getNode().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
! getNode().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
! contextMenu.show(getNode(), bounds.getMinX(), screenY);
} else if (screenX + menuWidth > bounds.getMaxX()) {
double leftOver = menuWidth - ( bounds.getMaxX() - screenX);
! getNode().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
! getNode().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
! contextMenu.show(getNode(), screenX - leftOver, screenY);
} else {
! getNode().getProperties().put("CONTEXT_MENU_SCREEN_X", 0);
! getNode().getProperties().put("CONTEXT_MENU_SCENE_X", 0);
! contextMenu.show(getNode(), menuX, screenY);
}
}
e.consume();
}
! protected void mouseSingleClick(TextPosInfo hit) {
skin.positionCaret(hit, false);
}
! protected void mouseDoubleClick(TextPosInfo hit) {
! final TextField textField = getNode();
textField.previousWord();
if (isWindows()) {
textField.selectNextWord();
} else {
textField.selectEndOfNextWord();
}
}
! protected void mouseTripleClick(TextPosInfo hit) {
! getNode().selectAll();
}
// Enumeration of all types of text input that can be simulated on
// touch device, such as iPad. Type is passed to native code and
// native text component is shown. It's used as workaround for iOS