1. FilterTableModel

filter table model diagram

The FilterTableModel is a table model central to the framework.

// Define a record representing the table rows
public record Person(String name, int age) {

  // Constants identifying the table columns
  public static final String NAME = "Name";
  public static final String AGE = "Age";
}
// Implement TableColumns, which specifies the column identifiers,
// the column class and how to extract column values from row objects
public static final class PersonColumns implements TableColumns<Person, String> {

  private static final List<String> COLUMNS = List.of(NAME, AGE);

  @Override
  public List<String> identifiers() {
    return COLUMNS;
  }

  @Override
  public Class<?> columnClass(String column) {
    return switch (column) {
      case NAME -> String.class;
      case AGE -> Integer.class;
      default -> throw new IllegalArgumentException();
    };
  }

  @Override
  public Object value(Person person, String column) {
    return switch (column) {
      case NAME -> person.name();
      case AGE -> person.age();
      default -> throw new IllegalArgumentException();
    };
  }
}
// Implement a Editor for handling row edits
private static final class PersonEditor implements Editor<Person, String> {

  // We need the underlying VisibleItems instance to replace the edited
  // row since the row objects are records and thereby immutable
  private final VisibleItems<Person> items;

  private PersonEditor(FilterTableModel<Person, String> tableModel) {
    this.items = tableModel.items().visible();
  }

  @Override
  public boolean editable(Person person, String identifier) {
    // Both columns editable
    return true;
  }

  @Override
  public void set(Object value, int rowIndex, Person person, String identifier) {
    switch (identifier) {
      case NAME -> items.set(rowIndex, new Person((String) value, person.age()));
      case AGE -> items.set(rowIndex, new Person(person.name(), (Integer) value));
    }
  }
}
// Implement an item supplier responsible for supplying
// the data when the table items are refreshed.
// Without one the model can be populated by adding items manually
Supplier<Collection<Person>> supplier = () -> List.of(
        new Person("John", 42),
        new Person("Mary", 43),
        new Person("Andy", 33),
        new Person("Joan", 37));

// Build the table model, providing the TableColumns
// implementation along with the item supplier and row editor.
FilterTableModel<Person, String> tableModel =
        FilterTableModel.builder()
                .columns(new PersonColumns())
                .supplier(supplier)
                .editor(PersonEditor::new)
                .build();

// Populate the model
tableModel.items().refresh();

1.1. Selection

FilterListSelection<Person> selection = tableModel.selection();

// Print the selected items when they change
selection.items().addConsumer(System.out::println);

// Print a message when the minimum selected index changes
selection.index().addListener(() ->
        System.out.println("Selected index changed"));

// Select the first row
selection.index().set(0);

// Select the first two rows
selection.indexes().set(List.of(0, 1));

// Fetch the selected items
List<Person> items = selection.items().get();

// Or just the first (minimum index)
Person item = selection.item().get();

// Select a specific person
selection.item().set(new Person("John", 42));

// Select all persons over 40
selection.items().set(person -> person.age() > 40);

// Increment all selected indexes by
// one, moving the selection down
selection.indexes().increment();

// Clear the selection
selection.clear();

1.2. Filters

TableConditionModel<String> filters = tableModel.filters();

// Filter out people under 40 years old
ConditionModel<Integer> ageFilter = filters.get(Person.AGE);

ageFilter.set().greaterThanOrEqualTo(40);
// Not necessary since filters auto-enable by default
// when operators and operands are specified
ageFilter.enabled().set(true);

// Filter is automatically disabled when it is cleared
ageFilter.clear();

// Filter out anyone besides John and Joan
ConditionModel<String> nameFilter = filters.get(NAME);

nameFilter.caseSensitive().set(false);
nameFilter.set().equalTo("jo%");

// Clear all filters
filters.clear();

1.3. Sorting

FilterTableSort<Person, String> sort = tableModel.sort();

// Sort by age and name, ascending
sort.ascending(AGE, NAME);

// Sort by age, descending,
// set() clears the previous sort
sort.order(AGE).set(DESCENDING);
// add sorting by name, ascending,
// add() adds to any previous sort
sort.order(NAME).add(ASCENDING);

// Clear the sorting
sort.clear();