Class TableData

java.lang.Object
swingtree.api.model.TableData

public final class TableData extends Object
An immutable value describing the entire contents of a table: its cells, the name and class of every column, the UI.CellOrder tying the two together, and whether the user may edit any of it. Hold one of these in a Var property, bind that property to a table, and you have a complete, thread safe, reactive table:

  Var<TableData> data = Var.of(
          TableData.of(UI.CellOrder.ROW_MAJOR, "Name", "Age")
              .addRow("Alice", 30)
              .addRow("Bob",   42)
      );

  UI.table(data);
  
Changing the table is then simply a matter of changing the value in the property, from wherever your business logic happens to live:

  data.update( it -> it.addRow("Carol", 55) );
  

It is a value

Every method on this class which sounds like it changes something really returns a new TableData, leaving the one you called it on untouched. Two tables with the same cell order, editability, columns and cells are equals(Object) to each other and have the same hashCode(), which is what lets a table tell whether anything actually changed.

Do not let the copying scare you: the cells live in immutable Tuples, which share their structure between versions. Adding a row to a thousand row table does not copy a thousand rows.

It is thread safe

Because this is a deeply immutable value, the application thread and the UI thread (the AWT Event Dispatch Thread) can hand it to each other without any locking. Under EventProcessor.DECOUPLED, the value in your property is what the UI thread reads, so every read within a single UI thread task sees the same consistent table, even while your application thread is busy building the next version of it.

It is cheap to update

A Tuple remembers how it was derived from its predecessor, and a UI.CellOrder.ROW_MAJOR table passes that knowledge straight to the JTable: adding, removing or changing a handful of rows only repaints those rows, rather than rebuilding the whole table. This is why a row major cell order is the right default for large, frequently changing tables.

Rows and columns, whatever the cell order

The cellOrder() decides how the cells() are stored: in a UI.CellOrder.ROW_MAJOR table the outer Tuple holds the rows and each inner Tuple holds the cells of one row, whereas in a UI.CellOrder.COLUMN_MAJOR table the outer Tuple holds the columns. That is a storage detail: every method on this class speaks in (row, column) terms no matter which cell order you picked, so addRow(Object...) adds a row to a column major table just as happily (it is merely a little more work for it).
  • Method Summary

    Modifier and Type
    Method
    Description
    addColumn(@Nullable String columnName, Class<?> columnClass, sprouts.Tuple<@Nullable Object> values)
    Appends a column to the right of this table, with a name, a class and its cells:
    addColumnAt(int columnIndex, @Nullable String columnName, Class<?> columnClass, sprouts.Tuple<@Nullable Object> values)
    Inserts a column at the given index, with a name, a class and its cells.
    addRow(@Nullable Object... values)
    Appends a row to the end of this table, built from plain values:
    addRow(sprouts.Tuple<@Nullable Object> row)
    Appends a row to the end of this table.
    addRowAt(int rowIndex, @Nullable Object... values)
    Inserts a row at the given index, built from plain values.
    addRowAt(int rowIndex, sprouts.Tuple<@Nullable Object> row)
    Inserts a row at the given index.
    addRows(sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
    Appends several rows at once, which is the efficient way to grow a table by more than one row: a row major table hands this to a JTable as a single insertion of a range of rows, rather than one event per row.
    addRowsAt(int rowIndex, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
    Inserts several rows at once, starting at the given index.
    Permits the user to edit the cells of this table, shorthand for withEditability(UI.Editability.EDITABLE).
    Forbids the user to edit the cells of this table, shorthand for withEditability(UI.Editability.READ_ONLY).
    The cell order deciding whether the cells() of this table are stored row by row or column by column.
    sprouts.Tuple<sprouts.Tuple<@Nullable Object>>
    The raw cell values of this table, in the order described by its cellOrder().
    sprouts.Tuple<Class<?>>
    The column classes of this table, which a JTable consults to pick a renderer and editor for each column.
    sprouts.Tuple<@Nullable String>
    The column names of this table, where a null entry means that the table falls back to the default (spreadsheet style) column name.
    Tells whether the user is allowed to edit the cells of this table.
    static TableData
    The shared empty table: no columns, no rows, not editable.
    boolean
     
    sprouts.Tuple<@Nullable Object>
    getColumn(int columnIndex)
    Reads an entire column, padded with null to the height of the table, so that the returned tuple always has exactly getRowCount() entries.
    getColumnClass(int columnIndex)
    Reads the class of a column, which a JTable consults to pick a renderer and an editor for it.
    int
    Returns the number of columns in this table.
    @Nullable String
    getColumnName(int columnIndex)
    Reads the name of a column.
    sprouts.Tuple<@Nullable Object>
    getRow(int rowIndex)
    Reads an entire row, padded with null to the width of the table, so that the returned tuple always has exactly getColumnCount() entries.
    int
    Returns the number of rows in this table.
    @Nullable Object
    getValueAt(int rowIndex, int columnIndex)
    Reads the value of a single cell, always in (row, column) terms, irrespective of the cellOrder() of this table.
    int
     
    int
    indexOfColumn(@Nullable String columnName)
    Looks up a column by name, so that your business logic may address columns by what they mean rather than by where they happen to sit:
    boolean
    Tells whether the user is allowed to edit the cells of this table.
    boolean
    Tells whether this table has nothing to show, meaning it has no rows, no columns, or neither.
    static TableData
    of(UI.CellOrder cellOrder, String... columnNames)
    Creates a table which has columns but no rows yet, which is how most tables start out in life:
    static TableData
    of(UI.CellOrder cellOrder, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
    Creates a table from nothing but its cells, whose dimensions are derived from them: the major axis of the cellOrder is as long as the outer Tuple, and the minor axis is as long as the longest inner Tuple (so a ragged matrix reads as though it were padded with null cells).
    static TableData
    of(UI.CellOrder cellOrder, UI.Editability editability, sprouts.Tuple<@Nullable String> columnNames, sprouts.Tuple<Class<?>> columnClasses, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
    Creates a fully described table, whose columns carry both a name and a class.
    Removes every row, while keeping the columns of this table exactly as they are.
    removeColumnAt(int columnIndex)
    Removes the column at the given index, along with its name and class.
    removeColumnsAt(int columnIndex, int count)
    Removes a whole range of columns at once, along with their names and classes.
    removeRowAt(int rowIndex)
    Removes the row at the given index.
    removeRowsAt(int rowIndex, int count)
    Removes a whole range of rows at once, which a row major table hands to a JTable as a single deletion of a range of rows.
    static sprouts.Tuple<@Nullable Object>
    row(@Nullable Object... values)
    Builds a single row (or column) out of plain values, which is handy when you want to hand a prepared row to addRow(Tuple) or setRowsAt(int, Tuple), or a prepared column to addColumn(String, Class, Tuple).
    setCellAt(int rowIndex, int columnIndex, @Nullable Object value)
    Produces a new table in which a single cell has a new value, reusing the immutable structure of this table for everything else.
    setCells(sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
    Replaces all of the cells of this table at once, keeping its cell order, editability and columns.
    setColumnAt(int columnIndex, sprouts.Tuple<@Nullable Object> values)
    Replaces the cells of the column at the given index, leaving its name and class alone.
    setColumnClassAt(int columnIndex, Class<?> columnClass)
    Changes the class of a single column, which is how you tell a JTable to render and edit it differently (a Boolean column becomes a column of check boxes, say).
    setColumnClasses(sprouts.Tuple<Class<?>> columnClasses)
    Changes the class of every column at once.
    setColumnNameAt(int columnIndex, @Nullable String columnName)
    Renames a single column, which a table picks up as a change of its header.
    setColumnNames(String... columnNames)
    Renames every column at once.
    setColumnNames(sprouts.Tuple<@Nullable String> columnNames)
    Renames every column at once.
    setRowAt(int rowIndex, @Nullable Object... values)
    Replaces the row at the given index, built from plain values.
    setRowAt(int rowIndex, sprouts.Tuple<@Nullable Object> row)
    Replaces the row at the given index.
    setRowsAt(int rowIndex, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
    Replaces a whole range of rows at once, starting at the given index, which a row major table hands to a JTable as a single update of a range of rows.
     
    Changes the cell order of this table, which is how you tell it to read the very same cells() along the other axis:
    Changes whether the user may edit this table, without touching a single cell and without any risk of disturbing how the cells are read:

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Method Details

    • empty

      public static TableData empty()
      The shared empty table: no columns, no rows, not editable. A good starting point for a table you are about to build up.
      Returns:
      An empty TableData.
    • of

      public static TableData of(UI.CellOrder cellOrder, String... columnNames)
      Creates a table which has columns but no rows yet, which is how most tables start out in life:
      
        TableData.of(UI.CellOrder.ROW_MAJOR, "Name", "Age", "City")
        
      The columns are all of type Object until you say otherwise through setColumnClassAt(int, Class), and the table is read only until you say otherwise through asEditable().
      Parameters:
      cellOrder - The UI.CellOrder deciding how the cells of the table are stored, see cellOrder().
      columnNames - The names of the columns, one per column.
      Returns:
      A new TableData with the given columns and no rows.
    • of

      public static TableData of(UI.CellOrder cellOrder, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
      Creates a table from nothing but its cells, whose dimensions are derived from them: the major axis of the cellOrder is as long as the outer Tuple, and the minor axis is as long as the longest inner Tuple (so a ragged matrix reads as though it were padded with null cells). The columns have no names, which makes a table fall back to the default (spreadsheet style) names, and they are all of type Object. The table is read only until you say otherwise through asEditable().
      Parameters:
      cellOrder - The UI.CellOrder describing how cells is to be interpreted.
      cells - The cell values, an immutable tuple of rows (or columns, see cellOrder), each of which is an immutable tuple of cell values.
      Returns:
      A new TableData.
    • of

      public static TableData of(UI.CellOrder cellOrder, UI.Editability editability, sprouts.Tuple<@Nullable String> columnNames, sprouts.Tuple<Class<?>> columnClasses, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
      Creates a fully described table, whose columns carry both a name and a class.

      Note that the dimensions of the table are derived from what you pass here, and that the column metadata takes part in that: a table with three column names but rows only two cells wide still has three columns, the last of which reads as null. This is what lets a table have columns but no rows.

      Parameters:
      cellOrder - The UI.CellOrder describing how cells is to be interpreted.
      editability - The UI.Editability deciding whether the user may edit the cells.
      columnNames - The column names, one per column, where null means "fall back to the default (spreadsheet style) name".
      columnClasses - The column classes, one per column, which a JTable consults to pick a renderer and an editor.
      cells - The cell values, an immutable tuple of rows (or columns, see cellOrder), each of which is an immutable tuple of cell values.
      Returns:
      A new TableData.
    • row

      public static sprouts.Tuple<@Nullable Object> row(@Nullable Object... values)
      Builds a single row (or column) out of plain values, which is handy when you want to hand a prepared row to addRow(Tuple) or setRowsAt(int, Tuple), or a prepared column to addColumn(String, Class, Tuple).
      Parameters:
      values - The cell values of the row.
      Returns:
      An immutable tuple of the given values.
    • cellOrder

      public UI.CellOrder cellOrder()
      The cell order deciding whether the cells() of this table are stored row by row or column by column.
      Returns:
      The UI.CellOrder of this table.
    • editability

      public UI.Editability editability()
      Tells whether the user is allowed to edit the cells of this table.
      Returns:
      The UI.Editability of this table.
    • isEditable

      public boolean isEditable()
      Tells whether the user is allowed to edit the cells of this table. Note that a table also needs to live in a mutable Var before an edit has anywhere to go.
      Returns:
      True if the editability() of this table permits cell editing.
    • getRowCount

      public int getRowCount()
      Returns the number of rows in this table. @return The row count.
    • getColumnCount

      public int getColumnCount()
      Returns the number of columns in this table. @return The column count.
    • isEmpty

      public boolean isEmpty()
      Tells whether this table has nothing to show, meaning it has no rows, no columns, or neither.
      Returns:
      True if this table has no cells to display.
    • getValueAt

      public @Nullable Object getValueAt(int rowIndex, int columnIndex)
      Reads the value of a single cell, always in (row, column) terms, irrespective of the cellOrder() of this table.
      Parameters:
      rowIndex - The row index of the cell.
      columnIndex - The column index of the cell.
      Returns:
      The value of the cell, or null if the indices are out of bounds.
    • getRow

      public sprouts.Tuple<@Nullable Object> getRow(int rowIndex)
      Reads an entire row, padded with null to the width of the table, so that the returned tuple always has exactly getColumnCount() entries.
      Parameters:
      rowIndex - The index of the row.
      Returns:
      The cells of the row, or an empty tuple if the index is out of bounds.
    • getColumn

      public sprouts.Tuple<@Nullable Object> getColumn(int columnIndex)
      Reads an entire column, padded with null to the height of the table, so that the returned tuple always has exactly getRowCount() entries.
      Parameters:
      columnIndex - The index of the column.
      Returns:
      The cells of the column, or an empty tuple if the index is out of bounds.
    • getColumnName

      public @Nullable String getColumnName(int columnIndex)
      Reads the name of a column.
      Parameters:
      columnIndex - The column index.
      Returns:
      The column name, or null if the column has no name of its own (in which case a table falls back to the default, spreadsheet style name).
    • getColumnClass

      public Class<?> getColumnClass(int columnIndex)
      Reads the class of a column, which a JTable consults to pick a renderer and an editor for it.
      Parameters:
      columnIndex - The column index.
      Returns:
      The column class, or Object if the column has no class of its own.
    • indexOfColumn

      public int indexOfColumn(@Nullable String columnName)
      Looks up a column by name, so that your business logic may address columns by what they mean rather than by where they happen to sit:
      
        data.setCellAt(0, data.indexOfColumn("Age"), 31);
        
      Parameters:
      columnName - The name of the column to look for.
      Returns:
      The index of the first column with the given name, or -1 if there is none.
    • cells

      public sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells()
      The raw cell values of this table, in the order described by its cellOrder(). This is exposed so that a table model can reuse the very same immutable structure without copying it, and so that you may reach for the full Tuple API when this class does not have the operation you need.
      Returns:
      The immutable tuple of rows (or columns, see cellOrder()).
    • columnNames

      public sprouts.Tuple<@Nullable String> columnNames()
      The column names of this table, where a null entry means that the table falls back to the default (spreadsheet style) column name.
      Returns:
      The immutable tuple of column names.
    • columnClasses

      public sprouts.Tuple<Class<?>> columnClasses()
      The column classes of this table, which a JTable consults to pick a renderer and editor for each column.
      Returns:
      The immutable tuple of column classes.
    • setCellAt

      public TableData setCellAt(int rowIndex, int columnIndex, @Nullable Object value)
      Produces a new table in which a single cell has a new value, reusing the immutable structure of this table for everything else.

      Note that this is a targeted change: a row major table hands it to a JTable as a single row update, so only that row repaints.

      Parameters:
      rowIndex - The row index of the cell to change.
      columnIndex - The column index of the cell to change.
      value - The new value of the cell.
      Returns:
      A new TableData with the changed cell, or this table unchanged if the indices are out of bounds or the cell already holds that value.
    • addRow

      public TableData addRow(@Nullable Object... values)
      Appends a row to the end of this table, built from plain values:
      
        data.addRow("Alice", 30, "Rome")
        
      Parameters:
      values - The cell values of the new row, one per column.
      Returns:
      A new TableData with the additional row.
    • addRow

      public TableData addRow(sprouts.Tuple<@Nullable Object> row)
      Appends a row to the end of this table.
      Parameters:
      row - The cells of the new row, one per column.
      Returns:
      A new TableData with the additional row.
    • addRowAt

      public TableData addRowAt(int rowIndex, @Nullable Object... values)
      Inserts a row at the given index, built from plain values.
      Parameters:
      rowIndex - The index the new row will have.
      values - The cell values of the new row, one per column.
      Returns:
      A new TableData with the additional row.
    • addRowAt

      public TableData addRowAt(int rowIndex, sprouts.Tuple<@Nullable Object> row)
      Inserts a row at the given index.
      Parameters:
      rowIndex - The index the new row will have.
      row - The cells of the new row, one per column.
      Returns:
      A new TableData with the additional row, or this table unchanged if the index is out of bounds.
    • addRows

      public TableData addRows(sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
      Appends several rows at once, which is the efficient way to grow a table by more than one row: a row major table hands this to a JTable as a single insertion of a range of rows, rather than one event per row.
      Parameters:
      rows - The new rows, each holding one cell value per column.
      Returns:
      A new TableData with the additional rows.
    • addRowsAt

      public TableData addRowsAt(int rowIndex, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
      Inserts several rows at once, starting at the given index. See addRows(Tuple) for why you should prefer this over adding the rows one at a time.
      Parameters:
      rowIndex - The index the first of the new rows will have.
      rows - The new rows, each holding one cell value per column.
      Returns:
      A new TableData with the additional rows, or this table unchanged if the index is out of bounds or there is nothing to add.
    • setRowAt

      public TableData setRowAt(int rowIndex, @Nullable Object... values)
      Replaces the row at the given index, built from plain values.
      Parameters:
      rowIndex - The index of the row to replace.
      values - The new cell values of the row, one per column.
      Returns:
      A new TableData with the replaced row.
    • setRowAt

      public TableData setRowAt(int rowIndex, sprouts.Tuple<@Nullable Object> row)
      Replaces the row at the given index.
      Parameters:
      rowIndex - The index of the row to replace.
      row - The new cells of the row, one per column.
      Returns:
      A new TableData with the replaced row, or this table unchanged if the index is out of bounds.
    • setRowsAt

      public TableData setRowsAt(int rowIndex, sprouts.Tuple<sprouts.Tuple<@Nullable Object>> rows)
      Replaces a whole range of rows at once, starting at the given index, which a row major table hands to a JTable as a single update of a range of rows. This is the operation you want when a batch of your data changed and you would rather not rebuild the whole table for it.
      Parameters:
      rowIndex - The index of the first row to replace.
      rows - The new rows, each holding one cell value per column.
      Returns:
      A new TableData with the replaced rows, or this table unchanged if the range is out of bounds or there is nothing to replace.
    • removeRowAt

      public TableData removeRowAt(int rowIndex)
      Removes the row at the given index.
      Parameters:
      rowIndex - The index of the row to remove.
      Returns:
      A new TableData without that row, or this table unchanged if the index is out of bounds.
    • removeRowsAt

      public TableData removeRowsAt(int rowIndex, int count)
      Removes a whole range of rows at once, which a row major table hands to a JTable as a single deletion of a range of rows.
      Parameters:
      rowIndex - The index of the first row to remove.
      count - The number of rows to remove.
      Returns:
      A new TableData without those rows, or this table unchanged if the range is out of bounds or there is nothing to remove.
    • removeAllRows

      public TableData removeAllRows()
      Removes every row, while keeping the columns of this table exactly as they are. Reach for empty() instead if you want to be rid of the columns too.
      Returns:
      A new TableData with the same columns but no rows.
    • addColumn

      public TableData addColumn(@Nullable String columnName, Class<?> columnClass, sprouts.Tuple<@Nullable Object> values)
      Appends a column to the right of this table, with a name, a class and its cells:
      
        data.addColumn("City", String.class, TableData.row("Rome", "Oslo"))
        
      Parameters:
      columnName - The name of the new column.
      columnClass - The class of the new column.
      values - The cells of the new column, one per row.
      Returns:
      A new TableData with the additional column.
    • addColumnAt

      public TableData addColumnAt(int columnIndex, @Nullable String columnName, Class<?> columnClass, sprouts.Tuple<@Nullable Object> values)
      Inserts a column at the given index, with a name, a class and its cells.
      Parameters:
      columnIndex - The index the new column will have.
      columnName - The name of the new column.
      columnClass - The class of the new column.
      values - The cells of the new column, one per row.
      Returns:
      A new TableData with the additional column, or this table unchanged if the index is out of bounds.
    • setColumnAt

      public TableData setColumnAt(int columnIndex, sprouts.Tuple<@Nullable Object> values)
      Replaces the cells of the column at the given index, leaving its name and class alone.
      Parameters:
      columnIndex - The index of the column to replace.
      values - The new cells of the column, one per row.
      Returns:
      A new TableData with the replaced column, or this table unchanged if the index is out of bounds.
    • removeColumnAt

      public TableData removeColumnAt(int columnIndex)
      Removes the column at the given index, along with its name and class.
      Parameters:
      columnIndex - The index of the column to remove.
      Returns:
      A new TableData without that column, or this table unchanged if the index is out of bounds.
    • removeColumnsAt

      public TableData removeColumnsAt(int columnIndex, int count)
      Removes a whole range of columns at once, along with their names and classes.
      Parameters:
      columnIndex - The index of the first column to remove.
      count - The number of columns to remove.
      Returns:
      A new TableData without those columns, or this table unchanged if the range is out of bounds or there is nothing to remove.
    • setColumnNameAt

      public TableData setColumnNameAt(int columnIndex, @Nullable String columnName)
      Renames a single column, which a table picks up as a change of its header.
      Parameters:
      columnIndex - The index of the column to rename.
      columnName - The new name of the column, where null means "fall back to the default (spreadsheet style) name".
      Returns:
      A new TableData with the renamed column, or this table unchanged if the index is out of bounds or the name did not change.
    • setColumnNames

      public TableData setColumnNames(String... columnNames)
      Renames every column at once.
      Parameters:
      columnNames - The new column names, one per column.
      Returns:
      A new TableData with the new column names.
    • setColumnNames

      public TableData setColumnNames(sprouts.Tuple<@Nullable String> columnNames)
      Renames every column at once. Note that the number of names takes part in deciding how many columns this table has, so handing over more names than the cells fill widens the table.
      Parameters:
      columnNames - The new column names, one per column.
      Returns:
      A new TableData with the new column names.
    • setColumnClassAt

      public TableData setColumnClassAt(int columnIndex, Class<?> columnClass)
      Changes the class of a single column, which is how you tell a JTable to render and edit it differently (a Boolean column becomes a column of check boxes, say).
      Parameters:
      columnIndex - The index of the column.
      columnClass - The new class of the column.
      Returns:
      A new TableData with the new column class, or this table unchanged if the index is out of bounds or the class did not change.
    • setColumnClasses

      public TableData setColumnClasses(sprouts.Tuple<Class<?>> columnClasses)
      Changes the class of every column at once.
      Parameters:
      columnClasses - The new column classes, one per column.
      Returns:
      A new TableData with the new column classes.
    • setCells

      public TableData setCells(sprouts.Tuple<sprouts.Tuple<@Nullable Object>> cells)
      Replaces all of the cells of this table at once, keeping its cell order, editability and columns.
      Parameters:
      cells - The new cell values, an immutable tuple of rows (or columns, see cellOrder()).
      Returns:
      A new TableData with the new cells.
    • withCellOrder

      public TableData withCellOrder(UI.CellOrder cellOrder)
      Changes the cell order of this table, which is how you tell it to read the very same cells() along the other axis:
      
        data.withCellOrder(UI.CellOrder.COLUMN_MAJOR)
        
      Careful: this reinterprets the cells rather than rearranging them, so a table whose cells stay put comes out transposed. Use it when you know the cells were the other way around all along, not to flip a table on screen.
      Parameters:
      cellOrder - The new UI.CellOrder of this table.
      Returns:
      A new TableData with the given cell order, or this table unchanged if it already has it.
    • withEditability

      public TableData withEditability(UI.Editability editability)
      Changes whether the user may edit this table, without touching a single cell and without any risk of disturbing how the cells are read:
      
        data.withEditability(UI.Editability.EDITABLE)
        
      Note that an editable table also has to live in a mutable Var before an edit has anywhere to go.
      Parameters:
      editability - The new UI.Editability of this table.
      Returns:
      A new TableData with the given editability, or this table unchanged if it already has it.
    • asEditable

      public TableData asEditable()
      Permits the user to edit the cells of this table, shorthand for withEditability(UI.Editability.EDITABLE).
      Returns:
      A new editable TableData, or this table unchanged if it already is.
    • asReadOnly

      public TableData asReadOnly()
      Forbids the user to edit the cells of this table, shorthand for withEditability(UI.Editability.READ_ONLY).
      Returns:
      A new read only TableData, or this table unchanged if it already is.
    • equals

      public boolean equals(Object obj)
      Overrides:
      equals in class Object
    • hashCode

      public int hashCode()
      Overrides:
      hashCode in class Object
    • toString

      public String toString()
      Overrides:
      toString in class Object