package com.insightfullogic.honest_profiler.ports.javafx.controller.filter; import static com.insightfullogic.honest_profiler.ports.javafx.util.FxUtil.refreshTable; import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.INFO_BUTTON_ADDFILTER; import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.INFO_BUTTON_REMOVEFILTER; import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.INFO_CHECK_HIDEERRORTHREADS; import static com.insightfullogic.honest_profiler.ports.javafx.util.ResourceUtil.INFO_LIST_FILTERS; import static com.insightfullogic.honest_profiler.ports.javafx.view.Icon.MINUS_16; import static com.insightfullogic.honest_profiler.ports.javafx.view.Icon.PLUS_16; import static com.insightfullogic.honest_profiler.ports.javafx.view.Icon.viewFor; import static java.util.stream.Collectors.toList; import static javafx.scene.layout.Border.EMPTY; import java.util.List; import java.util.function.Function; import com.insightfullogic.honest_profiler.core.aggregation.filter.Comparison; import com.insightfullogic.honest_profiler.core.aggregation.filter.FilterItem; import com.insightfullogic.honest_profiler.core.aggregation.filter.FilterSpecification; import com.insightfullogic.honest_profiler.core.aggregation.filter.Target; import com.insightfullogic.honest_profiler.core.aggregation.result.ItemType; import com.insightfullogic.honest_profiler.ports.javafx.controller.dialog.AbstractDialogController; import com.insightfullogic.honest_profiler.ports.javafx.model.ApplicationContext; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.CheckBox; import javafx.scene.control.Dialog; import javafx.scene.control.DialogPane; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.util.Callback; public class FilterDialogController<T> extends AbstractDialogController<FilterSpecification<T>> { @FXML private Dialog<FilterSpecification<T>> dialog; @FXML private DialogPane dialogPane; @FXML private CheckBox hideErrorThreads; @FXML private TableView<FilterItem<T, ?>> filters; @FXML private TableColumn<FilterItem<T, ?>, FilterItem<T, ?>> action; @FXML private TableColumn<FilterItem<T, ?>, Target> target; @FXML private TableColumn<FilterItem<T, ?>, Comparison> comparison; @FXML private TableColumn<FilterItem<T, ?>, Object> value; @FXML private FilterCreationDialogController<T> filterCreationController; private ItemType type; @Override @FXML public void initialize() { super.initialize(dialog); action.setCellFactory(column -> new ActionCell<>()); action.setCellValueFactory(data -> new ReadOnlyObjectWrapper<>(data.getValue())); target.setCellFactory( column -> new FilterCell<>((Target type) -> type.toString())); target.setCellValueFactory( data -> new ReadOnlyObjectWrapper<>( data.getValue() == null ? null : data.getValue().getTarget())); comparison.setCellFactory( column -> new FilterCell<>((Comparison type) -> type.toString())); comparison.setCellValueFactory( data -> new ReadOnlyObjectWrapper<>( data.getValue() == null ? null : data.getValue().getComparison())); value.setCellFactory( column -> new FilterCell<>(object -> object.toString())); value.setCellValueFactory( data -> new ReadOnlyObjectWrapper<>( data.getValue() == null ? null : data.getValue().getValue())); // The NULL item is always in the last row, and is used to figure out // where to put the "Add // Filter" (plus) button filters.getItems().add(null); } @Override public void setApplicationContext(ApplicationContext applicationContext) { super.setApplicationContext(applicationContext); filterCreationController.setApplicationContext(applicationContext); } public void setItemType(ItemType type) { this.type = type; filterCreationController.setItemType(type); } @Override public void reset() { // NOOP } @Override public Callback<ButtonType, FilterSpecification<T>> createResultHandler() { return buttonType -> new FilterSpecification<T>( type, hideErrorThreads.isSelected(), filters.getItems().stream().filter(item -> item != null).collect(toList())); } private void addFilter() { List<FilterItem<T, ?>> items = filters.getItems(); filterCreationController.showAndWait().ifPresent(item -> items.add(items.size() - 1, item)); refreshTable(filters); } private void removeFilter(FilterItem<T, ?> item) { filters.getItems().remove(item); refreshTable(filters); } private Button createActionButton(FilterItem<T, ?> item) { Button button = new Button(); button.borderProperty().set(EMPTY); button.setMinSize(16, 16); button.setPrefSize(16, 16); button.setMaxSize(16, 16); button.setGraphic(viewFor(item == null ? PLUS_16 : MINUS_16)); button.setOnAction(item == null ? event -> addFilter() : event -> removeFilter(item)); return button; } // AbstractController Implementation @Override protected void initializeInfoText() { info(hideErrorThreads, INFO_CHECK_HIDEERRORTHREADS); info(filters, INFO_LIST_FILTERS); } @Override protected void initializeHandlers() { // } // Helper Classes private class ActionCell<U> extends TableCell<FilterItem<T, ?>, FilterItem<T, ?>> { @Override protected void updateItem(FilterItem<T, ?> item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); return; } setGraphic(createActionButton(item)); info( super.getGraphic(), item == null ? INFO_BUTTON_ADDFILTER : INFO_BUTTON_REMOVEFILTER); } } private class FilterCell<U, V> extends TableCell<FilterItem<U, ?>, V> { private Function<V, String> displayFunction; public FilterCell(Function<V, String> displayFunction) { this.displayFunction = displayFunction; } @Override protected void updateItem(V type, boolean empty) { super.updateItem(type, empty); if (empty || type == null) { setText(null); return; } setText(this.displayFunction.apply(type)); } } }