modules/controls/src/main/java/com/sun/javafx/scene/control/behavior/TextAreaBehavior.java
Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
@@ -25,135 +25,206 @@
package com.sun.javafx.scene.control.behavior;
import com.sun.javafx.PlatformUtil;
import com.sun.javafx.geom.transform.Affine3D;
-import com.sun.javafx.scene.control.skin.TextAreaSkin;
-import com.sun.javafx.scene.text.HitInfo;
+import com.sun.javafx.scene.control.Properties;
+import javafx.scene.control.skin.TextAreaSkin;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
-import javafx.scene.control.IndexRange;
import javafx.scene.control.TextArea;
+import com.sun.javafx.scene.control.skin.Utils;
import javafx.scene.input.ContextMenuEvent;
+import com.sun.javafx.scene.control.inputmap.InputMap;
+import com.sun.javafx.scene.control.inputmap.KeyBinding;
+import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.stage.Screen;
import javafx.stage.Window;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.function.Predicate;
+
+import static javafx.scene.control.skin.TextAreaSkin.TextPosInfo;
import static com.sun.javafx.PlatformUtil.isMac;
import static com.sun.javafx.PlatformUtil.isWindows;
+import static javafx.scene.control.skin.TextInputControlSkin.TextUnit;
+import static javafx.scene.control.skin.TextInputControlSkin.Direction;
import static javafx.scene.input.KeyCode.*;
-import static javafx.scene.input.KeyEvent.KEY_PRESSED;
/**
* Text area behavior.
*/
public class TextAreaBehavior extends TextInputControlBehavior<TextArea> {
- /**************************************************************************
- * Setup KeyBindings *
- *************************************************************************/
- protected static final List<KeyBinding> TEXT_AREA_BINDINGS = new ArrayList<KeyBinding>();
- static {
- TEXT_AREA_BINDINGS.add(new KeyBinding(HOME, KEY_PRESSED, "LineStart")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(END, KEY_PRESSED, "LineEnd")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "PreviousLine")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "PreviousLine")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "NextLine")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "NextLine")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_UP, KEY_PRESSED, "PreviousPage")); // new
- TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_DOWN, KEY_PRESSED, "NextPage")); // new
- TEXT_AREA_BINDINGS.add(new KeyBinding(ENTER, KEY_PRESSED, "InsertNewLine")); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(TAB, KEY_PRESSED, "TraverseOrInsertTab")); // changed
-
- TEXT_AREA_BINDINGS.add(new KeyBinding(HOME, KEY_PRESSED, "SelectLineStart").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(END, KEY_PRESSED, "SelectLineEnd").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectPreviousLine").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectPreviousLine").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectNextLine").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectNextLine").shift()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_UP, KEY_PRESSED, "SelectPreviousPage").shift()); // new
- TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_DOWN, KEY_PRESSED, "SelectNextPage").shift()); // new
- // Platform specific settings
- if (isMac()) {
- TEXT_AREA_BINDINGS.add(new KeyBinding(LEFT, KEY_PRESSED, "LineStart").shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_LEFT, KEY_PRESSED, "LineStart").shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(RIGHT, KEY_PRESSED, "LineEnd").shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_RIGHT, KEY_PRESSED, "LineEnd").shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "Home").shortcut());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "Home").shortcut());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "End").shortcut());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "End").shortcut());
-
- TEXT_AREA_BINDINGS.add(new KeyBinding(LEFT, KEY_PRESSED, "SelectLineStartExtend").shift().shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_LEFT, KEY_PRESSED, "SelectLineStartExtend").shift().shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(RIGHT, KEY_PRESSED, "SelectLineEndExtend").shift().shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_RIGHT, KEY_PRESSED, "SelectLineEndExtend").shift().shortcut()); // changed
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectHomeExtend").shortcut().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectHomeExtend").shortcut().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectEndExtend").shortcut().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectEndExtend").shortcut().shift());
-
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "ParagraphStart").alt());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "ParagraphStart").alt());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "ParagraphEnd").alt());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "ParagraphEnd").alt());
-
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectParagraphStart").alt().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectParagraphStart").alt().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectParagraphEnd").alt().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectParagraphEnd").alt().shift());
- } else {
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "ParagraphStart").ctrl());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "ParagraphStart").ctrl());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "ParagraphEnd").ctrl());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "ParagraphEnd").ctrl());
- TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectParagraphStart").ctrl().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectParagraphStart").ctrl().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectParagraphEnd").ctrl().shift());
- TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectParagraphEnd").ctrl().shift());
- }
- // Add the other standard key bindings in
- TEXT_AREA_BINDINGS.addAll(TextInputControlBindings.BINDINGS);
- // However, we want to consume other key press / release events too, for
- // things that would have been handled by the InputCharacter normally
- TEXT_AREA_BINDINGS.add(new KeyBinding(null, KEY_PRESSED, "Consume"));
- }
-
+// /**************************************************************************
+// * Setup KeyBindings *
+// *************************************************************************/
+// protected static final List<KeyBinding> TEXT_AREA_BINDINGS = new ArrayList<KeyBinding>();
+// static {
+// TEXT_AREA_BINDINGS.add(new KeyBinding(HOME, KEY_PRESSED, "LineStart")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(END, KEY_PRESSED, "LineEnd")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "PreviousLine")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "PreviousLine")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "NextLine")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "NextLine")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_UP, KEY_PRESSED, "PreviousPage")); // new
+// TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_DOWN, KEY_PRESSED, "NextPage")); // new
+// TEXT_AREA_BINDINGS.add(new KeyBinding(ENTER, KEY_PRESSED, "InsertNewLine")); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(TAB, KEY_PRESSED, "TraverseOrInsertTab")); // changed
+//
+// TEXT_AREA_BINDINGS.add(new KeyBinding(HOME, KEY_PRESSED, "SelectLineStart").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(END, KEY_PRESSED, "SelectLineEnd").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectPreviousLine").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectPreviousLine").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectNextLine").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectNextLine").shift()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_UP, KEY_PRESSED, "SelectPreviousPage").shift()); // new
+// TEXT_AREA_BINDINGS.add(new KeyBinding(PAGE_DOWN, KEY_PRESSED, "SelectNextPage").shift()); // new
+// // Platform specific settings
+// if (isMac()) {
+// TEXT_AREA_BINDINGS.add(new KeyBinding(LEFT, KEY_PRESSED, "LineStart").shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_LEFT, KEY_PRESSED, "LineStart").shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(RIGHT, KEY_PRESSED, "LineEnd").shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_RIGHT, KEY_PRESSED, "LineEnd").shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "Home").shortcut());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "Home").shortcut());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "End").shortcut());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "End").shortcut());
+//
+// TEXT_AREA_BINDINGS.add(new KeyBinding(LEFT, KEY_PRESSED, "SelectLineStartExtend").shift().shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_LEFT, KEY_PRESSED, "SelectLineStartExtend").shift().shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(RIGHT, KEY_PRESSED, "SelectLineEndExtend").shift().shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_RIGHT, KEY_PRESSED, "SelectLineEndExtend").shift().shortcut()); // changed
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectHomeExtend").shortcut().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectHomeExtend").shortcut().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectEndExtend").shortcut().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectEndExtend").shortcut().shift());
+//
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "ParagraphStart").alt());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "ParagraphStart").alt());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "ParagraphEnd").alt());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "ParagraphEnd").alt());
+//
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectParagraphStart").alt().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectParagraphStart").alt().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectParagraphEnd").alt().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectParagraphEnd").alt().shift());
+// } else {
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "ParagraphStart").ctrl());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "ParagraphStart").ctrl());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "ParagraphEnd").ctrl());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "ParagraphEnd").ctrl());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(UP, KEY_PRESSED, "SelectParagraphStart").ctrl().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_UP, KEY_PRESSED, "SelectParagraphStart").ctrl().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(DOWN, KEY_PRESSED, "SelectParagraphEnd").ctrl().shift());
+// TEXT_AREA_BINDINGS.add(new KeyBinding(KP_DOWN, KEY_PRESSED, "SelectParagraphEnd").ctrl().shift());
+// }
+// // Add the other standard key bindings in
+// TEXT_AREA_BINDINGS.addAll(TextInputControlBindings.BINDINGS);
+// // However, we want to consume other key press / release events too, for
+// // things that would have been handled by the InputCharacter normally
+// TEXT_AREA_BINDINGS.add(new KeyBinding(null, KEY_PRESSED, "Consume"));
+// }
+//
private TextAreaSkin skin;
private ContextMenu contextMenu;
private TwoLevelFocusBehavior tlFocus;
/**************************************************************************
* Constructors *
*************************************************************************/
- public TextAreaBehavior(final TextArea textArea) {
- super(textArea, TEXT_AREA_BINDINGS);
+ public TextAreaBehavior(final TextArea c) {
+ super(c);
contextMenu = new ContextMenu();
- if (IS_TOUCH_SUPPORTED) {
+ if (Properties.IS_TOUCH_SUPPORTED) {
contextMenu.getStyleClass().add("text-input-context-menu");
}
+ // some of the mappings are only valid when the control is editable, or
+ // only on certain platforms, so we create the following predicates that filters out the mapping when the
+ // control is not in the correct state / on the correct platform
+ final Predicate<KeyEvent> validWhenEditable = e -> !c.isEditable();
+ final Predicate<KeyEvent> validOnMac = e -> !PlatformUtil.isMac();
+ final Predicate<KeyEvent> validOnWindows = e -> !PlatformUtil.isWindows();
+ final Predicate<KeyEvent> validOnLinux = e -> !PlatformUtil.isLinux();
+
+ // Add these bindings as a child input map, so they take precedence
+ InputMap<TextArea> textAreaInputMap = new InputMap<>(c);
+ textAreaInputMap.getMappings().addAll(
+ keyMapping(HOME, e -> lineStart(false)),
+ keyMapping(END, e -> lineEnd(false)),
+ keyMapping(UP, e -> skin.moveCaret(TextUnit.LINE, Direction.UP, false)),
+ keyMapping(DOWN, e -> skin.moveCaret(TextUnit.LINE, Direction.DOWN, false)),
+ keyMapping(PAGE_UP, e -> skin.moveCaret(TextUnit.PAGE, Direction.UP, false)),
+ keyMapping(PAGE_DOWN, e -> skin.moveCaret(TextUnit.PAGE, Direction.DOWN, false)),
+
+ keyMapping(new KeyBinding(HOME).shift(), e -> lineStart(true)),
+ keyMapping(new KeyBinding(END).shift(), e -> lineEnd(true)),
+ keyMapping(new KeyBinding(UP).shift(), e -> skin.moveCaret(TextUnit.LINE, Direction.UP, true)),
+ keyMapping(new KeyBinding(DOWN).shift(), e -> skin.moveCaret(TextUnit.LINE, Direction.DOWN, true)),
+ keyMapping(new KeyBinding(PAGE_UP).shift(), e -> skin.moveCaret(TextUnit.PAGE, Direction.UP, true)),
+ keyMapping(new KeyBinding(PAGE_DOWN).shift(), e -> skin.moveCaret(TextUnit.PAGE, Direction.DOWN, true)),
+
+ // editing-only mappings
+ keyMapping(new KeyBinding(ENTER), e -> insertNewLine(), validWhenEditable),
+ keyMapping(new KeyBinding(TAB), e -> insertTab(), validWhenEditable)
+ );
+ addDefaultChildMap(getInputMap(), textAreaInputMap);
+
+ // mac os specific mappings
+ InputMap<TextArea> macOsInputMap = new InputMap<>(c);
+ macOsInputMap.setInterceptor(e -> !PlatformUtil.isMac());
+ macOsInputMap.getMappings().addAll(
+ // Mac OS specific mappings
+ keyMapping(new KeyBinding(LEFT).shortcut(), e -> lineStart(false)),
+ keyMapping(new KeyBinding(RIGHT).shortcut(), e -> lineEnd(false)),
+ keyMapping(new KeyBinding(UP).shortcut(), e -> c.home()),
+ keyMapping(new KeyBinding(DOWN).shortcut(), e -> c.end()),
+
+ keyMapping(new KeyBinding(LEFT).shortcut().shift(), e -> lineStart(true)),
+ keyMapping(new KeyBinding(RIGHT).shortcut().shift(), e -> lineEnd(true)),
+ keyMapping(new KeyBinding(UP).shortcut().shift(), e -> selectHomeExtend()),
+ keyMapping(new KeyBinding(DOWN).shortcut().shift(), e -> selectEndExtend()),
+
+ keyMapping(new KeyBinding(UP).alt(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.UP, false)),
+ keyMapping(new KeyBinding(DOWN).alt(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.DOWN, false)),
+ keyMapping(new KeyBinding(UP).alt().shift(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.UP, true)),
+ keyMapping(new KeyBinding(DOWN).alt().shift(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.DOWN, true))
+ );
+ addDefaultChildMap(textAreaInputMap, macOsInputMap);
+
+ // windows / linux specific mappings
+ InputMap<TextArea> nonMacOsInputMap = new InputMap<>(c);
+ nonMacOsInputMap.setInterceptor(e -> PlatformUtil.isMac());
+ nonMacOsInputMap.getMappings().addAll(
+ keyMapping(new KeyBinding(UP).ctrl(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.UP, false)),
+ keyMapping(new KeyBinding(DOWN).ctrl(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.DOWN, false)),
+ keyMapping(new KeyBinding(UP).ctrl().shift(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.UP, true)),
+ keyMapping(new KeyBinding(DOWN).ctrl().shift(), e -> skin.moveCaret(TextUnit.PARAGRAPH, Direction.DOWN, true))
+ );
+ addDefaultChildMap(textAreaInputMap, nonMacOsInputMap);
+
+ addKeyPadMappings(textAreaInputMap);
+
// Register for change events
- textArea.focusedProperty().addListener(new ChangeListener<Boolean>() {
+ c.focusedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
// NOTE: The code in this method is *almost* and exact copy of what is in TextFieldBehavior.
// The only real difference is that TextFieldBehavior selects all the text when the control
// receives focus (when not gained by mouse click), whereas TextArea doesn't, and also the
// TextArea doesn't lose selection on focus lost, whereas the TextField does.
- final TextArea textArea = getControl();
+ final TextArea textArea = getNode();
if (textArea.isFocused()) {
if (PlatformUtil.isIOS()) {
// Special handling of focus on iOS is required to allow to
// control native keyboard, because native keyboard is popped-up only when native
// text component gets focus. When we have JFX keyboard we can remove this code
@@ -184,12 +255,12 @@
}
}
});
// 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(textArea); // needs to be last.
+ if (Utils.isTwoLevelFocus()) {
+ tlFocus = new TwoLevelFocusBehavior(c); // needs to be last.
}
}
@Override public void dispose() {
if (tlFocus != null) tlFocus.dispose();
@@ -199,112 +270,53 @@
// An unholy back-reference!
public void setTextAreaSkin(TextAreaSkin skin) {
this.skin = skin;
}
- /**************************************************************************
- * Key handling implementation *
- *************************************************************************/
-
- @Override public void callAction(String name) {
- final TextArea textInputControl = getControl();
-
- boolean done = false;
-
- if (textInputControl.isEditable()) {
-// fnCaretAnim(false);
-// setCaretOpacity(1.0);
+ private void insertNewLine() {
setEditing(true);
- done = true;
- if ("InsertNewLine".equals(name)) insertNewLine();
- else if ("TraverseOrInsertTab".equals(name)) insertTab();
- else {
- done = false;
- }
+ getNode().replaceSelection("\n");
setEditing(false);
}
- if (!done) {
- done = true;
- if ("LineStart".equals(name)) lineStart(false, false);
- else if ("LineEnd".equals(name)) lineEnd(false, false);
- else if ("SelectLineStart".equals(name)) lineStart(true, false);
- else if ("SelectLineStartExtend".equals(name)) lineStart(true, true);
- else if ("SelectLineEnd".equals(name)) lineEnd(true, false);
- else if ("SelectLineEndExtend".equals(name)) lineEnd(true, true);
- else if ("PreviousLine".equals(name)) skin.previousLine(false);
- else if ("NextLine".equals(name)) skin.nextLine(false);
- else if ("SelectPreviousLine".equals(name)) skin.previousLine(true);
- else if ("SelectNextLine".equals(name)) skin.nextLine(true);
-
- else if ("ParagraphStart".equals(name)) skin.paragraphStart(true, false);
- else if ("ParagraphEnd".equals(name)) skin.paragraphEnd(true, isWindows(), false);
- else if ("SelectParagraphStart".equals(name)) skin.paragraphStart(true, true);
- else if ("SelectParagraphEnd".equals(name)) skin.paragraphEnd(true, isWindows(), true);
-
- else if ("PreviousPage".equals(name)) skin.previousPage(false);
- else if ("NextPage".equals(name)) skin.nextPage(false);
- else if ("SelectPreviousPage".equals(name)) skin.previousPage(true);
- else if ("SelectNextPage".equals(name)) skin.nextPage(true);
- else if ("TraverseOrInsertTab".equals(name)) {
- // RT-40312: Non-editabe mode means traverse instead of insert.
- name = "TraverseNext";
- done = false;
- } else {
- done = false;
- }
- }
-// fnCaretAnim(true);
-
- if (!done) {
- super.callAction(name);
- }
- }
-
- private void insertNewLine() {
- TextArea textArea = getControl();
- textArea.replaceSelection("\n");
- }
-
private void insertTab() {
- TextArea textArea = getControl();
- textArea.replaceSelection("\t");
+ setEditing(true);
+ getNode().replaceSelection("\t");
+ setEditing(false);
}
@Override protected void deleteChar(boolean previous) {
- skin.deleteChar(previous);
+ if (previous) {
+ getNode().deletePreviousChar();
+ } else {
+ getNode().deleteNextChar();
+ }
}
@Override protected void deleteFromLineStart() {
- TextArea textArea = getControl();
+ TextArea textArea = getNode();
int end = textArea.getCaretPosition();
if (end > 0) {
- lineStart(false, false);
+ lineStart(false);
int start = textArea.getCaretPosition();
if (end > start) {
replaceText(start, end, "");
}
}
}
- private void lineStart(boolean select, boolean extendSelection) {
- skin.lineStart(select, extendSelection);
+ private void lineStart(boolean select) {
+ skin.moveCaret(TextUnit.LINE, Direction.BEGINNING, select);
}
- private void lineEnd(boolean select, boolean extendSelection) {
- skin.lineEnd(select, extendSelection);
- }
-
- protected void scrollCharacterToVisible(int index) {
- // TODO this method should be removed when TextAreaSkin
- // TODO is refactored to no longer need it.
- skin.scrollCharacterToVisible(index);
+ private void lineEnd(boolean select) {
+ skin.moveCaret(TextUnit.LINE, Direction.END, select);
}
@Override protected void replaceText(int start, int end, String txt) {
- getControl().replaceText(start, end, txt);
+ getNode().replaceText(start, end, txt);
}
/**
* If the focus is gained via response to a mouse click, then we don't
* want to select all the text even if selectOnFocus is true.
@@ -312,12 +324,11 @@
private boolean focusGainedByMouseClick = false; // TODO!!
private boolean shiftDown = false;
private boolean deferClick = false;
@Override public void mousePressed(MouseEvent e) {
- TextArea textArea = getControl();
- super.mousePressed(e);
+ TextArea textArea = getNode();
// We never respond to events if disabled
if (!textArea.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, TODO which will then NOT honor the selectOnFocus variable
@@ -332,12 +343,12 @@
// 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.getButton() == MouseButton.PRIMARY && !(e.isMiddleButtonDown() || e.isSecondaryButtonDown())) {
- HitInfo hit = skin.getIndex(e.getX(), e.getY());
- int i = com.sun.javafx.scene.control.skin.Utils.getHitInsertionIndex(hit, textArea.textProperty().getValueSafe());
+ TextPosInfo hit = skin.getIndex(e.getX(), e.getY());
+ int i = Utils.getHitInsertionIndex(hit, textArea.textProperty().getValueSafe());
// int i = skin.getInsertionPoint(e.getX(), e.getY());
final int anchor = textArea.getAnchor();
final int caretPosition = textArea.getCaretPosition();
if (e.getClickCount() < 2 &&
(e.isSynthesized() ||
@@ -353,11 +364,11 @@
// TODO start a timer such that after some millis we
// switch into text dragging mode, change the cursor
// to indicate the text can be dragged, etc.
} else if (!(e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown() || e.isShortcutDown())) {
switch (e.getClickCount()) {
- case 1: skin.positionCaret(hit, false, false); break;
+ case 1: skin.positionCaret(hit, false); break;
case 2: mouseDoubleClick(hit); break;
case 3: mouseTripleClick(hit); break;
default: // no-op
}
} else if (e.isShiftDown() && !(e.isControlDown() || e.isAltDown() || e.isMetaDown() || e.isShortcutDown()) && e.getClickCount() == 1) {
@@ -370,11 +381,11 @@
// the dot to be the new position.
// everywhere else we just move the dot.
if (isMac()) {
textArea.extendSelection(i);
} else {
- skin.positionCaret(hit, true, false);
+ skin.positionCaret(hit, true);
}
}
// skin.setForwardBias(hit.isLeading());
// if (textInputControl.editable)
// displaySoftwareKeyboard(true);
@@ -384,128 +395,113 @@
}
}
}
@Override public void mouseDragged(MouseEvent e) {
- final TextArea textArea = getControl();
+ final TextArea textArea = getNode();
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textArea.isDisabled() && !e.isSynthesized()) {
if (e.getButton() == MouseButton.PRIMARY &&
!(e.isMiddleButtonDown() || e.isSecondaryButtonDown() ||
e.isControlDown() || e.isAltDown() || e.isShiftDown() || e.isMetaDown())) {
- skin.positionCaret(skin.getIndex(e.getX(), e.getY()), true, false);
+ skin.positionCaret(skin.getIndex(e.getX(), e.getY()), true);
}
}
deferClick = false;
}
@Override public void mouseReleased(final MouseEvent e) {
- final TextArea textArea = getControl();
- super.mouseReleased(e);
+ final TextArea textArea = getNode();
// we never respond to events if disabled, but we do notify any onXXX
// event listeners on the control
if (!textArea.isDisabled()) {
setCaretAnimating(false);
if (deferClick) {
deferClick = false;
- skin.positionCaret(skin.getIndex(e.getX(), e.getY()), shiftDown, false);
+ skin.positionCaret(skin.getIndex(e.getX(), e.getY()), shiftDown);
shiftDown = false;
}
setCaretAnimating(true);
}
}
@Override public void contextMenuRequested(ContextMenuEvent e) {
- final TextArea textArea = getControl();
+ final TextArea textArea = getNode();
if (contextMenu.isShowing()) {
contextMenu.hide();
} else if (textArea.getContextMenu() == null) {
double screenX = e.getScreenX();
double screenY = e.getScreenY();
double sceneX = e.getSceneX();
- if (IS_TOUCH_SUPPORTED) {
+ if (Properties.IS_TOUCH_SUPPORTED) {
Point2D menuPos;
if (textArea.getSelection().getLength() == 0) {
- skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false, false);
+ skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false);
menuPos = skin.getMenuPosition();
} else {
menuPos = skin.getMenuPosition();
if (menuPos != null && (menuPos.getX() <= 0 || menuPos.getY() <= 0)) {
- skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false, false);
+ skin.positionCaret(skin.getIndex(e.getX(), e.getY()), false);
menuPos = skin.getMenuPosition();
}
}
if (menuPos != null) {
- Point2D p = getControl().localToScene(menuPos);
- Scene scene = getControl().getScene();
+ 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();
}
}
- skin.populateContextMenu(contextMenu);
+ populateContextMenu(contextMenu);
double menuWidth = contextMenu.prefWidth(-1);
- double menuX = screenX - (IS_TOUCH_SUPPORTED ? (menuWidth / 2) : 0);
+ 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()) {
- getControl().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
- getControl().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
- contextMenu.show(getControl(), bounds.getMinX(), screenY);
+ 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);
- getControl().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
- getControl().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
- contextMenu.show(getControl(), screenX - leftOver, screenY);
+ getNode().getProperties().put("CONTEXT_MENU_SCREEN_X", screenX);
+ getNode().getProperties().put("CONTEXT_MENU_SCENE_X", sceneX);
+ contextMenu.show(getNode(), 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);
+ getNode().getProperties().put("CONTEXT_MENU_SCREEN_X", 0);
+ getNode().getProperties().put("CONTEXT_MENU_SCENE_X", 0);
+ contextMenu.show(getNode(), menuX, screenY);
}
}
e.consume();
}
@Override protected void setCaretAnimating(boolean play) {
skin.setCaretAnimating(play);
}
- protected void mouseDoubleClick(HitInfo hit) {
- final TextArea textArea = getControl();
+ protected void mouseDoubleClick(TextPosInfo hit) {
+ final TextArea textArea = getNode();
textArea.previousWord();
if (isWindows()) {
textArea.selectNextWord();
} else {
textArea.selectEndOfNextWord();
}
}
- protected void mouseTripleClick(HitInfo hit) {
+ protected void mouseTripleClick(TextPosInfo hit) {
// select the line
- skin.paragraphStart(false, false);
- skin.paragraphEnd(false, isWindows(), true);
+ skin.moveCaret(TextUnit.PARAGRAPH, Direction.BEGINNING, false);
+ skin.moveCaret(TextUnit.PARAGRAPH, Direction.END, true);
}
-
- // public function mouseWheelMove(e:MouseEvent):Void {
-// def textBox = bind skin.control as TextBox;
-// // we never respond to events if disabled, but we do notify any onXXX
-// // event listeners on the control
-// if (not textBox.disabled) {
-// var rot = Math.abs(e.wheelRotation);
-// while (rot > 0) {
-// rot--;
-// scrollText(e.wheelRotation > 0);
-// }
-// }
-// }
-
}