Skip to content
JordanMartinez edited this page Jan 25, 2017 · 5 revisions

The following diagram shows the core classes which RichTextFX uses internally (use "Open image in new tab" from your browser's context menu to get a larger image). They are described in more detail below.

Class Diagram

Essentially, the code is divided into two packages: the Model part (org.fxmisc.richtext.model) and the View part (org.fxmisc.richtext). The Model contains the structure of the document, and the View uses the Model to render the document in a JavaFX scene.

The core Model classes are:

  • Paragraph

    This is one Paragraph of the document. Depending on whether the text is wrapped, it corresponds to a single line or it can also span multiple lines. A Paragraph contains of a list of SEG objects which make up the individual segments of the Paragraph. By providing a specific segment object and an associated segment operations object, all required data and the necessary operations on this data for a single segment can be provided. For example, StyledText<S> is a segment type which is used in the StyledTextArea, a text area which can render simple text only (which is already sufficient to implement all kinds of code editors). For more complex requirements (for example, when images shall be part of the document) a different segment type must be provided (which can make use of StyledText<S> for the text part and add another segment type for images). Note that Paragraph is an immutable class - to modify a Paragraph, a new Paragraph object must be created. Paragraph itself contains some methods which take care of this, such as concat(), which appends some Paragraph to the current one and returns a new Paragraph.

  • StyledDocument

    StyledDocument is an interface to the document itself. Its implementation class (ReadOnlyStyledDocument) contains essentially a list of Paragraph objects. [pending: EditableStyledDocument]

  • TwoLevelNavigator / Position / TwoDimensional

    These classes and interfaces are used as a pointer into the document to specify a particular position inside the document. Essentially, a TwoLevelNavigator contains a major index (such as the Paragraph index within the StyledDocument) and a minor index (such as the segment index within the Paragraph).

The core View classes are:

  • TextExt

    This is an extension of the JavaFX Text class which adds some missing rendering options, such as a background shape.

  • ParagraphText

    This is the container for the Text objects. It is essentially a TextFlow so that it takes care of laying out the text segments correctly.

  • ParagraphBox

    This class adds a label (such as a line number) in front of the Paragraph text.

  • VirtualFlow

    Rather than laying out all the Paragraphs in the scene graph, RichTextFX's areas use a VirtualFlow from Flowless. Thus, the viewport only displays enough Paragraphs to fill the viewport. All other Paragraph objects are left undisplayed until needed.

  • StyledTextAreaBehavior

    This is essentially the controller for the styled text area. It takes the user input and modifies the model appropriately. When the model has been modified, the view is adjusted by recreating the affected cells of the text flow layout.

    StyledTextAreaBehavior uses InputMapTemplates from the WellBehavedFX library. This allows two things: defining actions for keyboard actions in an almost declarative way and allowing easy overriding of the default behavior.

Defining Actions Declaratively

For example, editsBase maps the primary control keys like DELETE, BACKSPACE or ENTER. If we want to add a specific key mapping to perform a special action whenever this key combination is pressed, we can simply add that key or key combination as an additional consumer. Lets say we want to add SHIFT-ENTER to add functionality for a soft line break, or SHIFT-TAB for some outdent functionality. Those key combinations can be added like

InputMapTemplate<StyledTextAreaBehavior, KeyEvent> editsBase = sequence(
...
   // tab & newline
   consume(keyPressed(ENTER, SHIFT_DOWN), (b, e) -> b.model.addSoftLinebreak()),
   consume(keyPressed(TAB, SHIFT_DOWN), (b, e) -> b.model.outdent()),
...
);

Then, one only needs to implement the corresponding addSoftLinebreak() and outdent() methods in the StyledTextAreaModel class. Those methods will now be called whenever SHIFT-ENTER or SHIFT-TAB is pressed and can adjust the model accordingly.

Overriding Default Behavior

To override the default behavior, one only needs to use the above example to create an InputMap (for instances of a class) or InputMapTempate (for all instances of a class). Then, one merely writes the code:

InputMap<StyledTextArea, KeyEvent> overrides = // creation code
Nodes.addInputMap(area, overrides);
);
  • GenericStyledArea

    This is the base area which all other area classes subclass. It is a generic rich text area which can be parameterized to render any kind of rich text. Subclass this class when rendering custom objects.

  • StyledTextArea and its sub classes

    StyledTextArea is only capable of rendering StyledText segments. This class hierarchy can be used to implement text editors such as code editors with syntax highlighting.