# Class StyledTextModel

java.lang.Object
jfx.incubator.scene.control.richtext.model.StyledTextModel

Direct Known Subclasses:
  `BasicTextModel`, `RichTextModel`, `StyledTextModelViewOnlyBase`

public abstract class StyledTextModel extends Object
The base class for styled text models used by the `RichTextArea`.

This class handles the following functionality with the intent to simplify custom models:

- managing listeners
- firing events
- decomposing the edits into multiple operations performed on individual paragraphs
- managing `Marker`s

## Editing

The model supports editing when `isWritable()` returns `true`. Three methods participate in modification of the content: `replace(StyleResolver, TextPos, TextPos, String, boolean)`, `replace(StyleResolver, TextPos, TextPos, StyledInput, boolean)`, `applyStyle(TextPos, TextPos, StyleAttributeMap, boolean)`. These methods decompose the main modification into operations with individual paragraphs and delegate these to subclasses.

At the end of this process, an event is sent to all the `StyledTextModel.Listener`s, followed by the skin requesting the updated paragraphs when required.

## Creating a Paragraph

The model presents its content to the view(s) via immutable `RichParagraph`. There are two ways of adding styles to the model:

- Using the style names in the stylesheet or inline styles (example: `"-fx-font-size:200%;"`), or
- Using attributes defined in `StyleAttributeMap`, such as bold typeface, italic, and so on. In this case, the resulting paragraph appearance is decoupled from the stylesheet and will look the same regardless of the active stylesheet.

The latter method is intended for applications where an editable control is needed, such as general purpose rich text editor, the former is designed for view-only informational controls that must follow the application theme and therefore are coupled to the stylesheet.

## Extending the Model

The subclasses are free to choose how the data is stored, the only limitation is that the model neither stores nor caches any `Node`s, since multiple skins might be attached to the same model. When required, the model may contain properties which can be bound to the Nodes created in `getParagraph(int)`. It is the responsibility of the model to store and restore the values of such properties.

Since:
  24

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Class
  Description
  `static interface`
  `StyledTextModel.Listener`
  Receives information about modifications of the model.

- ## Property Summary

  Properties
  Type
  Property
  Description
  `final ReadOnlyBooleanProperty`
  `redoable`
  The property describes if it's currently possible to redo the latest change of the content that was undone.
  `final ReadOnlyBooleanProperty`
  `undoable`
  The property describes if it's currently possible to undo the latest change of the content that was done.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `StyledTextModel()`
  Constructs the instance of the model.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `final void`
  `addListener(StyledTextModel.Listener listener)`
  Adds a `StyledTextModel.Listener` to this model.
  `protected abstract void`
  `applyStyle(int index, int start, int end, StyleAttributeMap a, boolean merge)`
  Applies style to the specified text range within a single paragraph.
  `final void`
  `applyStyle(TextPos start, TextPos end, StyleAttributeMap attrs, boolean mergeAttributes)`
  Applies the style attributes to the specified range in the document.
  `final TextPos`
  `clamp(TextPos p)`
  Returns the text position guaranteed to be within the document and paragraph limits.
  `final void`
  `clearUndoRedo()`
  Clears the undo-redo stack.
  `final void`
  `export(TextPos start, TextPos end, StyledOutput out)`
  Exports the stream of `StyledSegment`s in the given range to the specified `StyledOutput`.
  `protected final void`
  `exportParagraph(int index, int start, int end, boolean withParAttrs, StyledOutput out)`
  Exports part of the paragraph as a sequence of styled segments.
  `void`
  `fireChangeEvent(TextPos start, TextPos end, int charsTop, int linesAdded, int charsBottom)`
  Fires a text modification event for the given range.
  `void`
  `fireStyleChangeEvent(TextPos start, TextPos end)`
  Fires a style change event for the given range.
  `final DataFormatHandler`
  `getDataFormatHandler(DataFormat format, boolean forExport)`
  Returns a `DataFormatHandler` instance corresponding to the given `DataFormat`.
  `final TextPos`
  `getDocumentEnd()`
  Returns the text position corresponding to the end of the document.
  `final TextPos`
  `getEndOfParagraphTextPos(int index)`
  Returns a TextPos corresponding to the end of paragraph at the given index.
  `final Marker`
  `getMarker(TextPos pos)`
  Returns the `Marker` at the specified position.
  `abstract RichParagraph`
  `getParagraph(int index)`
  Returns a `RichParagraph` at the given model index.
  `int`
  `getParagraphLength(int index)`
  Returns the length of text in a paragraph at the specified index.
  `abstract String`
  `getPlainText(int index)`
  Returns the plain text string for the specified paragraph.
  `abstract StyleAttributeMap`
  `getStyleAttributeMap(StyleResolver resolver, TextPos pos)`
  Returns the `StyleAttributeMap` of the character at the specified position's `charIndex`.
  `protected Set<StyleAttribute<?>>`
  `getSupportedAttributes()`
  Returns the set of attributes supported attributes.
  `final List<DataFormat>`
  `getSupportedDataFormats(boolean forExport)`
  Returns an immutable list of supported data formats for either export or import operations, in the order of priority - from high to low.
  `protected abstract void`
  `insertLineBreak(int index, int offset)`
  Inserts a line break at the specified position.
  `protected abstract void`
  `insertParagraph(int index, Supplier<Region> generator)`
  Inserts a paragraph that contains a single `Region`.
  `protected abstract int`
  `insertTextSegment(int index, int offset, String text, StyleAttributeMap attrs)`
  This method is called to insert a single styled text segment at the given position.
  `final boolean`
  `isRedoable()`
  Gets the value of the `redoable` property.
  `final boolean`
  `isUndoable()`
  Gets the value of the `undoable` property.
  `abstract boolean`
  `isWritable()`
  Indicates whether the model supports content modifications made via `applyStyle()`, `replace()`, `undo()`, `redo()` methods.
  `final void`
  `read(StyleResolver r, DataFormat f, InputStream input)`
  Replaces the content of the model with the data read from the input stream, using the specified `DataFormat`.
  `final TextPos[]`
  `redo(StyleResolver resolver)`
  Redoes the recent change, if possible, returning an array comprising [start, end] text positions prior to the change.
  `final ReadOnlyBooleanProperty`
  `redoableProperty()`
  The property describes if it's currently possible to redo the latest change of the content that was undone.
  `protected final void`
  `registerDataFormatHandler(DataFormatHandler h, boolean forExport, boolean forImport, int priority)`
  Registers a format handler for export and/or import operations.
  `protected final void`
  `removeDataFormatHandler(DataFormat f, boolean forExport, boolean forImport)`
  Removes the data format handler registered previously with `registerDataFormatHandler(DataFormatHandler, boolean, boolean, int)`.
  `final void`
  `removeListener(StyledTextModel.Listener listener)`
  Removes a `StyledTextModel.Listener` from this model.
  `protected abstract void`
  `removeRange(TextPos start, TextPos end)`
  Removes the specified text range.
  `final TextPos`
  `replace(StyleResolver resolver, TextPos start, TextPos end, String text, boolean allowUndo)`
  Replaces the given range with the provided plain text.
  `final TextPos`
  `replace(StyleResolver resolver, TextPos start, TextPos end, StyledInput input, boolean allowUndo)`
  Replaces the given range with the provided styled text input.
  `protected abstract void`
  `setParagraphStyle(int index, StyleAttributeMap paragraphAttrs)`
  Replaces the paragraph styles in the specified paragraph.
  `abstract int`
  `size()`
  Returns the number of paragraphs in the model.
  `final TextPos[]`
  `undo(StyleResolver resolver)`
  Undoes the recent change, if possible, returning an array comprising [start, end] text positions prior to the change.
  `final ReadOnlyBooleanProperty`
  `undoableProperty()`
  The property describes if it's currently possible to undo the latest change of the content that was done.
  `final void`
  `write(StyleResolver r, DataFormat f, OutputStream out)`
  Writes the model content to the output stream using the specified `DataFormat`.

  ### Methods declared in class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Property Details

  - ### undoable

    public final ReadOnlyBooleanProperty undoableProperty
    The property describes if it's currently possible to undo the latest change of the content that was done.
    Default value:
      false
    See Also:
      - `isUndoable()`
      - `undoableProperty()`

  - ### redoable

    public final ReadOnlyBooleanProperty redoableProperty
    The property describes if it's currently possible to redo the latest change of the content that was undone.
    Default value:
      false
    See Also:
      - `isRedoable()`
      - `redoableProperty()`

- ## Constructor Details

  - ### StyledTextModel

    public StyledTextModel()
    Constructs the instance of the model.

    This constructor registers data handlers for RTF, HTML (export only), and plain text.

- ## Method Details

  - ### isWritable

    public abstract boolean isWritable()
    Indicates whether the model supports content modifications made via `applyStyle()`, `replace()`, `undo()`, `redo()` methods.

    Note that even when this method returns `false`, the model itself may still update its content and fire the change events as a response, for example, to changes in its backing data storage.

    Returns:
      true if the model supports content modifications

  - ### size

    public abstract int size()
    Returns the number of paragraphs in the model.
    Returns:
      number of paragraphs

  - ### getPlainText

    public abstract String getPlainText(int index)
    Returns the plain text string for the specified paragraph. The returned text string cannot be null and must not contain any control characters other than TAB. The callers must ensure that the value of `index` is within the valid document range, since doing otherwise might result in an exception or undetermined behavior.
    Parameters:
      `index` - the paragraph index in the range (0...`size()`)
    Returns:
      the non-null paragraph text string

  - ### getParagraph

    public abstract RichParagraph getParagraph(int index)
    Returns a `RichParagraph` at the given model index. The callers must ensure that the value of `index` is within the valid document range, since doing otherwise might result in an exception or undetermined behavior.

    This method makes no guarantees that the same paragraph instance will be returned for the same model index.

    Parameters:
      `index` - the paragraph index in the range (0...`size()`)
    Returns:
      the instance of `RichParagraph`

  - ### removeRange

    protected abstract void removeRange(TextPos start, TextPos end)
    Removes the specified text range. This method gets called only if the model is editable. The caller guarantees that `start` precedes `end`.
    Parameters:
      `start` - the start of the range to be removed
      `end` - the end of the range to be removed, expected to be greater than the start position
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### insertTextSegment

    protected abstract int insertTextSegment(int index, int offset, String text, StyleAttributeMap attrs)
    This method is called to insert a single styled text segment at the given position.
    Parameters:
      `index` - the paragraph index
      `offset` - the insertion offset within the paragraph
      `text` - the text to insert
      `attrs` - the style attributes
    Returns:
      the number of characters inserted
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### insertLineBreak

    protected abstract void insertLineBreak(int index, int offset)
    Inserts a line break at the specified position.
    Parameters:
      `index` - the model index
      `offset` - the text offset
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### insertParagraph

    protected abstract void insertParagraph(int index, Supplier<Region> generator)
    Inserts a paragraph that contains a single `Region`.

    The model should not cache or otherwise retain references to the created `Region`s, as they might be requested multiple times during the lifetime of the model, or by different views.

    This method allows for embedding `Control`s that handle user input. In this case, the model should declare necessary properties and provide bidirectional bindings between the properties in the model and the corresponding properties in the control, as well as handle copy, paste, writing to and reading from I/O streams.

    Parameters:
      `index` - model index
      `generator` - code that will be used to create a Node instance
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### setParagraphStyle

    protected abstract void setParagraphStyle(int index, StyleAttributeMap paragraphAttrs)
    Replaces the paragraph styles in the specified paragraph.
    Parameters:
      `index` - the paragraph index
      `paragraphAttrs` - the paragraph attributes
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### applyStyle

    protected abstract void applyStyle(int index, int start, int end, StyleAttributeMap a, boolean merge)
    Applies style to the specified text range within a single paragraph. The new attributes override any existing attributes. The `end` argument may exceed the paragraph length, in which case the outcome should be the same as supplying the paragraph length value.
    Parameters:
      `index` - the paragraph index
      `start` - the start offset
      `end` - the end offset
      `a` - the character attributes
      `merge` - determines whether to merge with or overwrite the existing attributes
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### getStyleAttributeMap

    public abstract StyleAttributeMap getStyleAttributeMap(StyleResolver resolver, TextPos pos)
    Returns the `StyleAttributeMap` of the character at the specified position's `charIndex`. When at the end of the document, returns the attributes of the last character.
    Parameters:
      `resolver` - the style resolver
      `pos` - the text position
    Returns:
      the style attributes, non-null

  - ### getSupportedAttributes

    protected Set<StyleAttribute<?>> getSupportedAttributes()
    Returns the set of attributes supported attributes. When this method returns a non-null set, it will be used by the methods which handle the external input for the purpose of filtering out the attributes the model cannot understand, preventing the attributes from being added to the model (for example, as a result of pasting from the system clipboard).

    The methods that utilize the filtering are: `applyStyle(TextPos, TextPos, StyleAttributeMap, boolean)`, `replace(StyleResolver, TextPos, TextPos, StyledInput, boolean)`, and `replace(StyleResolver, TextPos, TextPos, String, boolean)`.

    When this method returns `null`, no filtering is performed.

    This method might be overridden by certain models. The base class implementation returns `null`.

    Returns:
      the set of supported attributes, or null if the model requires no filtering

  - ### addListener

    public final void addListener(StyledTextModel.Listener listener)
    Adds a `StyledTextModel.Listener` to this model.
    Parameters:
      `listener` - a non-null listener

  - ### removeListener

    public final void removeListener(StyledTextModel.Listener listener)
    Removes a `StyledTextModel.Listener` from this model.

    This method does nothing if this listener has never been added.

    Parameters:
      `listener` - a non-null listener

  - ### registerDataFormatHandler

    protected final void registerDataFormatHandler(DataFormatHandler h, boolean forExport, boolean forImport, int priority)
    Registers a format handler for export and/or import operations. The priority determines the format chosen for operations with the `Clipboard` when input data is available in more than one supported format. The handler with the highest priority will be used by `RichTextArea.read(InputStream)` and `RichTextArea.write(OutputStream)` methods.

    The same handler can be registered for input and export. When registering multiple handlers for the same data handler and import/export, the last registered one wins.

    This method is expected to be called from a `StyledTextModel` child class constructor.

    Parameters:
      `h` - data format handler
      `forExport` - true if the handler supports export operations
      `forImport` - true if the handler supports import operations
      `priority` - from 0 (lowest, usually plain text) to `Integer.MAX_VALUE`

  - ### removeDataFormatHandler

    protected final void removeDataFormatHandler(DataFormat f, boolean forExport, boolean forImport)
    Removes the data format handler registered previously with `registerDataFormatHandler(DataFormatHandler, boolean, boolean, int)`.
    Parameters:
      `f` - the data format
      `forExport` - whether to remove the export handler
      `forImport` - whether to remove the import handler

  - ### getSupportedDataFormats

    public final List<DataFormat> getSupportedDataFormats(boolean forExport)
    Returns an immutable list of supported data formats for either export or import operations, in the order of priority - from high to low.

    The top priority format will be used by `RichTextArea.read(InputStream)` and `RichTextArea.write(OutputStream)` methods.

    Parameters:
      `forExport` - determines whether the operation is export (true) or import (false)
    Returns:
      the immutable list of supported formats

  - ### getDataFormatHandler

    public final DataFormatHandler getDataFormatHandler(DataFormat format, boolean forExport)
    Returns a `DataFormatHandler` instance corresponding to the given `DataFormat`. This method will return `null` if the data format is not supported.
    Parameters:
      `format` - data format
      `forExport` - for export (true) or for input (false)
    Returns:
      DataFormatHandler or null

  - ### fireChangeEvent

    public void fireChangeEvent(TextPos start, TextPos end, int charsTop, int linesAdded, int charsBottom)
    Fires a text modification event for the given range.
    Parameters:
      `start` - start of the affected range
      `end` - end of the affected range
      `charsTop` - number of characters added before any added paragraphs
      `linesAdded` - number of paragraphs inserted
      `charsBottom` - number of characters added after any inserted paragraphs

  - ### fireStyleChangeEvent

    public void fireStyleChangeEvent(TextPos start, TextPos end)
    Fires a style change event for the given range. This event indicates that only the styling has changed, with no changes to any text positions.
    Parameters:
      `start` - the start position
      `end` - the end position, must be greater than the start position

  - ### getParagraphLength

    public int getParagraphLength(int index)
    Returns the length of text in a paragraph at the specified index.
    Parameters:
      `index` - the paragraph index
    Returns:
      the length

  - ### export

    public final void export(TextPos start, TextPos end, StyledOutput out) throws IOException
    Exports the stream of `StyledSegment`s in the given range to the specified `StyledOutput`. This method does not close the `StyledOutput`.
    Parameters:
      `start` - start of the range
      `end` - end of the range
      `out` - `StyledOutput` to receive the stream
    Throws:
      `IOException` - when an I/O error occurs
    See Also:
      - `replace(StyleResolver, TextPos, TextPos, StyledInput, boolean)`

  - ### exportParagraph

    protected final void exportParagraph(int index, int start, int end, boolean withParAttrs, StyledOutput out) throws IOException
    Exports part of the paragraph as a sequence of styled segments. The caller guarantees that the start position precedes the end. The subclass may override this method to provide a more performant implementation. The paragraph end argument may exceed the actual length of the paragraph, in which case it should be treated as equal to the paragraph text length.
    Parameters:
      `index` - the paragraph index in the model
      `start` - the start offset
      `end` - the end offset (may exceed the paragraph length)
      `withParAttrs` - determines whether to emit paragraph attributes
      `out` - the target StyledOutput
    Throws:
      `IOException` - when an I/O error occurs

  - ### getMarker

    public final Marker getMarker(TextPos pos)
    Returns the `Marker` at the specified position. The actual text position tracked by the marker will always be within the document boundaries.
    Parameters:
      `pos` - text position
    Returns:
      Marker instance

  - ### clamp

    public final TextPos clamp(TextPos p)
    Returns the text position guaranteed to be within the document and paragraph limits.
    Parameters:
      `p` - the text position, cannot be null
    Returns:
      the text position within the document and paragraph limits

  - ### getDocumentEnd

    public final TextPos getDocumentEnd()
    Returns the text position corresponding to the end of the document. The start of the document can be referenced by the `TextPos.ZERO` constant.
    Returns:
      the text position
    See Also:
      - `TextPos.ZERO`

  - ### getEndOfParagraphTextPos

    public final TextPos getEndOfParagraphTextPos(int index)
    Returns a TextPos corresponding to the end of paragraph at the given index.
    Parameters:
      `index` - the paragraph index
    Returns:
      the text position

  - ### replace

    public final TextPos replace(StyleResolver resolver, TextPos start, TextPos end, String text, boolean allowUndo)
    Replaces the given range with the provided plain text.

    This is a convenience method which eventually calls `replace(StyleResolver, TextPos, TextPos, StyledInput, boolean)` with the attributes provided by `getStyleAttributeMap(StyleResolver, TextPos)` at the `start` position.

    Parameters:
      `resolver` - the StyleResolver to use
      `start` - start text position
      `end` - end text position
      `text` - text string to insert
      `allowUndo` - when true, creates an undo-redo entry
    Returns:
      the text position at the end of the inserted text, or null if the model is read only
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### replace

    public final TextPos replace(StyleResolver resolver, TextPos start, TextPos end, StyledInput input, boolean allowUndo)
    Replaces the given range with the provided styled text input. When inserting plain text, the style is taken from the preceding text segment, or, if the text is being inserted in the beginning of the document, the style is taken from the following text segment.

    After the model applies the requested changes, an event is sent to all the registered listeners.

    Parameters:
      `resolver` - the StyleResolver to use, can be null
      `start` - the start text position
      `end` - the end text position
      `input` - the input content stream
      `allowUndo` - when true, creates an undo-redo entry
    Returns:
      the text position at the end of the inserted text, or null if the model is read only
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### applyStyle

    public final void applyStyle(TextPos start, TextPos end, StyleAttributeMap attrs, boolean mergeAttributes)
    Applies the style attributes to the specified range in the document.

    Depending on `mergeAttributes` parameter, the attributes will either be merged with (true) or completely replace the existing attributes within the range. The affected range might be wider than the range specified when applying the paragraph attributes.

    This operation is undoable.

    Parameters:
      `start` - the start of text range
      `end` - the end of text range
      `attrs` - the style attributes to set
      `mergeAttributes` - whether to merge or replace the attributes
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### clearUndoRedo

    public final void clearUndoRedo()
    Clears the undo-redo stack.

  - ### undo

    public final TextPos[] undo(StyleResolver resolver)
    Undoes the recent change, if possible, returning an array comprising [start, end] text positions prior to the change. Returns null when the undo operation is not possible.
    Parameters:
      `resolver` - the StyleResolver to use
    Returns:
      the [start, end] text positions prior to the change
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### redo

    public final TextPos[] redo(StyleResolver resolver)
    Redoes the recent change, if possible, returning an array comprising [start, end] text positions prior to the change. Returns null when the redo operation is not possible.
    Parameters:
      `resolver` - the StyleResolver to use
    Returns:
      the [start, end] text positions prior to the change
    Throws:
      `UnsupportedOperationException` - if the model is not `writable`

  - ### undoableProperty

    public final ReadOnlyBooleanProperty undoableProperty()
    The property describes if it's currently possible to undo the latest change of the content that was done.
    Default value:
      false
    Returns:
      the read-only property
    See Also:
      - `isUndoable()`

  - ### isUndoable

    public final boolean isUndoable()
    Gets the value of the `undoable` property.
    Property description:
      The property describes if it's currently possible to undo the latest change of the content that was done.
    Default value:
      false
    Returns:
      the value of the `undoable` property
    See Also:
      - `undoableProperty()`

  - ### redoableProperty

    public final ReadOnlyBooleanProperty redoableProperty()
    The property describes if it's currently possible to redo the latest change of the content that was undone.
    Default value:
      false
    Returns:
      the read-only property
    See Also:
      - `isRedoable()`

  - ### isRedoable

    public final boolean isRedoable()
    Gets the value of the `redoable` property.
    Property description:
      The property describes if it's currently possible to redo the latest change of the content that was undone.
    Default value:
      false
    Returns:
      the value of the `redoable` property
    See Also:
      - `redoableProperty()`

  - ### read

    public final void read(StyleResolver r, DataFormat f, InputStream input) throws IOException
    Replaces the content of the model with the data read from the input stream, using the specified `DataFormat`. This operation clears the undo/redo stack.
    Parameters:
      `r` - the style resolver
      `f` - the data format
      `input` - the input stream
    Throws:
      `IOException` - in case of an I/O error
      `UnsupportedOperationException` - when the data format is not supported by the model, or the model is not `writable`

  - ### write

    public final void write(StyleResolver r, DataFormat f, OutputStream out) throws IOException
    Writes the model content to the output stream using the specified `DataFormat`.
    Parameters:
      `r` - the style resolver
      `f` - the data format
      `out` - the output stream
    Throws:
      `IOException` - in case of an I/O error
      `UnsupportedOperationException` - when the data format is not supported by the model