Replace result table by result list

This commit is contained in:
Armin Schrenk
2021-05-21 12:00:46 +02:00
parent a8364a8c1a
commit 1abf0e1bfa
9 changed files with 191 additions and 122 deletions

View File

@@ -2,21 +2,17 @@ package org.cryptomator.ui.health;
import com.tobiasdiez.easybind.EasyBind;
import com.tobiasdiez.easybind.optional.OptionalBinding;
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.ListView;
public class CheckDetailController implements FxController {
@@ -24,19 +20,18 @@ public class CheckDetailController implements FxController {
private final OptionalBinding<Worker.State> taskState;
private final Binding<String> taskName;
private final Binding<String> taskDescription;
private final ResultListCellFactory resultListCellFactory;
private final BooleanBinding producingResults;
public TableView<DiagnosticResultAction> resultsTableView;
public TableColumn<DiagnosticResultAction, String> resultDescriptionColumn;
public TableColumn<DiagnosticResultAction, DiagnosticResult.Severity> resultSeverityColumn;
public TableColumn<DiagnosticResultAction, Runnable> resultActionColumn;
public ListView<DiagnosticResultAction> resultsListView;
@Inject
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask) {
public CheckDetailController(ObjectProperty<HealthCheckTask> selectedTask, ResultListCellFactory resultListCellFactory) {
this.results = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::results).orElse(FXCollections.emptyObservableList());
this.taskState = EasyBind.wrapNullable(selectedTask).mapObservable(HealthCheckTask::stateProperty);
this.taskName = EasyBind.wrapNullable(selectedTask).map(HealthCheckTask::getTitle).orElse("");
this.taskDescription = EasyBind.wrapNullable(selectedTask).map(task -> task.getCheck().toString()).orElse("");
this.resultListCellFactory = resultListCellFactory;
this.producingResults = taskState.filter(this::producesResults).isPresent();
}
@@ -49,12 +44,8 @@ public class CheckDetailController implements FxController {
@FXML
public void initialize() {
resultsTableView.itemsProperty().bind(results);
resultDescriptionColumn.setCellValueFactory(cellFeatures -> new SimpleStringProperty(cellFeatures.getValue().getDescription()));
resultSeverityColumn.setCellValueFactory(cellFeatures -> new SimpleObjectProperty<>(cellFeatures.getValue().getSeverity()));
resultSeverityColumn.setCellFactory(column -> new ResultSeverityTableCell());
resultActionColumn.setCellValueFactory(cellFeatures -> new SimpleObjectProperty<>(cellFeatures.getValue()));
resultActionColumn.setCellFactory(column -> new ResultActionTableCell());
resultsListView.itemsProperty().bind(results);
resultsListView.setCellFactory(resultListCellFactory);
}
/* Getter/Setter */

View File

@@ -134,5 +134,9 @@ abstract class HealthCheckModule {
@FxControllerKey(CheckDetailController.class)
abstract FxController bindCheckDetailController(CheckDetailController controller);
@Binds
@IntoMap
@FxControllerKey(ResultListCellController.class)
abstract FxController bindResultListCellController(ResultListCellController controller);
}

View File

@@ -1,30 +0,0 @@
package org.cryptomator.ui.health;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
class ResultActionTableCell extends TableCell<DiagnosticResultAction, Runnable> {
private Button button;
ResultActionTableCell() {
button = new Button();
setGraphic(null);
}
@Override
protected void updateItem(Runnable item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setGraphic(button);
button.setOnAction(event -> item.run());
button.setText("FIXME"); //FIXME
button.setAlignment(Pos.CENTER);
}
}
}

View File

@@ -1,19 +0,0 @@
package org.cryptomator.ui.health;
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
import org.cryptomator.cryptofs.health.api.HealthCheck;
import javafx.scene.control.ListCell;
class ResultListCell extends ListCell<DiagnosticResult> {
@Override
protected void updateItem(DiagnosticResult item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.toString());
} else {
setText(null);
}
}
}

View File

@@ -0,0 +1,93 @@
package org.cryptomator.ui.health;
import com.tobiasdiez.easybind.EasyBind;
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
public class ResultListCellController implements FxController {
private final ObjectProperty<DiagnosticResultAction> result;
private final Binding<Boolean> fixButtonVisible;
private final Binding<String> description;
@FXML
public FontAwesome5IconView iconView;
@Inject
public ResultListCellController() {
this.result = new SimpleObjectProperty<>(null);
this.fixButtonVisible = EasyBind.wrapNullable(result) //
.map(val -> val.getSeverity() == DiagnosticResult.Severity.WARN).orElse(true); //
this.description = EasyBind.wrapNullable(result).map(DiagnosticResultAction::getDescription).orElse("");
result.addListener(this::getGlyphForSeverity);
}
private void getGlyphForSeverity(ObservableValue<? extends DiagnosticResultAction> observable, DiagnosticResultAction oldVal, DiagnosticResultAction newVal) {
iconView.getStyleClass().clear();
switch (newVal.getSeverity()) {
case INFO -> {
iconView.setGlyph(FontAwesome5Icon.INFO_CIRCLE);
iconView.getStyleClass().add("glyph-icon-muted");
}
case GOOD -> {
iconView.setGlyph(FontAwesome5Icon.CHECK);
iconView.getStyleClass().add("glyph-icon-primary");
}
case WARN -> {
iconView.setGlyph(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
iconView.getStyleClass().add("glyph-icon-orange");
}
case CRITICAL -> {
iconView.setGlyph(FontAwesome5Icon.TIMES);
iconView.getStyleClass().add("glyph-icon-red");
}
}
}
@FXML
public void runResultAction() {
final var realResult = result.get();
if (realResult != null) {
realResult.run(); //TODO: this hogs currently the JAVAFX thread
}
}
/* Getter & Setter */
public DiagnosticResultAction getResult() {
return result.get();
}
public void setResult(DiagnosticResultAction result) {
this.result.set(result);
}
public ObjectProperty<DiagnosticResultAction> resultProperty() {
return result;
}
public boolean isFixButtonVisibile() {
return fixButtonVisible.getValue();
}
public Binding<Boolean> fixButtonVisibleProperty() {
return fixButtonVisible;
}
public String getDescription() {
return description.getValue();
}
public Binding<String> descriptionProperty() {
return description;
}
}

View File

@@ -0,0 +1,58 @@
package org.cryptomator.ui.health;
import org.cryptomator.ui.common.FxmlLoaderFactory;
import javax.inject.Inject;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import java.io.IOException;
import java.io.UncheckedIOException;
public class ResultListCellFactory implements Callback<ListView<DiagnosticResultAction>, ListCell<DiagnosticResultAction>> {
private final FxmlLoaderFactory fxmlLoaders;
@Inject
ResultListCellFactory(@HealthCheckWindow FxmlLoaderFactory fxmlLoaders) {
this.fxmlLoaders = fxmlLoaders;
}
@Override
public ListCell<DiagnosticResultAction> call(ListView<DiagnosticResultAction> param) {
try {
FXMLLoader fxmlLoader = fxmlLoaders.load("/fxml/health_result_listcell.fxml");
return new ResultListCellFactory.Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
} catch (IOException e) {
throw new UncheckedIOException("Failed to load /fxml/health_result_listcell.fxml.", e);
}
}
private static class Cell extends ListCell<DiagnosticResultAction> {
private final Parent node;
private final ResultListCellController controller;
public Cell(Parent node, ResultListCellController controller) {
this.node = node;
this.controller = controller;
}
@Override
protected void updateItem(DiagnosticResultAction item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
controller.setResult(item);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(node);
}
}
}
}

View File

@@ -1,47 +0,0 @@
package org.cryptomator.ui.health;
import org.cryptomator.cryptofs.health.api.DiagnosticResult;
import org.cryptomator.ui.controls.FontAwesome5Icon;
import org.cryptomator.ui.controls.FontAwesome5IconView;
import javafx.scene.control.TableCell;
public class ResultSeverityTableCell extends TableCell<DiagnosticResultAction, DiagnosticResult.Severity> {
private FontAwesome5IconView iconView;
ResultSeverityTableCell() {
iconView = new FontAwesome5IconView();
}
@Override
protected void updateItem(DiagnosticResult.Severity item, boolean empty) {
super.updateItem(item, empty);
iconView.getStyleClass().clear();
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
switch (item) {
case INFO -> {
iconView.setGlyph(FontAwesome5Icon.INFO_CIRCLE);
iconView.getStyleClass().add("glyph-icon-muted");
}
case GOOD -> {
iconView.setGlyph(FontAwesome5Icon.CHECK);
iconView.getStyleClass().add("glyph-icon-primary");
}
case WARN -> {
iconView.setGlyph(FontAwesome5Icon.EXCLAMATION_TRIANGLE);
iconView.getStyleClass().add("glyph-icon-orange");
}
case CRITICAL -> {
iconView.setGlyph(FontAwesome5Icon.TIMES);
iconView.getStyleClass().add("glyph-icon-red");
}
}
setGraphic(iconView);
setText(item.name());
}
}
}

View File

@@ -1,21 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<VBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.health.CheckDetailController"
spacing="6">
<Label fx:id="checkTitle" styleClass="label-large" text="${controller.taskName}"/>
<Label fx:id="checkTitle" styleClass="label-large" text="${controller.taskName}"/> <!-- use formatted label and let the text be "Results of [TASKNAME] -->
<Text fx:id="checkDescription" styleClass="label" text="${controller.taskDescription}"/>
<TableView fx:id="resultsTableView" visible="${controller.producingResults}" managed="${controller.producingResults}" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="resultDescriptionColumn" text="Info" editable="false" maxWidth="Infinity" />
<TableColumn fx:id="resultSeverityColumn" text="Severity" editable="false" />
<TableColumn fx:id="resultActionColumn" text="Action" editable="false"/>
</columns>
</TableView>
<ListView fx:id="resultsListView"/>
</VBox>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Region?>
<HBox xmlns:fx="http://javafx.com/fxml"
xmlns="http://javafx.com/javafx"
fx:controller="org.cryptomator.ui.health.ResultListCellController"
prefHeight="25"
prefWidth="200"
spacing="6"
alignment="CENTER_LEFT">
<!-- Remark Check the containing list view for a fixed cell size before editing height properties -->
<padding>
<Insets topRightBottomLeft="6"/>
</padding>
<children>
<FontAwesome5IconView fx:id="iconView" HBox.hgrow="NEVER" glyphSize="16"/>
<Label text="${controller.description}" wrapText="true"/>
<Region HBox.hgrow="ALWAYS"/>
<Button text="YOLO" onAction="#runResultAction" alignment="CENTER_RIGHT" visible="${controller.fixButtonVisibile}"/>
</children>
</HBox>