Skip to content

Commit

Permalink
Merge pull request #529 from JordanMartinez/refactorCode
Browse files Browse the repository at this point in the history
Reposition code and refactor / add javadoc to #526 & #528
  • Loading branch information
JordanMartinez authored Jun 22, 2017
2 parents ce3bf9b + ce27fd3 commit c73aacb
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
* then just write the much simpler {@code BoundedSelection<?, ?, ?> selection}</b>.
* </p>
*
* @see Caret
* @see UnboundedSelection
*
* @param <PS> type for {@link StyledDocument}'s paragraph style; only necessary when using the "selectedDocument"
* getter or property
* @param <SEG> type for {@link StyledDocument}'s segment type; only necessary when using the "selectedDocument"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import java.util.Optional;

public class BoundedSelectionImpl<PS, SEG, S> implements BoundedSelection<PS, SEG, S> {
final class BoundedSelectionImpl<PS, SEG, S> implements BoundedSelection<PS, SEG, S> {

private final UnboundedSelection<PS, SEG, S> delegate;
@Override public ObservableValue<IndexRange> rangeProperty() { return delegate.rangeProperty(); }
Expand Down
140 changes: 75 additions & 65 deletions richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -315,52 +315,6 @@ private static int clamp(int min, int val, int max) {
@Override public Duration getMouseOverTextDelay() { return mouseOverTextDelay.get(); }
@Override public ObjectProperty<Duration> 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<Consumer<MouseEvent>> onOutsideSelectionMousePress = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
});
public final void setOnOutsideSelectionMousePress(Consumer<MouseEvent> consumer) { onOutsideSelectionMousePress.setValue(consumer); }
public final Consumer<MouseEvent> getOnOutsideSelectionMousePress() { return onOutsideSelectionMousePress.getValue(); }

private final Property<Consumer<MouseEvent>> onInsideSelectionMousePressRelease = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
});
public final void setOnInsideSelectionMousePressRelease(Consumer<MouseEvent> consumer) { onInsideSelectionMousePressRelease.setValue(consumer); }
public final Consumer<MouseEvent> getOnInsideSelectionMousePressRelease() { return onInsideSelectionMousePressRelease.getValue(); }

private final Property<Consumer<Point2D>> onNewSelectionDrag = new SimpleObjectProperty<>(p -> {
CharacterHit hit = hit(p.getX(), p.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
});
public final void setOnNewSelectionDrag(Consumer<Point2D> consumer) { onNewSelectionDrag.setValue(consumer); }
public final Consumer<Point2D> getOnNewSelectionDrag() { return onNewSelectionDrag.getValue(); }

private final Property<Consumer<MouseEvent>> onNewSelectionDragEnd = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
});
public final void setOnNewSelectionDragEnd(Consumer<MouseEvent> consumer) { onNewSelectionDragEnd.setValue(consumer); }
public final Consumer<MouseEvent> getOnNewSelectionDragEnd() { return onNewSelectionDragEnd.getValue(); }

private final Property<Consumer<Point2D>> onSelectionDrag = new SimpleObjectProperty<>(p -> {
CharacterHit hit = hit(p.getX(), p.getY());
displaceCaret(hit.getInsertionIndex());
});
public final void setOnSelectionDrag(Consumer<Point2D> consumer) { onSelectionDrag.setValue(consumer); }
public final Consumer<Point2D> getOnSelectionDrag() { return onSelectionDrag.getValue(); }

private final Property<Consumer<MouseEvent>> onSelectionDrop = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveSelectedText(hit.getInsertionIndex());
});
@Override public final void setOnSelectionDrop(Consumer<MouseEvent> consumer) { onSelectionDrop.setValue(consumer); }
@Override public final Consumer<MouseEvent> getOnSelectionDrop() { return onSelectionDrop.getValue(); }

private final ObjectProperty<IntFunction<? extends Node>> paragraphGraphicFactory = new SimpleObjectProperty<>(null);
@Override
public void setParagraphGraphicFactory(IntFunction<? extends Node> factory) { paragraphGraphicFactory.set(factory); }
Expand Down Expand Up @@ -415,6 +369,60 @@ public Optional<Tuple2<Codec<PS>, Codec<SEG>>> 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<Consumer<MouseEvent>> onOutsideSelectionMousePress = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
});
public final void setOnOutsideSelectionMousePress(Consumer<MouseEvent> consumer) { onOutsideSelectionMousePress.setValue(consumer); }
public final Consumer<MouseEvent> getOnOutsideSelectionMousePress() { return onOutsideSelectionMousePress.getValue(); }

private final Property<Consumer<MouseEvent>> onInsideSelectionMousePressRelease = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
});
public final void setOnInsideSelectionMousePressRelease(Consumer<MouseEvent> consumer) { onInsideSelectionMousePressRelease.setValue(consumer); }
public final Consumer<MouseEvent> getOnInsideSelectionMousePressRelease() { return onInsideSelectionMousePressRelease.getValue(); }

private final Property<Consumer<Point2D>> onNewSelectionDrag = new SimpleObjectProperty<>(p -> {
CharacterHit hit = hit(p.getX(), p.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
});
public final void setOnNewSelectionDrag(Consumer<Point2D> consumer) { onNewSelectionDrag.setValue(consumer); }
public final Consumer<Point2D> getOnNewSelectionDrag() { return onNewSelectionDrag.getValue(); }

private final Property<Consumer<MouseEvent>> onNewSelectionDragEnd = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
});
public final void setOnNewSelectionDragEnd(Consumer<MouseEvent> consumer) { onNewSelectionDragEnd.setValue(consumer); }
public final Consumer<MouseEvent> getOnNewSelectionDragEnd() { return onNewSelectionDragEnd.getValue(); }

private final Property<Consumer<Point2D>> onSelectionDrag = new SimpleObjectProperty<>(p -> {
CharacterHit hit = hit(p.getX(), p.getY());
displaceCaret(hit.getInsertionIndex());
});
public final void setOnSelectionDrag(Consumer<Point2D> consumer) { onSelectionDrag.setValue(consumer); }
public final Consumer<Point2D> getOnSelectionDrag() { return onSelectionDrag.getValue(); }

private final Property<Consumer<MouseEvent>> onSelectionDrop = new SimpleObjectProperty<>(e -> {
CharacterHit hit = hit(e.getX(), e.getY());
moveSelectedText(hit.getInsertionIndex());
});
@Override public final void setOnSelectionDrop(Consumer<MouseEvent> consumer) { onSelectionDrop.setValue(consumer); }
@Override public final Consumer<MouseEvent> 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(); }

/* ********************************************************************** *
* *
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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

Expand All @@ -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<UnaryOperator<Point2D>> 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

Expand All @@ -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<UnaryOperator<Point2D>> userOffset = Val.map(
popupAnchorOffsetProperty(),
offset -> anchor -> anchor.add(offset));
_popupAnchorAdjustment =
Val.orElse(
popupAnchorAdjustmentProperty(),
userOffset)
.orElseConst(UnaryOperator.identity());
}

/* ********************************************************************** *
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import static org.reactfx.EventStreams.invalidationsOf;
import static org.reactfx.EventStreams.merge;

public final class UnboundedSelectionImpl<PS, SEG, S> implements UnboundedSelection<PS, SEG, S> {
final class UnboundedSelectionImpl<PS, SEG, S> implements UnboundedSelection<PS, SEG, S> {

private final SuspendableVal<IndexRange> range;
@Override public final IndexRange getRange() { return range.getValue(); }
Expand Down
68 changes: 59 additions & 9 deletions richtextfx/src/main/java/org/fxmisc/richtext/util/UndoUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 <PS, SEG, S> UndoManager createUndoManager(GenericStyledArea<PS, SEG, S> 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 <PS, SEG, S> UndoManager defaultUndoManager(GenericStyledArea<PS, SEG, S> area) {
return area.isPreserveStyle()
? richTextUndoManager(area)
: plainTextUndoManager(area);
}

public static <PS, SEG, S> UndoManager richTextUndoManager(GenericStyledArea<PS, SEG, S> 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 <PS, SEG, S> UndoManager<RichTextChange<PS, SEG, S>> richTextUndoManager(GenericStyledArea<PS, SEG, S> area) {
return richTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory());
}

public static <PS, SEG, S> UndoManager richTextUndoManager(GenericStyledArea<PS, SEG, S> area,
/**
* Returns an UndoManager that can undo/redo {@link RichTextChange}s.
*/
public static <PS, SEG, S> UndoManager<RichTextChange<PS, SEG, S>> richTextUndoManager(GenericStyledArea<PS, SEG, S> area,
UndoManagerFactory factory) {
Consumer<RichTextChange<PS, SEG, S>> 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 <PS, SEG, S> UndoManager plainTextUndoManager(GenericStyledArea<PS, SEG, S> area) {
/**
* Returns an UndoManager with an unlimited history that can undo/redo {@link PlainTextChange}s.
*/
public static <PS, SEG, S> UndoManager<PlainTextChange> plainTextUndoManager(GenericStyledArea<PS, SEG, S> area) {
return plainTextUndoManager(area, UndoManagerFactory.unlimitedHistoryFactory());
}

public static <PS, SEG, S> UndoManager plainTextUndoManager(GenericStyledArea<PS, SEG, S> area,
/**
* Returns an UndoManager that can undo/redo {@link PlainTextChange}s.
*/
public static <PS, SEG, S> UndoManager<PlainTextChange> plainTextUndoManager(GenericStyledArea<PS, SEG, S> area,
UndoManagerFactory factory) {
Consumer<PlainTextChange> 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 <PS, SEG, S> Consumer<PlainTextChange> applyPlainTextChange(GenericStyledArea<PS, SEG, S> 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 <PS, SEG, S> Consumer<RichTextChange<PS, SEG, S>> applyRichTextChange(GenericStyledArea<PS, SEG, S> area) {
return change -> area.replace(change.getPosition(), change.getRemovalEnd(), change.getInserted());
}
}

0 comments on commit c73aacb

Please sign in to comment.