Module org.apache.sis.util
Package org.apache.sis.util.collection

# Class TreeTableFormat

Object
Format
CompoundFormat<TreeTable>
TabularFormat<TreeTable>
TreeTableFormat

All Implemented Interfaces:
  `Serializable`, `Cloneable`, `Localized`

public class TreeTableFormat extends TabularFormat<TreeTable>
A parser and formatter for `TreeTable` instances. This formatter is given an arbitrary number of `TableColumn`s to use during the formatting. The first column is taken as the node label. If a `TreeTable` is formatted with only that column, then the `String` result is like the following example:

       Node #1
         ├─Node #2
         │   └─Node #4
         └─Node #3

If the same `TreeTable` is formatted with two columns, then the `String` result is like the following example:

       Node #1……………………… More #1
         ├─Node #2…………… More #2
         │   └─Node #4… More #4
         └─Node #3…………… More #3

This representation can be printed to the console output (for example) if the stream uses a monospaced font and supports Unicode characters.

## Customization

Some formatting characteristics (indentation width, column where to draw the vertical line below nodes) can be modified by calls to the setter methods defined in this formatter. In particular, the dots joining the node labels to their values can be specified by the column separator pattern. The default pattern is `"?……[…] "`, which means "If the next value is non-null, then insert the `"……"` string, repeat the `'…'` character as many time as needed (may be zero), and finally insert a space".

## Safety against infinite recursivity

Some `TreeTable` implementations generate the nodes dynamically as wrappers around Java objects. Such Java objects may contain cyclic associations (A contains B contains C contains A), which result in a tree of infinite depth. Some examples can be found in ISO 19115 metadata. This `TreeTableFormat` class contains a safety against such cycles. The algorithm is based on the assumption that for each node, the values and children are fully determined by the user object, if non-null. Consequently, for each node C to be formatted, if the user object of that node is the same instance (in the sense of the `==` operator) than the user object of a parent node A, then the children of the C node will not be formatted.

Since:
  0.3
See Also:
  - Serialized Form

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from class Format

  `Format​.Field`

- ## Field Summary

  ### Fields inherited from class TabularFormat

  `beforeFill, columnSeparator, fillCharacter, lineSeparator, omitTrailingNulls`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `TreeTableFormat(Locale locale, TimeZone timezone)`
  Creates a new tree table format.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `TreeTableFormat`
  `clone()`
  Returns a clone of this format.
  `protected Format`
  `createFormat(Class<?> valueType)`
  Creates a new format to use for parsing and formatting values of the given type.
  `void`
  `format(TreeTable tree, Appendable toAppendTo)`
  Writes a graphical representation of the specified tree table in the given stream or buffer.
  `TableColumn<?>[]`
  `getColumns()`
  Returns the table columns to parse and format, or `null` for the default list of columns.
  `int`
  `getIndentation()`
  Returns the number of spaces to add on the left margin for each indentation level.
  `Predicate<TreeTable​.Node>`
  `getNodeFilter()`
  Returns the filter that specify whether a node should be formatted or ignored.
  `final Class<TreeTable>`
  `getValueType()`
  Returns the type of objects formatted by this class.
  `int`
  `getVerticalLinePosition()`
  Returns the position of the vertical line, relative to the position of the root label.
  `TreeTable`
  `parse(CharSequence text, ParsePosition pos)`
  Creates a tree from the given character sequence, or returns `null` if the given text does not look like a tree for this method.
  `void`
  `setColumns(TableColumn<?>... columns)`
  Sets the table columns to parse and format.
  `void`
  `setIndentation(int indentation)`
  Sets the number of spaces to add on the left margin for each indentation level.
  `void`
  `setNodeFilter(Predicate<TreeTable​.Node> filter)`
  Sets a filter specifying whether a node should be formatted or ignored.
  `void`
  `setVerticalLinePosition(int verticalLinePosition)`
  Sets the position of the vertical line, relative to the position of the root label.
  `protected void`
  `writeColumnSeparator(int nextColumn, TableAppender out)`
  Writes characters between columns.

  ### Methods inherited from class TabularFormat

  `getColumnSeparatorMatcher, getColumnSeparatorPattern, getLineSeparator, setColumnSeparatorPattern, setLineSeparator`

  ### Methods inherited from class CompoundFormat

  `format, getFormat, getLocale, getLocale, getTimeZone, parseObject, parseObject`

  ### Methods inherited from class Format

  `format, formatToCharacterIterator`

  ### Methods inherited from class Object

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

- ## Constructor Details

  - ### TreeTableFormat

    public TreeTableFormat(Locale locale, TimeZone timezone)
    Creates a new tree table format.
    Parameters:
      `locale` - the locale to use for numbers, dates and angles formatting, or `null` for the root locale.
      `timezone` - the timezone, or `null` for UTC.

- ## Method Details

  - ### getValueType

    public final Class<TreeTable> getValueType()
    Returns the type of objects formatted by this class.
    Specified by:
      `getValueType` in class `CompoundFormat<TreeTable>`
    Returns:
      `TreeTable​.class`

  - ### getColumns

    public TableColumn<?>[] getColumns()
    Returns the table columns to parse and format, or `null` for the default list of columns. The default is:
    - On parsing, a single column containing the node label as a `String`.
    - On formatting, all `TreeTable` columns.
    Returns:
      the table columns to parse and format, or `null` for the default.

  - ### setColumns

    public void setColumns(TableColumn<?>... columns) throws IllegalArgumentException
    Sets the table columns to parse and format. A `null` value means to use the default list of columns, as defined in the `getColumns()` method.
    Parameters:
      `columns` - the table columns to parse and format, or `null` for the default.
    Throws:
      `IllegalArgumentException` - if the given array is empty, contains a null element or a duplicated value.

  - ### getIndentation

    public int getIndentation()
    Returns the number of spaces to add on the left margin for each indentation level. The default value is 4.
    Returns:
      the current indentation.

  - ### setIndentation

    public void setIndentation(int indentation) throws IllegalArgumentException
    Sets the number of spaces to add on the left margin for each indentation level. If the new indentation is smaller than the vertical line position, then the latter is also set to the given indentation value.
    Parameters:
      `indentation` - the new indentation.
    Throws:
      `IllegalArgumentException` - if the given value is negative.

  - ### getVerticalLinePosition

    public int getVerticalLinePosition()
    Returns the position of the vertical line, relative to the position of the root label. The default value is 2, which means that the vertical line is drawn below the third letter of the root label.
    Returns:
      the current vertical line position.

  - ### setVerticalLinePosition

    public void setVerticalLinePosition(int verticalLinePosition) throws IllegalArgumentException
    Sets the position of the vertical line, relative to the position of the root label. The given value cannot be greater than the indentation.
    Parameters:
      `verticalLinePosition` - the new vertical line position.
    Throws:
      `IllegalArgumentException` - if the given value is negative or greater than the indentation.

  - ### getNodeFilter

    public Predicate<TreeTable.Node> getNodeFilter()
    Returns the filter that specify whether a node should be formatted or ignored. This is the predicate specified in the last call to `setNodeFilter(Predicate)`. If no filter has been set, then this method returns `null`.
    Returns:
      a filter for specifying whether a node should be formatted, or `null` if no filtering is applied.
    Since:
      1.0

  - ### setNodeFilter

    public void setNodeFilter(Predicate<TreeTable.Node> filter)
    Sets a filter specifying whether a node should be formatted or ignored. Filters are tested at formatting time for all children of the root node (but not for the root node itself). Filters are ignored at parsing time.
    Parameters:
      `filter` - filter for specifying whether a node should be formatted, or `null` for no filtering.
    Since:
      1.0

  - ### parse

    public TreeTable parse(CharSequence text, ParsePosition pos) throws ParseException
    Creates a tree from the given character sequence, or returns `null` if the given text does not look like a tree for this method. This method can parse the trees created by the `format(…)` methods defined in this class.

    #### Parsing rules

    - Each node shall be represented by a single line made of two parts, in that order:
      1. white spaces and tree drawing characters (`'│'`, `'├'`, `'└'` or `'─'`);
      2. string representations of node values, separated by the colunm separator.
    - The number of spaces and drawing characters before the node values determines the node indentation. This indentation does not need to be a factor of the `getIndentation()` value, but must be consistent across all the parsed tree.
    - The indentation determines the parent of each node.
    - Parsing stops at first empty line (ignoring whitespaces), or at the end of the given text.

    #### Error index

    If the given text does not seem to be a tree table, then this method returns `null`. Otherwise if parsing started but failed, then:
    - `ParsePosition​.getErrorIndex()` will give the index at the beginning of line or beginning of cell where the error occurred, and
    - `ParseException​.getErrorOffset()` will give either the same value, or a slightly more accurate value inside the cell.
    Specified by:
      `parse` in class `CompoundFormat<TreeTable>`
    Parameters:
      `text` - the character sequence for the tree to parse.
      `pos` - the position where to start the parsing.
    Returns:
      the parsed tree, or `null` if the given character sequence cannot be parsed.
    Throws:
      `ParseException` - if an error occurred while parsing a node value.

  - ### format

    public void format(TreeTable tree, Appendable toAppendTo) throws IOException
    Writes a graphical representation of the specified tree table in the given stream or buffer. This method iterates recursively over all children. For each column to format in each node, this method gets a textual representation of the value in that column using the formatter obtained by a call to `CompoundFormat​.getFormat(Class)`.
    Specified by:
      `format` in class `CompoundFormat<TreeTable>`
    Parameters:
      `tree` - the tree to format.
      `toAppendTo` - where to format the tree.
    Throws:
      `IOException` - if an error occurred while writing to the given appendable.
    See Also:
      - `TreeTables​.toString(TreeTable)`

  - ### createFormat

    protected Format createFormat(Class<?> valueType)
    Creates a new format to use for parsing and formatting values of the given type. This method is invoked the first time that a format is needed for the given type. Subclasses can override this method if they want to configure the way dates, numbers or other objects are formatted. See parent class documentation for more information.

    The implementation in `TreeTableFormat` differs from the default implementation in the following aspects:

    - `UnitFormat` uses `UnitFormat​.Style​.NAME`.
    Overrides:
      `createFormat` in class `CompoundFormat<TreeTable>`
    Parameters:
      `valueType` - the base type of values to parse or format.
    Returns:
      the format to use for parsing of formatting values of the given type, or `null` if none.

  - ### writeColumnSeparator

    protected void writeColumnSeparator(int nextColumn, TableAppender out)
    Writes characters between columns. The default implementation applies the configuration specified by `TabularFormat​.setColumnSeparatorPattern(String)` as below:

    > `out​.append(beforeFill); out​.nextColumn(fillCharacter); out​.append(columnSeparator);`

    The output with default values is like below:

           root
             └─column0…… column1…… column2…… column3

    Subclasses can override this method if different column separators are desired. Note however that doing so may prevent the `parse(…)` method to work.
    Parameters:
      `nextColumn` - zero-based index of the column to be written after the separator.
      `out` - where to write the column separator.
    Since:
      1.0
    See Also:
      - `TableAppender​.nextColumn(char)`

  - ### clone

    public TreeTableFormat clone()
    Returns a clone of this format.
    Overrides:
      `clone` in class `TabularFormat<TreeTable>`
    Returns:
      a clone of this format.