Skip to content

Commit

Permalink
Add AutoSave property and merge adjacent pieces with same decoration (#…
Browse files Browse the repository at this point in the history
…140)

Co-authored-by: jose.pereda <jose.pereda@gluonhq.com>
  • Loading branch information
jperedadnr and jperedadnr authored Apr 1, 2022
1 parent df7837a commit 4f2f45c
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 18 deletions.
4 changes: 4 additions & 0 deletions src/main/java/com/gluonhq/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
Expand Down Expand Up @@ -212,10 +213,13 @@ public Double fromString(String s) {
statusBar.getChildren().setAll(textLengthLabel);

Menu fileMenu = new Menu("File");
CheckMenuItem autoSaveMenuItem = new CheckMenuItem("Auto Save");
editor.autoSaveProperty().bind(autoSaveMenuItem.selectedProperty());
fileMenu.getItems().addAll(
actionMenuItem("New Text", LineAwesomeSolid.FILE, editor.getActionFactory().newDocument()),
actionMenuItem("Open Text", LineAwesomeSolid.FOLDER_OPEN, editor.getActionFactory().open(document)),
new SeparatorMenuItem(),
autoSaveMenuItem,
actionMenuItem("Save Text", LineAwesomeSolid.SAVE, editor.getActionFactory().save()));
Menu editMenu = new Menu("Edit");
editMenu.getItems().addAll(
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/gluonhq/richtext/RichTextArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ public final void setDocument(Document value) {
documentProperty.set(value);
}

// autoSaveProperty
private final BooleanProperty autoSaveProperty = new SimpleBooleanProperty(this, "autoSave");
public final BooleanProperty autoSaveProperty() {
return autoSaveProperty;
}
public final boolean isAutoSave() {
return autoSaveProperty.get();
}
public final void setAutoSave(boolean value) {
autoSaveProperty.set(value);
}

// modifiedProperty
final ReadOnlyBooleanWrapper modifiedProperty = new ReadOnlyBooleanWrapper(this, "modified");
public final ReadOnlyBooleanProperty modifiedProperty() {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/gluonhq/richtext/RichTextAreaSkin.java
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ public void dispose() {
viewModel.caretPositionProperty().removeListener(caretChangeListener);
viewModel.removeChangeListener(textChangeListener);
viewModel.documentProperty().removeListener(documentChangeListener);
viewModel.autoSaveProperty().unbind();
lastValidCaretPosition = -1;
getSkinnable().editableProperty().removeListener(this::editableChangeListener);
getSkinnable().textLengthProperty.unbind();
Expand Down Expand Up @@ -327,6 +328,7 @@ private void setup(Document document) {
viewModel.addChangeListener(textChangeListener);
viewModel.setDocument(document);
viewModel.documentProperty().addListener(documentChangeListener);
viewModel.autoSaveProperty().bind(getSkinnable().autoSaveProperty());
getSkinnable().textLengthProperty.bind(viewModel.textLengthProperty());
getSkinnable().modifiedProperty.bind(viewModel.savedProperty().not());
getSkinnable().setOnContextMenuRequested(contextMenuEventEventHandler);
Expand Down
50 changes: 39 additions & 11 deletions src/main/java/com/gluonhq/richtext/model/PieceTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -88,9 +89,23 @@ public String getText(final int start, final int end) {

@Override
public List<DecorationModel> getDecorationModelList() {
return pieces.stream()
.map(p -> new DecorationModel(p.start, p.length, p.getDecoration(), p.getParagraphDecoration()))
.collect(Collectors.toList());
List<DecorationModel> mergedList = new ArrayList<>();
if (!pieces.isEmpty()) {
AtomicInteger start = new AtomicInteger();
DecorationModel dm = null;
for (Piece piece : pieces) {
if (mergedList.isEmpty()) {
dm = new DecorationModel(start.addAndGet(piece.start), piece.length, piece.getDecoration(), piece.getParagraphDecoration());
} else if (piece.getDecoration().equals(dm.getDecoration()) && piece.getParagraphDecoration().equals(dm.getParagraphDecoration())) {
mergedList.remove(mergedList.size() - 1);
dm = new DecorationModel(dm.getStart(), dm.getLength() + piece.length, dm.getDecoration(), dm.getParagraphDecoration());
} else {
dm = new DecorationModel(start.addAndGet(dm.getLength()), piece.length, piece.getDecoration(), piece.getParagraphDecoration());
}
mergedList.add(dm);
}
}
return mergedList;
}

@Override
Expand All @@ -114,11 +129,11 @@ public void resetCharacterIterator() {
}

// internal append
Piece appendTextInternal(String text, Decoration decoration) {
Piece appendTextInternal(String text, Decoration decoration, ParagraphDecoration paragraphDecoration) {
int pos = additionBuffer.length();
additionBuffer += text;
textLengthProperty.set(getTextLength() + text.length());
return new Piece(this, Piece.BufferType.ADDITION, pos, text.length(), decoration);
return new Piece(this, Piece.BufferType.ADDITION, pos, text.length(), decoration, paragraphDecoration);
}

/**
Expand Down Expand Up @@ -189,7 +204,7 @@ public ParagraphDecoration getParagraphDecorationAtCaret(int caretPosition) {
}
textPosition += piece.length;
}
return null;
return previousPieceParagraphDecoration(index);
}

@Override
Expand Down Expand Up @@ -282,6 +297,11 @@ Decoration previousPieceDecoration(int index) {
TextDecoration.builder().presets().build() : pieces.get(index > 0 ? index - 1 : 0).getDecoration();
}

ParagraphDecoration previousPieceParagraphDecoration(int index) {
return pieces.isEmpty() ?
ParagraphDecoration.builder().presets().build() : pieces.get(index > 0 ? index - 1 : 0).getParagraphDecoration();
}

@Override
public String toString() {
String p = pieces.stream().map(piece -> " - " + piece.toString()).collect(Collectors.joining("\n", "\n", ""));
Expand Down Expand Up @@ -464,8 +484,11 @@ protected void doUndo(PieceTable pt) {
protected void doRedo(PieceTable pt) {
if (!text.isEmpty()) {
int pos = pt.getTextLength();
newPiece = pt.appendTextInternal(text, pt.decorationAtCaret != null ?
pt.decorationAtCaret : pt.previousPieceDecoration(pt.pieces.size()));
newPiece = pt.appendTextInternal(text,
pt.decorationAtCaret != null ?
pt.decorationAtCaret : pt.previousPieceDecoration(pt.pieces.size()),
pt.getParagraphDecorationAtCaret(pos) != null ?
pt.getParagraphDecorationAtCaret(pos) : pt.previousPieceParagraphDecoration(pt.pieces.size()));
pt.pieces.add(newPiece);
pt.fire(new TextBuffer.InsertEvent(text, pos));
execSuccess = true;
Expand Down Expand Up @@ -521,9 +544,11 @@ protected void doRedo(PieceTable pt) {
if (PieceTable.inRange(insertPosition, textPosition, piece.length)) {
int pieceOffset = insertPosition - textPosition;
final Decoration decoration = pieceOffset > 0 ? (TextDecoration) piece.getDecoration() : pt.previousPieceDecoration(pieceIndex);
final ParagraphDecoration paragraphDecoration = pt.getParagraphDecorationAtCaret(insertPosition) != null ?
pt.getParagraphDecorationAtCaret(insertPosition) : pt.previousPieceParagraphDecoration(pieceIndex);
newPieces = PieceTable.normalize(List.of(
piece.pieceBefore(pieceOffset),
pt.appendTextInternal(text, decoration),
pt.appendTextInternal(text, decoration, paragraphDecoration),
piece.pieceFrom(pieceOffset)
));
oldPiece = piece;
Expand Down Expand Up @@ -680,9 +705,12 @@ protected void doRedo(PieceTable pt) {
throw new IllegalArgumentException("Position " + insertPosition + " is outside of text bounds [0, " + pt.getTextLength() + "]");
}

final ParagraphDecoration paragraphDecoration = pt.getParagraphDecorationAtCaret(insertPosition) != null ?
pt.getParagraphDecorationAtCaret(insertPosition) : pt.previousPieceParagraphDecoration(insertPosition);

if (insertPosition == pt.getTextLength()) {
int pos = pt.getTextLength();
newPiece = pt.appendTextInternal(ZERO_WIDTH_TEXT, decoration);
newPiece = pt.appendTextInternal(ZERO_WIDTH_TEXT, decoration, paragraphDecoration);
pt.pieces.add(newPiece);
pt.fire(new TextBuffer.InsertEvent(ZERO_WIDTH_TEXT, pos));
execSuccess = true;
Expand All @@ -692,7 +720,7 @@ protected void doRedo(PieceTable pt) {
int pieceOffset = insertPosition - textPosition;
newPieces = PieceTable.normalize(List.of(
piece.pieceBefore(pieceOffset),
pt.appendTextInternal(ZERO_WIDTH_TEXT, decoration),
pt.appendTextInternal(ZERO_WIDTH_TEXT, decoration, paragraphDecoration),
piece.pieceFrom(pieceOffset)
));
oldPiece = piece;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -147,7 +146,11 @@ public final int getTextLength() {
private final ReadOnlyIntegerWrapper undoStackSizeProperty = new ReadOnlyIntegerWrapper(this, "undoStackSize") {
@Override
protected void invalidated() {
savedProperty.set(get() == undoStackSizeWhenSaved);
if (isAutoSave()) {
save();
} else {
savedProperty.set(get() == undoStackSizeWhenSaved);
}
}
};
public final ReadOnlyIntegerProperty undoStackSizeProperty() {
Expand Down Expand Up @@ -234,6 +237,18 @@ public final void setDocument(Document value) {
documentProperty.set(value);
}

// autoSaveProperty
private final BooleanProperty autoSaveProperty = new SimpleBooleanProperty(this, "autoSave");
public final BooleanProperty autoSaveProperty() {
return autoSaveProperty;
}
public final boolean isAutoSave() {
return autoSaveProperty.get();
}
public final void setAutoSave(boolean value) {
autoSaveProperty.set(value);
}

// savedProperty
final ReadOnlyBooleanWrapper savedProperty = new ReadOnlyBooleanWrapper(this, "saved", true);
public final ReadOnlyBooleanProperty savedProperty() {
Expand Down Expand Up @@ -635,10 +650,8 @@ void open(Document document) {

void save() {
Document currentDocument = getCurrentDocument();
Platform.runLater(() -> {
undoStackSizeWhenSaved = getUndoStackSize();
savedProperty.set(true);
setDocument(currentDocument);
});
undoStackSizeWhenSaved = getUndoStackSize();
savedProperty.set(true);
setDocument(currentDocument);
}
}

0 comments on commit 4f2f45c

Please sign in to comment.