diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelection.java b/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelection.java
index d1b9b23a9..09c9ba5b5 100644
--- a/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelection.java
+++ b/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelection.java
@@ -44,6 +44,9 @@
* then just write the much simpler {@code BoundedSelection, ?, ?> selection}.
*
*
+ * @see Caret
+ * @see UnboundedSelection
+ *
* @param type for {@link StyledDocument}'s paragraph style; only necessary when using the "selectedDocument"
* getter or property
* @param type for {@link StyledDocument}'s segment type; only necessary when using the "selectedDocument"
diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelectionImpl.java b/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelectionImpl.java
index 876fb491a..6e27d2817 100644
--- a/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelectionImpl.java
+++ b/richtextfx/src/main/java/org/fxmisc/richtext/BoundedSelectionImpl.java
@@ -16,7 +16,7 @@
import java.util.Optional;
-public class BoundedSelectionImpl implements BoundedSelection {
+final class BoundedSelectionImpl implements BoundedSelection {
private final UnboundedSelection delegate;
@Override public ObservableValue rangeProperty() { return delegate.rangeProperty(); }
diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
index 41615d980..8749891e1 100644
--- a/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
+++ b/richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
@@ -315,52 +315,6 @@ private static int clamp(int min, int val, int max) {
@Override public Duration getMouseOverTextDelay() { return mouseOverTextDelay.get(); }
@Override public ObjectProperty mouseOverTextDelayProperty() { return mouseOverTextDelay; }
- private final BooleanProperty autoScrollOnDragDesired = new SimpleBooleanProperty(true);
- public final void setAutoScrollOnDragDesired(boolean val) { autoScrollOnDragDesired.set(val); }
- public final boolean isAutoScrollOnDragDesired() { return autoScrollOnDragDesired.get(); }
-
- private final Property> onOutsideSelectionMousePress = new SimpleObjectProperty<>(e -> {
- CharacterHit hit = hit(e.getX(), e.getY());
- moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
- });
- public final void setOnOutsideSelectionMousePress(Consumer consumer) { onOutsideSelectionMousePress.setValue(consumer); }
- public final Consumer getOnOutsideSelectionMousePress() { return onOutsideSelectionMousePress.getValue(); }
-
- private final Property> onInsideSelectionMousePressRelease = new SimpleObjectProperty<>(e -> {
- CharacterHit hit = hit(e.getX(), e.getY());
- moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
- });
- public final void setOnInsideSelectionMousePressRelease(Consumer consumer) { onInsideSelectionMousePressRelease.setValue(consumer); }
- public final Consumer getOnInsideSelectionMousePressRelease() { return onInsideSelectionMousePressRelease.getValue(); }
-
- private final Property> onNewSelectionDrag = new SimpleObjectProperty<>(p -> {
- CharacterHit hit = hit(p.getX(), p.getY());
- moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
- });
- public final void setOnNewSelectionDrag(Consumer consumer) { onNewSelectionDrag.setValue(consumer); }
- public final Consumer getOnNewSelectionDrag() { return onNewSelectionDrag.getValue(); }
-
- private final Property> onNewSelectionDragEnd = new SimpleObjectProperty<>(e -> {
- CharacterHit hit = hit(e.getX(), e.getY());
- moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
- });
- public final void setOnNewSelectionDragEnd(Consumer consumer) { onNewSelectionDragEnd.setValue(consumer); }
- public final Consumer getOnNewSelectionDragEnd() { return onNewSelectionDragEnd.getValue(); }
-
- private final Property> onSelectionDrag = new SimpleObjectProperty<>(p -> {
- CharacterHit hit = hit(p.getX(), p.getY());
- displaceCaret(hit.getInsertionIndex());
- });
- public final void setOnSelectionDrag(Consumer consumer) { onSelectionDrag.setValue(consumer); }
- public final Consumer getOnSelectionDrag() { return onSelectionDrag.getValue(); }
-
- private final Property> onSelectionDrop = new SimpleObjectProperty<>(e -> {
- CharacterHit hit = hit(e.getX(), e.getY());
- moveSelectedText(hit.getInsertionIndex());
- });
- @Override public final void setOnSelectionDrop(Consumer consumer) { onSelectionDrop.setValue(consumer); }
- @Override public final Consumer getOnSelectionDrop() { return onSelectionDrop.getValue(); }
-
private final ObjectProperty> paragraphGraphicFactory = new SimpleObjectProperty<>(null);
@Override
public void setParagraphGraphicFactory(IntFunction extends Node> factory) { paragraphGraphicFactory.set(factory); }
@@ -415,6 +369,60 @@ public Optional, Codec>> getStyleCodecs() {
@Override
public void setEstimatedScrollY(double value) { virtualFlow.estimatedScrollYProperty().setValue(value); }
+ /* ********************************************************************** *
+ * *
+ * Mouse Behavior Hooks *
+ * *
+ * Hooks for overriding some of the default mouse behavior *
+ * *
+ * ********************************************************************** */
+
+ private final Property> onOutsideSelectionMousePress = new SimpleObjectProperty<>(e -> {
+ CharacterHit hit = hit(e.getX(), e.getY());
+ moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
+ });
+ public final void setOnOutsideSelectionMousePress(Consumer consumer) { onOutsideSelectionMousePress.setValue(consumer); }
+ public final Consumer getOnOutsideSelectionMousePress() { return onOutsideSelectionMousePress.getValue(); }
+
+ private final Property> onInsideSelectionMousePressRelease = new SimpleObjectProperty<>(e -> {
+ CharacterHit hit = hit(e.getX(), e.getY());
+ moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
+ });
+ public final void setOnInsideSelectionMousePressRelease(Consumer consumer) { onInsideSelectionMousePressRelease.setValue(consumer); }
+ public final Consumer getOnInsideSelectionMousePressRelease() { return onInsideSelectionMousePressRelease.getValue(); }
+
+ private final Property> onNewSelectionDrag = new SimpleObjectProperty<>(p -> {
+ CharacterHit hit = hit(p.getX(), p.getY());
+ moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
+ });
+ public final void setOnNewSelectionDrag(Consumer consumer) { onNewSelectionDrag.setValue(consumer); }
+ public final Consumer getOnNewSelectionDrag() { return onNewSelectionDrag.getValue(); }
+
+ private final Property> onNewSelectionDragEnd = new SimpleObjectProperty<>(e -> {
+ CharacterHit hit = hit(e.getX(), e.getY());
+ moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
+ });
+ public final void setOnNewSelectionDragEnd(Consumer consumer) { onNewSelectionDragEnd.setValue(consumer); }
+ public final Consumer getOnNewSelectionDragEnd() { return onNewSelectionDragEnd.getValue(); }
+
+ private final Property> onSelectionDrag = new SimpleObjectProperty<>(p -> {
+ CharacterHit hit = hit(p.getX(), p.getY());
+ displaceCaret(hit.getInsertionIndex());
+ });
+ public final void setOnSelectionDrag(Consumer consumer) { onSelectionDrag.setValue(consumer); }
+ public final Consumer getOnSelectionDrag() { return onSelectionDrag.getValue(); }
+
+ private final Property> onSelectionDrop = new SimpleObjectProperty<>(e -> {
+ CharacterHit hit = hit(e.getX(), e.getY());
+ moveSelectedText(hit.getInsertionIndex());
+ });
+ @Override public final void setOnSelectionDrop(Consumer consumer) { onSelectionDrop.setValue(consumer); }
+ @Override public final Consumer getOnSelectionDrop() { return onSelectionDrop.getValue(); }
+
+ // not a hook, but still plays a part in the default mouse behavior
+ private final BooleanProperty autoScrollOnDragDesired = new SimpleBooleanProperty(true);
+ public final void setAutoScrollOnDragDesired(boolean val) { autoScrollOnDragDesired.set(val); }
+ public final boolean isAutoScrollOnDragDesired() { return autoScrollOnDragDesired.get(); }
/* ********************************************************************** *
* *
@@ -615,7 +623,7 @@ public GenericStyledArea(
this.applyParagraphStyle = applyParagraphStyle;
this.segmentOps = segmentOps;
- undoManager = UndoUtils.createUndoManager(this);
+ undoManager = UndoUtils.defaultUndoManager(this);
// allow tab traversal into area
setFocusTraversable(true);
@@ -647,13 +655,6 @@ public GenericStyledArea(
IntUnaryOperator cellLength = i -> virtualFlow.getCell(i).getNode().getLineCount();
navigator = new TwoLevelNavigator(cellCount, cellLength);
- // relayout the popup when any of its settings values change (besides the caret being dirty)
- EventStream> popupAlignmentDirty = invalidationsOf(popupAlignmentProperty());
- EventStream> popupAnchorAdjustmentDirty = invalidationsOf(popupAnchorAdjustmentProperty());
- EventStream> popupAnchorOffsetDirty = invalidationsOf(popupAnchorOffsetProperty());
- EventStream> popupDirty = merge(popupAlignmentDirty, popupAnchorAdjustmentDirty, popupAnchorOffsetDirty);
- subscribeTo(popupDirty, x -> layoutPopup());
-
viewportDirty = merge(
// no need to check for width & height invalidations as scroll values update when these do
@@ -677,17 +678,6 @@ public GenericStyledArea(
visibleParagraphs = LiveList.map(virtualFlow.visibleCells(), c -> c.getNode().getParagraph()).suspendable();
- // Adjust popup anchor by either a user-provided function,
- // or user-provided offset, or don't adjust at all.
- Val> userOffset = Val.map(
- popupAnchorOffsetProperty(),
- offset -> anchor -> anchor.add(offset));
- _popupAnchorAdjustment =
- Val.orElse(
- popupAnchorAdjustmentProperty(),
- userOffset)
- .orElseConst(UnaryOperator.identity());
-
final Suspendable omniSuspendable = Suspendable.combine(
beingUpdated, // must be first, to be the last one to release
@@ -703,6 +693,26 @@ public GenericStyledArea(
.subscribe(evt -> Event.fireEvent(this, evt));
new StyledTextAreaBehavior(this);
+
+ // Code below this point is deprecated Popup API. It will be removed in the future
+
+ // relayout the popup when any of its settings values change (besides the caret being dirty)
+ EventStream> popupAlignmentDirty = invalidationsOf(popupAlignmentProperty());
+ EventStream> popupAnchorAdjustmentDirty = invalidationsOf(popupAnchorAdjustmentProperty());
+ EventStream> popupAnchorOffsetDirty = invalidationsOf(popupAnchorOffsetProperty());
+ EventStream> popupDirty = merge(popupAlignmentDirty, popupAnchorAdjustmentDirty, popupAnchorOffsetDirty);
+ subscribeTo(popupDirty, x -> layoutPopup());
+
+ // Adjust popup anchor by either a user-provided function,
+ // or user-provided offset, or don't adjust at all.
+ Val> userOffset = Val.map(
+ popupAnchorOffsetProperty(),
+ offset -> anchor -> anchor.add(offset));
+ _popupAnchorAdjustment =
+ Val.orElse(
+ popupAnchorAdjustmentProperty(),
+ userOffset)
+ .orElseConst(UnaryOperator.identity());
}
/* ********************************************************************** *
diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/UnboundedSelectionImpl.java b/richtextfx/src/main/java/org/fxmisc/richtext/UnboundedSelectionImpl.java
index 12293ac67..b34bc4066 100644
--- a/richtextfx/src/main/java/org/fxmisc/richtext/UnboundedSelectionImpl.java
+++ b/richtextfx/src/main/java/org/fxmisc/richtext/UnboundedSelectionImpl.java
@@ -25,7 +25,7 @@
import static org.reactfx.EventStreams.invalidationsOf;
import static org.reactfx.EventStreams.merge;
-public final class UnboundedSelectionImpl implements UnboundedSelection {
+final class UnboundedSelectionImpl implements UnboundedSelection {
private final SuspendableVal range;
@Override public final IndexRange getRange() { return range.getValue(); }
diff --git a/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java b/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java
index 9c6fe170f..39088ca1f 100644
--- a/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java
+++ b/richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java
@@ -9,35 +9,85 @@
import java.util.function.Consumer;
+/**
+ * A class filled with factory methods to help easily construct an {@link UndoManager} for a {@link GenericStyledArea}.
+ */
public final class UndoUtils {
private UndoUtils() {
throw new IllegalStateException("UndoUtils cannot be instantiated");
}
- public static UndoManager createUndoManager(GenericStyledArea area) {
+ /**
+ * Constructs an UndoManager with an unlimited history:
+ * if {@link GenericStyledArea#isPreserveStyle() the area's preserveStyle flag is true}, the returned UndoManager
+ * can undo/redo {@link RichTextChange}s; otherwise, it can undo/redo {@link PlainTextChange}s.
+ */
+ public static UndoManager defaultUndoManager(GenericStyledArea area) {
return area.isPreserveStyle()
? richTextUndoManager(area)
: plainTextUndoManager(area);
}
- public static UndoManager richTextUndoManager(GenericStyledArea area) {
+ /* ********************************************************************** *
+ * *
+ * UndoManager Factory Methods *
+ * *
+ * Code that constructs different kinds of UndoManagers for an area *
+ * *
+ * ********************************************************************** */
+
+ /**
+ * Returns an UndoManager with an unlimited history that can undo/redo {@link RichTextChange}s.
+ */
+ public static UndoManager> richTextUndoManager(GenericStyledArea area) {
return richTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory());
}
- public static UndoManager richTextUndoManager(GenericStyledArea area,
+ /**
+ * Returns an UndoManager that can undo/redo {@link RichTextChange}s.
+ */
+ public static UndoManager> richTextUndoManager(GenericStyledArea area,
UndoManagerFactory factory) {
- Consumer> apply = change -> area.replace(change.getPosition(), change.getPosition() + change.getRemoved().length(), change.getInserted());
- return factory.create(area.richChanges(), RichTextChange::invert, apply, TextChange::mergeWith, TextChange::isIdentity);
+ return factory.create(area.richChanges(), TextChange::invert, applyRichTextChange(area), TextChange::mergeWith, TextChange::isIdentity);
};
- public static UndoManager plainTextUndoManager(GenericStyledArea area) {
+ /**
+ * Returns an UndoManager with an unlimited history that can undo/redo {@link PlainTextChange}s.
+ */
+ public static UndoManager plainTextUndoManager(GenericStyledArea area) {
return plainTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory());
}
- public static UndoManager plainTextUndoManager(GenericStyledArea area,
+ /**
+ * Returns an UndoManager that can undo/redo {@link PlainTextChange}s.
+ */
+ public static UndoManager plainTextUndoManager(GenericStyledArea area,
UndoManagerFactory factory) {
- Consumer apply = change -> area.replaceText(change.getPosition(), change.getPosition() + change.getRemoved().length(), change.getInserted());
- return factory.create(area.plainTextChanges(), PlainTextChange::invert, apply, TextChange::mergeWith, TextChange::isIdentity);
+ return factory.create(area.plainTextChanges(), TextChange::invert, applyPlainTextChange(area), TextChange::mergeWith, TextChange::isIdentity);
+ }
+
+ /* ********************************************************************** *
+ * *
+ * Change Appliers *
+ * *
+ * Code that handles how a change should be applied to the area *
+ * *
+ * ********************************************************************** */
+
+ /**
+ * Applies a {@link PlainTextChange} to the given area when the {@link UndoManager}'s change stream emits an event
+ * by {@code area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
+ */
+ public static Consumer applyPlainTextChange(GenericStyledArea area) {
+ return change -> area.replaceText(change.getPosition(), change.getRemovalEnd(), change.getInserted());
+ }
+
+ /**
+ * Applies a {@link PlainTextChange} to the given area when the {@link UndoManager}'s change stream emits an event
+ * by {@code area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted()}.
+ */
+ public static Consumer> applyRichTextChange(GenericStyledArea area) {
+ return change -> area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted());
}
}