Skip to content

Commit

Permalink
Make Document and Decoration serializables (#312)
Browse files Browse the repository at this point in the history
  • Loading branch information
jperedadnr authored May 6, 2024
1 parent 6a0bef0 commit 768cb64
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 46 deletions.
23 changes: 18 additions & 5 deletions rta/src/main/java/com/gluonhq/richtextarea/RichListCell.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -56,6 +56,8 @@
import javafx.scene.text.Text;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand All @@ -70,6 +72,8 @@ class RichListCell extends ListCell<Paragraph> {

private static final Font MIN_LF_FONT = Font.font(10);

private final static Map<String, Color> COLOR_MAP = new HashMap<>();

private final RichTextAreaSkin richTextAreaSkin;
private final ParagraphTile paragraphTile;

Expand Down Expand Up @@ -194,10 +198,11 @@ protected void updateItem(Paragraph item, boolean empty) {
} else {
final Node node = buildNode(unit, (TextDecoration) decoration);
fragments.add(node);
Color background = ((TextDecoration) decoration).getBackground();
if (background != Color.TRANSPARENT) {
String background = ((TextDecoration) decoration).getBackground();
Color backgroundColor = COLOR_MAP.computeIfAbsent(background, s -> parseColorOrDefault(background, Color.TRANSPARENT));
if (!Color.TRANSPARENT.equals(backgroundColor)) {
backgroundIndexRanges.add(new IndexRangeColor(
length.get(), length.get() + unit.length(), background));
length.get(), length.get() + unit.length(), backgroundColor));
}
}
length.addAndGet(unit.length());
Expand Down Expand Up @@ -249,7 +254,8 @@ private Text buildText(String content, TextDecoration decoration) {
}
Objects.requireNonNull(decoration);
Text text = new Text(Objects.requireNonNull(content));
text.setFill(decoration.getForeground());
String foreground = decoration.getForeground();
text.setFill(COLOR_MAP.computeIfAbsent(foreground, s -> parseColorOrDefault(foreground, Color.BLACK)));
text.setStrikethrough(decoration.isStrikethrough());
text.setUnderline(decoration.isUnderline());

Expand Down Expand Up @@ -353,4 +359,11 @@ private Optional<ParagraphTile> getParagraphTile() {
return Optional.empty();
}

private static Color parseColorOrDefault(String color, Color defaultColor) {
try {
return Color.web(color);
} catch (Exception e) {
return defaultColor;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -27,12 +27,14 @@
*/
package com.gluonhq.richtextarea.model;

import java.io.Serializable;

/**
* Interface used to define the decoration applied to a fragment of RichTextArea
*
* Known implementations: {@link TextDecoration} and {@link ImageDecoration} for
* text decoration, and {@link ParagraphDecoration} for paragraph decoration
*/
public interface Decoration {
public interface Decoration extends Serializable {

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -27,13 +27,14 @@
*/
package com.gluonhq.richtextarea.model;

import java.io.Serializable;
import java.util.Objects;

/**
* A DecorationModel contains the text and paragraph decorations for a fragment of text,
* defined by a start position and a length.
*/
public class DecorationModel {
public class DecorationModel implements Serializable {
private final int start;
private final int length;
private final Decoration decoration; // TextDecoration or ImageDecoration
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -29,6 +29,7 @@

import com.gluonhq.richtextarea.Tools;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
Expand All @@ -46,7 +47,7 @@
* decorations or caret position) should refer to their position within the full raw text.
*
*/
public class Document {
public class Document implements Serializable {

private final String text;
private final List<DecorationModel> decorationList;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -41,8 +41,8 @@
*/
public class TextDecoration implements Decoration {

private Color foreground;
private Color background;
private String foreground;
private String background;
private String fontFamily;
private double fontSize;
private FontPosture fontPosture;
Expand All @@ -55,30 +55,32 @@ private TextDecoration() {}

/**
* Gets the foreground color of the text.
* Any string value that can be parsed with {@link Color#web(String)}
*
* @defaultValue {@link Color#BLACK}
* @defaultValue #000000, black
*
* @return the foreground color of the text
*/
public Color getForeground() {
public String getForeground() {
return foreground;
}

/**
* Gets the background color of the text.
* Any string value that can be parsed with {@link Color#web(String)}
*
* @defaultValue {@link Color#TRANSPARENT}
* @defaultValue #00000000, transparent
*
* @return the background color of the text
*/
public Color getBackground() {
public String getBackground() {
return background;
}

/**
* Gets the font size of the text.
*
* @defaultValue 12
* @defaultValue 14
*
* @return the font size of the text
*/
Expand Down Expand Up @@ -210,8 +212,8 @@ public int hashCode() {

public static class Builder {

private Color foreground;
private Color background;
private String foreground;
private String background;
private String fontFamily;
private double fontSize;
private FontPosture fontPosture;
Expand All @@ -237,8 +239,8 @@ public TextDecoration build() {
}

public Builder presets() {
foreground = Color.BLACK;
background = Color.TRANSPARENT;
foreground = "black";
background = "transparent";
fontFamily = "System";
fontSize = 14.0;
fontPosture = FontPosture.REGULAR;
Expand All @@ -262,12 +264,12 @@ public Builder fromDecoration(TextDecoration decoration) {
return this;
}

public Builder foreground(Color color) {
public Builder foreground(String color) {
this.foreground = Objects.requireNonNull(color);
return this;
}

public Builder background(Color color) {
public Builder background(String color) {
this.background = Objects.requireNonNull(color);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2023, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -27,7 +27,6 @@
*/
package com.gluonhq.richtextarea.model;

import javafx.scene.paint.Color;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -232,11 +231,11 @@ public void emojiSameBlockDecorateWeight() {
public void sameBlockDecorateForegroundColor() {
String text = "Original Bigger Text";
PieceTable pt = new PieceTable(new Document(text));
pt.decorate(1, 2, TextDecoration.builder().foreground(Color.AQUA).build());
pt.decorate(1, 2, TextDecoration.builder().foreground("aqua").build());
Assertions.assertEquals(text, pt.getText());
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getInternalText().equals("r"))
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getForeground() == Color.AQUA)
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getForeground().equals("aqua"))
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -251,11 +251,11 @@ public void sameBlockDecoratePosture() {
public void sameBlockDecorateForegroundColor() {
String text = "Original Bigger Text";
PieceTable pt = new PieceTable(new Document(text));
pt.decorate(1, 2, TextDecoration.builder().foreground(Color.AQUA).build());
pt.decorate(1, 2, TextDecoration.builder().foreground("aqua").build());
Assertions.assertEquals(text, pt.getText());
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getInternalText().equals("r"))
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getForeground() == Color.AQUA)
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getForeground().equals("aqua"))
);
}

Expand All @@ -264,11 +264,11 @@ public void sameBlockDecorateForegroundColor() {
public void sameBlockDecorateBackgroundColor() {
String text = "Original Bigger Text";
PieceTable pt = new PieceTable(new Document(text));
pt.decorate(1, 2, TextDecoration.builder().background(Color.AQUA).build());
pt.decorate(1, 2, TextDecoration.builder().background("aqua").build());
Assertions.assertEquals(text, pt.getText());
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getInternalText().equals("r"))
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getBackground() == Color.AQUA)
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getBackground().equals("aqua"))
);
}

Expand Down Expand Up @@ -464,12 +464,12 @@ public void multiBlockDecorateSizeAndColor() {
pt.insert(insert, 9); // 'Original Bigger Text'
pt.insert(insert, 9); // 'Original Bigger Bigger Text'
pt.decorate(9, 15, TextDecoration.builder().fontSize(20).build());
pt.decorate(9, 15, TextDecoration.builder().foreground(Color.AQUA).build());
pt.decorate(9, 15, TextDecoration.builder().foreground("aqua").build());
Assertions.assertEquals("Original Bigger Bigger Text", pt.getText());
Assertions.assertTrue(pt.pieces.stream()
.filter(piece -> piece.getInternalText().equals("Bigger"))
.anyMatch(piece -> ((TextDecoration) piece.getDecoration()).getFontSize() == 20 &&
((TextDecoration) piece.getDecoration()).getForeground() == Color.AQUA)
((TextDecoration) piece.getDecoration()).getForeground().equals("aqua"))
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2023, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -35,7 +35,6 @@
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.List;
Expand Down Expand Up @@ -82,7 +81,7 @@ public void start(Stage stage) {
TextDecoration textDecoration = TextDecoration.builder().presets()
.fontFamily("Arial")
.fontSize(20)
.foreground(Color.RED)
.foreground("red")
.build();
ParagraphDecoration paragraphDecoration = ParagraphDecoration.builder().presets().build();
DecorationModel decorationModel = new DecorationModel(0, text.length(), textDecoration, paragraphDecoration);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2023, Gluon
* Copyright (c) 2022, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -140,7 +140,7 @@ public class FullFeaturedDemo extends Application {
private final List<DecorationModel> decorations;

{
TextDecoration bold14 = TextDecoration.builder().presets().fontWeight(BOLD).fontSize(14).build();
TextDecoration bold14 = TextDecoration.builder().presets().fontWeight(BOLD).fontSize(14).foreground("darkblue").build();
TextDecoration preset = TextDecoration.builder().presets().build();
ParagraphDecoration center63 = ParagraphDecoration.builder().presets().alignment(TextAlignment.CENTER).topInset(6).bottomInset(3).build();
ParagraphDecoration justify22 = ParagraphDecoration.builder().presets().alignment(TextAlignment.JUSTIFY).topInset(2).bottomInset(2).build();
Expand Down Expand Up @@ -243,12 +243,12 @@ public Double fromString(String s) {

final ColorPicker textForeground = new ColorPicker();
textForeground.getStyleClass().add("foreground");
new TextDecorateAction<>(editor, textForeground.valueProperty(), TextDecoration::getForeground, (builder, a) -> builder.foreground(a).build());
new TextDecorateAction<>(editor, textForeground.valueProperty(), (TextDecoration textDecoration1) -> Color.web(textDecoration1.getForeground()), (builder, a) -> builder.foreground(toHexString(a)).build());
textForeground.setValue(Color.BLACK);

final ColorPicker textBackground = new ColorPicker();
textBackground.getStyleClass().add("background");
new TextDecorateAction<>(editor, textBackground.valueProperty(), TextDecoration::getBackground, (builder, a) -> builder.background(a).build());
new TextDecorateAction<>(editor, textBackground.valueProperty(), (TextDecoration textDecoration) -> Color.web(textDecoration.getBackground()), (builder, a) -> builder.background(toHexString(a)).build());
textBackground.setValue(Color.TRANSPARENT);

CheckBox editableProp = new CheckBox("Editable");
Expand Down Expand Up @@ -598,6 +598,13 @@ private TextDecoration getStyleFromMarker(String marker) {
return builder.build();
}

private String toHexString(Color value) {
return String.format("#%02X%02X%02X%02X", (int) Math.round(value.getRed() * 255),
(int) Math.round(value.getGreen() * 255),
(int) Math.round(value.getBlue() * 255),
(int) Math.round(value.getOpacity() * 255));
}

public static void main(String[] args) {
launch(args);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Gluon
* Copyright (c) 2023, 2024, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -35,7 +35,6 @@
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.ArrayList;
Expand Down Expand Up @@ -71,7 +70,7 @@ public class HighlightDemo extends Application {
TextDecoration.builder().presets().fontFamily("Arial").fontWeight(BOLD).fontSize(16).build();
private static final TextDecoration mono =
TextDecoration.builder().presets().fontFamily("Monospaced").fontWeight(BOLD)
.fontPosture(ITALIC).background(Color.CORNFLOWERBLUE).build();
.fontPosture(ITALIC).background("#6495ED").build();
private static final ParagraphDecoration parPreset =
ParagraphDecoration.builder().presets().build();

Expand Down

0 comments on commit 768cb64

Please sign in to comment.