Skip to content

PS, S, and SEG: Explaining the main generics in RichTextFX

JordanMartinez edited this page Jan 13, 2018 · 1 revision

This page was written in response to the question, "What exactly is the SEG generic?" Along the way, we'll explain what the other generics, PS and S, are.

In RichTextFX's original design (this has changed since then, and we'll get to that in a bit), a segment used to be nothing more than a String for the text part and a Style (the S generic) for the style part. This was stored in the class called StyledText<S> with the style part and the text part stored in the same object (rather than two separate objects as it is currently).

This is what the class looked like in code.

public class StyledText<S> {
    private final String text;
    private final S style;

    // constructor, getters, setters (returns a new immutable StyledText object)
    //  equals, & hashcode
}

One line of text (i.e. a Paragraph<S>) might have differently styled texts, so the data was stored in a List<StyledText<S>> object:

Text:  a lucky cat caught a mouse when wandering around the house
Style: | red font |   italics   | red and bold                  |
List:  | index 0  | index 1     | index 2

This is what the data type looked like in code:

public class Paragraph<S> {
    private final List<StyledText<S>> segments

    // constructor, getters, setters (returns a new immutable Paragraph object)
    //  equals, & hashcode
}

The area's content would be composed of multiple lines (i.e. Paragraphs) of styled text. Thus, we would sumamrize these into a StyledDocument<S> that would store a List<Paragraph<S>> object:

public class StyledDocument<S> {
    private final List<Paragraph<S>> paragraphs;
    
    // constructor, getters, setters (returns a new immutable StyledText object)
    //  equals, & hashcode
}

Later on, someone wanted to be able to align the text to the right, so they added paragraph styles (the PS generic) to the text model. Now, each Paragraph<PS, S> could be styled so that all of its text could be left/center/right-aligned. This changed StyledDocument<S> (and related underlying classes) to StyledDocument<PS, S>.

Later on, someone thought "But a rich text editor should be able to display more than just text! What if we wanted to render an image in-line with the text?" So, they introduced the idea of a segment (the SEG generic). If one wanted to render both text and images to the area, they could now do so. This change resulted in StyledDocument<PS, S> changing to StyledDocument<PS, SEG, S>.

The SEG object was made completely generic, so that it does not need any specific methods, which allows the developer complete freedom as to what that object should / could be. This led to the addition of the SegmentOps<SEG, S> (read: segment operations) interface in order to get the methods we need to operate on a segment (e.g. concat, subsequence, length, etc.).

So, to answer the question, what exactly is SEG? Technically it's any data type that you want to display in the area. It can be any POJO, for example Address or Person or String which is what it is in InlineCssTextArea.

To display SEGs visually in the area a node factory function needs to be supplied that receives StyledSegment<SEG, S> as a parameter and returns an object that extends Node. So if for example SEG was of type Person one could for instance display the person's name and surname in a Hyperlink control, or maybe display a thumbnail pic of the person with ImageView.

SEG can also be a combination of data types, like String and Image. This can be done by using the type-container-like type, Either: Either<String, Image>. Such an object is either the left type (String) or the right type (Image). Theoretically, one could use it to render multiple objects such as Either<String, Either<Image, Either<Table, Video>>>, but this gets rather hectic since Java doesn't support type aliases.

Bear in mind that each SEG type needs a corresponding SegmentOps implementation. So for Strings you can use one of the SegmentOps.styledTextOps() variants, and for Images or any other POJO you can extend NodeSegmentOpsBase. Also note that SEG must be immutable.