Skip to content

Commit

Permalink
Merge pull request #463 from JordanMartinez/removeSTAModel
Browse files Browse the repository at this point in the history
Remove middleman: ESD is the model now, not STAModel
  • Loading branch information
JordanMartinez authored Mar 23, 2017
2 parents 7bf8f4c + ec94238 commit 7c253dd
Show file tree
Hide file tree
Showing 8 changed files with 395 additions and 811 deletions.
345 changes: 261 additions & 84 deletions richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;

import org.fxmisc.richtext.model.StyledTextAreaModel;
import org.fxmisc.richtext.model.NavigationActions.SelectionPolicy;
import org.fxmisc.richtext.model.TwoDimensional.Position;
import org.fxmisc.wellbehaved.event.EventPattern;
Expand Down Expand Up @@ -64,13 +63,13 @@ class StyledTextAreaBehavior {
anyOf(keyPressed(PASTE), keyPressed(V, SHORTCUT_DOWN), keyPressed(INSERT, SHIFT_DOWN)),
(b, e) -> b.view.paste()),
// tab & newline
consume(keyPressed(ENTER), (b, e) -> b.model.replaceSelection("\n")),
consume(keyPressed(TAB), (b, e) -> b.model.replaceSelection("\t")),
consume(keyPressed(ENTER), (b, e) -> b.view.replaceSelection("\n")),
consume(keyPressed(TAB), (b, e) -> b.view.replaceSelection("\t")),
// undo/redo
consume(keyPressed(Z, SHORTCUT_DOWN), (b, e) -> b.model.undo()),
consume(keyPressed(Z, SHORTCUT_DOWN), (b, e) -> b.view.undo()),
consume(
anyOf(keyPressed(Y, SHORTCUT_DOWN), keyPressed(Z, SHORTCUT_DOWN, SHIFT_DOWN)),
(b, e) -> b.model.redo())
(b, e) -> b.view.redo())
);
InputMapTemplate<StyledTextAreaBehavior, KeyEvent> edits = when(b -> b.view.isEditable(), editsBase);

Expand Down Expand Up @@ -111,8 +110,8 @@ class StyledTextAreaBehavior {
keyPressed(LEFT, SHORTCUT_DOWN),
keyPressed(KP_LEFT, SHORTCUT_DOWN)
), (b, e) -> b.skipToPrevWord(SelectionPolicy.CLEAR)),
consume(keyPressed(HOME, SHORTCUT_DOWN), (b, e) -> b.model.start(SelectionPolicy.CLEAR)),
consume(keyPressed(END, SHORTCUT_DOWN), (b, e) -> b.model.end(SelectionPolicy.CLEAR)),
consume(keyPressed(HOME, SHORTCUT_DOWN), (b, e) -> b.view.start(SelectionPolicy.CLEAR)),
consume(keyPressed(END, SHORTCUT_DOWN), (b, e) -> b.view.end(SelectionPolicy.CLEAR)),
// selection
consume(
anyOf(
Expand All @@ -126,8 +125,8 @@ class StyledTextAreaBehavior {
), StyledTextAreaBehavior::selectLeft),
consume(keyPressed(HOME, SHIFT_DOWN), (b, e) -> b.view.lineStart(selPolicy)),
consume(keyPressed(END, SHIFT_DOWN), (b, e) -> b.view.lineEnd(selPolicy)),
consume(keyPressed(HOME, SHIFT_DOWN, SHORTCUT_DOWN), (b, e) -> b.model.start(selPolicy)),
consume(keyPressed(END, SHIFT_DOWN, SHORTCUT_DOWN), (b, e) -> b.model.end(selPolicy)),
consume(keyPressed(HOME, SHIFT_DOWN, SHORTCUT_DOWN), (b, e) -> b.view.start(selPolicy)),
consume(keyPressed(END, SHIFT_DOWN, SHORTCUT_DOWN), (b, e) -> b.view.end(selPolicy)),
consume(
anyOf(
keyPressed(RIGHT, SHIFT_DOWN, SHORTCUT_DOWN),
Expand All @@ -138,7 +137,7 @@ class StyledTextAreaBehavior {
keyPressed(LEFT, SHIFT_DOWN, SHORTCUT_DOWN),
keyPressed(KP_LEFT, SHIFT_DOWN, SHORTCUT_DOWN)
), (b, e) -> b.skipToPrevWord(selPolicy)),
consume(keyPressed(A, SHORTCUT_DOWN), (b, e) -> b.model.selectAll())
consume(keyPressed(A, SHORTCUT_DOWN), (b, e) -> b.view.selectAll())
);

InputMapTemplate<StyledTextAreaBehavior, KeyEvent> copyAction = consume(
Expand Down Expand Up @@ -214,8 +213,6 @@ private enum DragState {

private final GenericStyledArea<?, ?, ?> view;

private final StyledTextAreaModel<?, ?, ?> model;

/**
* Indicates whether selection is being dragged by the user.
*/
Expand All @@ -229,7 +226,6 @@ private enum DragState {

StyledTextAreaBehavior(GenericStyledArea<?, ?, ?> area) {
this.view = area;
this.model = area.getModel();

InputMapTemplate.installFallback(EVENT_TEMPLATE, this, b -> b.view);

Expand Down Expand Up @@ -266,7 +262,7 @@ private void keyTyped(KeyEvent event) {
return;
}

model.replaceSelection(text);
view.replaceSelection(text);
}

private static boolean isLegal(String text) {
Expand All @@ -280,71 +276,71 @@ private static boolean isLegal(String text) {
}

private void deleteBackward(KeyEvent ignore) {
IndexRange selection = model.getSelection();
IndexRange selection = view.getSelection();
if(selection.getLength() == 0) {
model.deletePreviousChar();
view.deletePreviousChar();
} else {
model.replaceSelection("");
view.replaceSelection("");
}
}

private void deleteForward(KeyEvent ignore) {
IndexRange selection = model.getSelection();
IndexRange selection = view.getSelection();
if(selection.getLength() == 0) {
model.deleteNextChar();
view.deleteNextChar();
} else {
model.replaceSelection("");
view.replaceSelection("");
}
}

private void left(KeyEvent ignore) {
IndexRange sel = model.getSelection();
IndexRange sel = view.getSelection();
if(sel.getLength() == 0) {
model.previousChar(SelectionPolicy.CLEAR);
view.previousChar(SelectionPolicy.CLEAR);
} else {
model.moveTo(sel.getStart(), SelectionPolicy.CLEAR);
view.moveTo(sel.getStart(), SelectionPolicy.CLEAR);
}
}

private void right(KeyEvent ignore) {
IndexRange sel = model.getSelection();
IndexRange sel = view.getSelection();
if(sel.getLength() == 0) {
model.nextChar(SelectionPolicy.CLEAR);
view.nextChar(SelectionPolicy.CLEAR);
} else {
model.moveTo(sel.getEnd(), SelectionPolicy.CLEAR);
view.moveTo(sel.getEnd(), SelectionPolicy.CLEAR);
}
}

private void selectLeft(KeyEvent ignore) {
model.previousChar(SelectionPolicy.ADJUST);
view.previousChar(SelectionPolicy.ADJUST);
}

private void selectRight(KeyEvent ignore) {
model.nextChar(SelectionPolicy.ADJUST);
view.nextChar(SelectionPolicy.ADJUST);
}

private void selectWord() {
model.wordBreaksBackwards(1, SelectionPolicy.CLEAR);
model.wordBreaksForwards(1, SelectionPolicy.ADJUST);
view.wordBreaksBackwards(1, SelectionPolicy.CLEAR);
view.wordBreaksForwards(1, SelectionPolicy.ADJUST);
}

private void deletePrevWord(KeyEvent ignore) {
int end = model.getCaretPosition();
int end = view.getCaretPosition();

if (end > 0) {
model.wordBreaksBackwards(2, SelectionPolicy.CLEAR);
int start = model.getCaretPosition();
model.replaceText(start, end, "");
view.wordBreaksBackwards(2, SelectionPolicy.CLEAR);
int start = view.getCaretPosition();
view.replaceText(start, end, "");
}
}

private void deleteNextWord(KeyEvent ignore) {
int start = model.getCaretPosition();
int start = view.getCaretPosition();

if (start < model.getLength()) {
model.wordBreaksForwards(2, SelectionPolicy.CLEAR);
int end = model.getCaretPosition();
model.replaceText(start, end, "");
if (start < view.getLength()) {
view.wordBreaksForwards(2, SelectionPolicy.CLEAR);
int end = view.getCaretPosition();
view.replaceText(start, end, "");
}
}

Expand All @@ -356,7 +352,7 @@ private void downLines(SelectionPolicy selectionPolicy, int nLines) {
CharacterHit hit = view.hit(view.getTargetCaretOffset(), targetLine);

// update model
model.moveTo(hit.getInsertionIndex(), selectionPolicy);
view.moveTo(hit.getInsertionIndex(), selectionPolicy);
}
}

Expand All @@ -369,23 +365,23 @@ private void nextLine(SelectionPolicy selectionPolicy) {
}

private void skipToPrevWord(SelectionPolicy selectionPolicy) {
int caretPos = model.getCaretPosition();
int caretPos = view.getCaretPosition();

// if (0 == caretPos), do nothing as can't move to the left anyway
if (1 <= caretPos ) {
boolean prevCharIsWhiteSpace = isWhitespace(model.getText(caretPos - 1, caretPos).charAt(0));
model.wordBreaksBackwards(prevCharIsWhiteSpace ? 2 : 1, selectionPolicy);
boolean prevCharIsWhiteSpace = isWhitespace(view.getText(caretPos - 1, caretPos).charAt(0));
view.wordBreaksBackwards(prevCharIsWhiteSpace ? 2 : 1, selectionPolicy);
}
}

private void skipToNextWord(SelectionPolicy selectionPolicy) {
int caretPos = model.getCaretPosition();
int length = model.getLength();
int caretPos = view.getCaretPosition();
int length = view.getLength();

// if (caretPos == length), do nothing as can't move to the right anyway
if (caretPos <= length - 1) {
boolean nextCharIsWhiteSpace = isWhitespace(model.getText(caretPos, caretPos + 1).charAt(0));
model.wordBreaksForwards(nextCharIsWhiteSpace ? 2 : 1, selectionPolicy);
boolean nextCharIsWhiteSpace = isWhitespace(view.getText(caretPos, caretPos + 1).charAt(0));
view.wordBreaksForwards(nextCharIsWhiteSpace ? 2 : 1, selectionPolicy);
}
}

Expand Down Expand Up @@ -420,14 +416,14 @@ private void mousePressed(MouseEvent e) {
if(e.isShiftDown()) {
// On Mac always extend selection,
// switching anchor and caret if necessary.
model.moveTo(
view.moveTo(
hit.getInsertionIndex(),
isMac ? SelectionPolicy.EXTEND : SelectionPolicy.ADJUST);
} else {
switch (e.getClickCount()) {
case 1: firstLeftPress(hit); break;
case 2: selectWord(); break;
case 3: model.selectParagraph(); break;
case 3: view.selectParagraph(); break;
default: // do nothing
}
}
Expand All @@ -438,7 +434,7 @@ private void mousePressed(MouseEvent e) {

private void firstLeftPress(CharacterHit hit) {
view.clearTargetCaretOffset();
IndexRange selection = model.getSelection();
IndexRange selection = view.getSelection();
if(view.isEditable() &&
selection.getLength() != 0 &&
hit.getCharacterIndex().isPresent() &&
Expand All @@ -448,7 +444,7 @@ private void firstLeftPress(CharacterHit hit) {
dragSelection = DragState.POTENTIAL_DRAG;
} else {
dragSelection = DragState.NO_DRAG;
model.moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
view.moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
}
}

Expand Down Expand Up @@ -486,9 +482,9 @@ private void dragTo(Point2D p) {

if(dragSelection == DragState.DRAG ||
dragSelection == DragState.POTENTIAL_DRAG) { // MOUSE_DRAGGED may arrive even before DRAG_DETECTED
model.positionCaret(hit.getInsertionIndex());
view.positionCaret(hit.getInsertionIndex());
} else {
model.moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
view.moveTo(hit.getInsertionIndex(), SelectionPolicy.ADJUST);
}
}

Expand All @@ -505,7 +501,7 @@ private void mouseReleased(MouseEvent e) {
case POTENTIAL_DRAG:
// drag didn't happen, position caret
CharacterHit hit = view.hit(e.getX(), e.getY());
model.moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
view.moveTo(hit.getInsertionIndex(), SelectionPolicy.CLEAR);
break;
case DRAG:
// only handle drags if mouse was released inside of view
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

import org.reactfx.EventStream;
import org.reactfx.SuspendableNo;
import org.reactfx.collection.LiveList;
import org.reactfx.value.Val;

/**
* Content model for {@link org.fxmisc.richtext.GenericStyledArea}. Implements edit operations
* on styled text, but not worrying about additional aspects such as
* caret or selection, which are handled by {@link StyledTextAreaModel}.
* on styled text, but not worrying about view aspects.
*/
public interface EditableStyledDocument<PS, SEG, S> extends StyledDocument<PS, SEG, S> {

Expand All @@ -30,7 +30,7 @@ public interface EditableStyledDocument<PS, SEG, S> extends StyledDocument<PS, S
Val<Integer> lengthProperty();

@Override
ObservableList<Paragraph<PS, SEG, S>> getParagraphs();
LiveList<Paragraph<PS, SEG, S>> getParagraphs();

/**
* Read-only snapshot of the current state of this document.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@
import java.util.Collections;
import java.util.List;

import javafx.collections.ObservableList;
import org.reactfx.EventSource;
import org.reactfx.EventStream;
import org.reactfx.Subscription;
import org.reactfx.Suspendable;
import org.reactfx.SuspendableEventStream;
import org.reactfx.SuspendableNo;
import org.reactfx.collection.LiveList;
import org.reactfx.collection.LiveListBase;
import org.reactfx.collection.MaterializedListModification;
import org.reactfx.collection.QuasiListModification;
import org.reactfx.collection.SuspendableList;
import org.reactfx.collection.UnmodifiableByDefaultLiveList;
import org.reactfx.util.BiIndex;
import org.reactfx.util.Lists;
import org.reactfx.value.SuspendableVal;
import org.reactfx.value.Val;

/**
Expand Down Expand Up @@ -51,24 +56,26 @@ protected Subscription observeInputs() {

private ReadOnlyStyledDocument<PS, SEG, S> doc;

private final EventSource<RichTextChange<PS, SEG, S>> richChanges = new EventSource<>();
private final EventSource<RichTextChange<PS, SEG, S>> internalRichChanges = new EventSource<>();
private final SuspendableEventStream<RichTextChange<PS, SEG, S>> richChanges = internalRichChanges.pausable();
@Override public EventStream<RichTextChange<PS, SEG, S>> richChanges() { return richChanges; }

private final Val<String> text = Val.create(() -> doc.getText(), richChanges);
private final Val<String> internalText = Val.create(() -> doc.getText(), internalRichChanges);
private final SuspendableVal<String> text = internalText.suspendable();
@Override public String getText() { return text.getValue(); }
@Override public Val<String> textProperty() { return text; }


private final Val<Integer> length = Val.create(() -> doc.length(), richChanges);
private final Val<Integer> internalLength = Val.create(() -> doc.length(), internalRichChanges);
private final SuspendableVal<Integer> length = internalLength.suspendable();
@Override public int getLength() { return length.getValue(); }
@Override public Val<Integer> lengthProperty() { return length; }
@Override public int length() { return length.getValue(); }

private final EventSource<MaterializedListModification<Paragraph<PS, SEG, S>>> parChanges =
new EventSource<>();

private final LiveList<Paragraph<PS, SEG, S>> paragraphs = new ParagraphList();

private final SuspendableList<Paragraph<PS, SEG, S>> paragraphs = new ParagraphList().suspendable();
@Override
public LiveList<Paragraph<PS, SEG, S>> getParagraphs() {
return paragraphs;
Expand All @@ -85,6 +92,17 @@ public ReadOnlyStyledDocument<PS, SEG, S> snapshot() {

GenericEditableStyledDocumentBase(Paragraph<PS, SEG, S> initialParagraph/*, SegmentOps<SEG, S> segmentOps*/) {
this.doc = new ReadOnlyStyledDocument<>(Collections.singletonList(initialParagraph));

final Suspendable omniSuspendable = Suspendable.combine(
text,
length,

// add streams after properties, to be released before them
richChanges,

// paragraphs to be released first
paragraphs);
omniSuspendable.suspendWhen(beingUpdated);
}

/**
Expand Down Expand Up @@ -202,7 +220,7 @@ private void update(
MaterializedListModification<Paragraph<PS, SEG, S>> parChange) {
this.doc = newValue;
beingUpdated.suspendWhile(() -> {
richChanges.push(change);
internalRichChanges.push(change);
parChanges.push(parChange);
});
}
Expand Down
Loading

0 comments on commit 7c253dd

Please sign in to comment.