Filter In Javafx

package com.ibadmin.control.tablefilter;

import java.util.Optional;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.scene.control.CheckBox;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;


/**
 * Applies a filtering control to a provided {@link TableView} instance. The filter will be applied immediately on construction, and can be
 * made visible by right-clicking the desired column to filter on. <br>
 * <br>
 * <b>Features</b><br>
 * -Convenient filter control holds a checklist of distinct items to include/exclude, much like an Excel filter.<br>
 * -New/removed records will be captured by the filter control and reflect new or removed values from checklist. -Filters on more than one
 * column are combined to only display mutually inclusive records on the client's TableView.
 *
 * @param <T>
 */
public final class TableFilter<T> {

  private final TableView<T> tableView;

  /**
   * TODO Please rename this to some understandable name!!!
   */
  private final ObservableList<T> backingList;
  private final FilteredList<T> filteredList;
  private final SortedList<T> sortedControlList;
  private boolean parentSearchEnable = false;
  BooleanProperty clearButtonDisabledProperty = new SimpleBooleanProperty(true);

  private final ObservableList<ColumnFilter<T, ?>> columnFilters = FXCollections.observableArrayList();

  /**
   * Constructor applies a filtering control to the provided {@link TableView} instance.
   *
   * @param tableView
   */
  public TableFilter(TableView<T> tableView, ObservableList<T> sourceList) {
    this.tableView = tableView;

    // sourceList passed here is the FilteredList from the Repository Controller. FilteredList has its source as the originalReferenceList
    backingList = sourceList;
    filteredList = new FilteredList<>(backingList);
    sortedControlList = new SortedList<>(filteredList);

    // initially display full list without filters
    filteredList.setPredicate(v -> true);

    sortedControlList.comparatorProperty().bind(tableView.comparatorProperty());
    tableView.setItems(sortedControlList);

    applyForAllColumns();
    columnFilters.forEach(ColumnFilter::initialize);
  }

  /**
   * Allows specifying a different behavior for the search box on the TableFilter. By default, the contains() method on a String is used to
   * evaluate the search box input to qualify the distinct filter values. But you can specify a different behavior by providing a simple
   * BiPredicate argument to this method. The BiPredicate argument allows you take the input value and target value and use a lambda to
   * evaluate a boolean. For instance, you can implement a comparison by assuming the input value is a regular expression, and call
   * matches() on the target value to see if it aligns to the pattern.
   *
   * @param searchStrategy
   */
  public void setSearchStrategy(BiPredicate<String, String> searchStrategy) {
    columnFilters.forEach(cf -> cf.setSearchStrategy(searchStrategy));
  }

  /**
   * Returns the backing {@link ObservableList} originally provided to the constructor.
   *
   * @return ObservableList
   */
  public ObservableList<T> getBackingList() {
    return backingList;
  }

  /**
   * Returns the {@link FilteredList} used by this TableFilter and is backing the {@link TableView}.
   *
   * @return FilteredList
   */
  public FilteredList<T> getFilteredList() {
    return filteredList;
  }

  /**
   * @treatAsPrivate
   */
  private void applyForAllColumns() {
    columnFilters.setAll(this.tableView.getColumns().stream().map(c -> new ColumnFilter<>(this, c)).collect(Collectors.toList()));
  }

  public void executeFilter() {
    if (columnFilters.stream().filter(ColumnFilter::isFiltered).findAny().isPresent()) {
      filteredList.setPredicate(item -> !columnFilters.stream().filter(cf -> !cf.evaluate(item)).findAny().isPresent());
      clearButtonDisabledProperty.setValue(filteredList.equals(backingList));
    } else {
      resetFilter();
    }
  }

  public void resetFilter() {
    filteredList.setPredicate(item -> true);
  }

  /**
   * @treatAsPrivate
   */
  public TableView<T> getTableView() {
    return tableView;
  }

  /**
   * @treatAsPrivate
   */
  public ObservableList<ColumnFilter<T, ?>> getColumnFilters() {
    return columnFilters;
  }

  /**
   * @treatAsPrivate
   */
  public Optional<ColumnFilter<T, ?>> getColumnFilter(TableColumn<T, ?> tableColumn) {
    return columnFilters.stream().filter(f -> f.getTableColumn().equals(tableColumn)).findAny();
  }

  public boolean isDirty() {
    return columnFilters.stream().filter(ColumnFilter::isFiltered).findAny().isPresent();
  }

  public boolean containsIgnoreCase(final String str, final String searchStr) {
    if (str == null || searchStr == null) {
      return false;
    }
    final int len = searchStr.length();
    final int max = str.length() - len;
    for (int i = 0; i <= max; i++) {
      if (str.regionMatches(true, i, searchStr, 0, len)) {
        return true;
      }
    }
    return false;
  }

  public void clearAllFilters() {
    columnFilters.stream().forEach(cf -> cf.resetAllFilters());
    columnFilters.stream().forEach(cf -> {
      if (!(cf.getTableColumn().getGraphic() != null && cf.getTableColumn().getGraphic() instanceof CheckBox))
        cf.getTableColumn().setGraphic(null);
    });
    clearButtonDisabledProperty.setValue(true);
  }

  public boolean isParentSearchEnable() {
    return parentSearchEnable;
  }

  public void setParentSearchEnable(boolean parentSearchEnable) {
    this.parentSearchEnable = parentSearchEnable;
  }
  //DEV-5207 New IBAdmin:Issues in Search in Repo UI in New Admin
  public BooleanProperty getClearButtonDisabledProperty() {
    return clearButtonDisabledProperty;
  }
  // DEV-5207 END
}

USE :
 Platform.runLater(new Runnable() {
      @Override
      public void run() {
        repositoryTableFilter = new TableFilter<GenerationForRepoProperty>(repositoryTableView, filteredGenerationForRepoList);
        clearAllFiltersButton.disableProperty().bind(repositoryTableFilter.getClearButtonDisabledProperty());
        repositoryTableFilter.setSearchStrategy((input, target) -> {
          try {
            return repositoryTableFilter.containsIgnoreCase(target, input);
          } catch (Exception e) {
            return false;
          }
        });
      }
    });

Comments

Popular posts from this blog

Filter In Javafx

Kotlin with StandAlone Complier