From 9f7c69388c1a43045f6eba33782f6b0033863072 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 21 Jul 2021 10:43:10 +0200 Subject: [PATCH] make the view depend on state, not on another view --- .../ui/controls/FontAwesome5IconView.java | 4 +- .../ui/health/CheckStateIconView.java | 52 ++++++++++++------- .../ui/health/ResultListCellController.java | 36 +++++++------ .../fxml/health_result_listcell.fxml | 2 +- 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/cryptomator/ui/controls/FontAwesome5IconView.java b/src/main/java/org/cryptomator/ui/controls/FontAwesome5IconView.java index 3bfa70c46..4c89ca674 100644 --- a/src/main/java/org/cryptomator/ui/controls/FontAwesome5IconView.java +++ b/src/main/java/org/cryptomator/ui/controls/FontAwesome5IconView.java @@ -21,8 +21,8 @@ public class FontAwesome5IconView extends Text { private static final String FONT_PATH = "/css/fontawesome5-free-solid.otf"; private static final Font FONT; - private final ObjectProperty glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH); - private final DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE); + protected final ObjectProperty glyph = new SimpleObjectProperty<>(this, "glyph", DEFAULT_GLYPH); + protected final DoubleProperty glyphSize = new SimpleDoubleProperty(this, "glyphSize", DEFAULT_GLYPH_SIZE); static { try { diff --git a/src/main/java/org/cryptomator/ui/health/CheckStateIconView.java b/src/main/java/org/cryptomator/ui/health/CheckStateIconView.java index 615cb10b8..9b91238d2 100644 --- a/src/main/java/org/cryptomator/ui/health/CheckStateIconView.java +++ b/src/main/java/org/cryptomator/ui/health/CheckStateIconView.java @@ -2,48 +2,62 @@ package org.cryptomator.ui.health; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.Subscription; -import com.tobiasdiez.easybind.optional.OptionalBinding; import org.cryptomator.cryptofs.health.api.DiagnosticResult; import org.cryptomator.ui.controls.FontAwesome5Icon; import org.cryptomator.ui.controls.FontAwesome5IconView; +import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableObjectValue; import java.util.List; -import java.util.Optional; +/** + * A {@link FontAwesome5IconView} that automatically sets the glyph depending on + * the {@link Check#stateProperty() state} and {@link Check#highestResultSeverityProperty() severity} of a HealthCheck. + */ public class CheckStateIconView extends FontAwesome5IconView { - private final static List ATTENTION_ICONS = List.of(FontAwesome5Icon.CHECK, FontAwesome5Icon.EXCLAMATION_TRIANGLE, FontAwesome5Icon.TIMES); - private final ObjectProperty check = new SimpleObjectProperty<>(); - private final OptionalBinding state; - private final OptionalBinding severity; - private List subscriptions; + private final ObservableObjectValue state; + private final ObservableObjectValue severity; + private final List subscriptions; public CheckStateIconView() { - super(); - this.state = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty); - this.severity = EasyBind.wrapNullable(check).mapObservable(Check::highestResultSeverityProperty); - glyphProperty().bind(EasyBind.combine(state, severity, this::glyphForState)); //TODO: does the binding need to be stored? + this.state = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty).asOrdinary(); + this.severity = EasyBind.wrapNullable(check).mapObservable(Check::highestResultSeverityProperty).asOrdinary(); + this.glyph.bind(Bindings.createObjectBinding(this::glyphForState, state, severity)); this.subscriptions = List.of( - EasyBind.includeWhen(getStyleClass(), "glyph-icon-muted", EasyBind.map(glyphProperty(), glyph -> glyph == null || !ATTENTION_ICONS.contains(glyph))), - EasyBind.includeWhen(getStyleClass(), "glyph-icon-primary", glyphProperty().isEqualTo(FontAwesome5Icon.CHECK)), - EasyBind.includeWhen(getStyleClass(), "glyph-icon-orange", glyphProperty().isEqualTo(FontAwesome5Icon.EXCLAMATION_TRIANGLE)), - EasyBind.includeWhen(getStyleClass(), "glyph-icon-red", glyphProperty().isEqualTo(FontAwesome5Icon.TIMES)) + //EasyBind.includeWhen(getStyleClass(), "glyph-icon-muted", Bindings.notEqual(state, Check.CheckState.ERROR).and(Bindings.isNull(severity))), // TODO not really needed, right? + EasyBind.includeWhen(getStyleClass(), "glyph-icon-primary", Bindings.equal(severity, DiagnosticResult.Severity.GOOD)), // + EasyBind.includeWhen(getStyleClass(), "glyph-icon-orange", Bindings.equal(severity, DiagnosticResult.Severity.WARN)), // + EasyBind.includeWhen(getStyleClass(), "glyph-icon-red", Bindings.equal(severity, DiagnosticResult.Severity.CRITICAL).or(Bindings.equal(state, Check.CheckState.ERROR))) // ); } - private FontAwesome5Icon glyphForState(Optional state, Optional severity) { - return state.map(s -> switch (s) { + private FontAwesome5Icon glyphForState() { + if (state.getValue() == null) { + return null; + } + return switch (state.getValue()) { case RUNNABLE -> null; case SKIPPED -> FontAwesome5Icon.FAST_FORWARD; case SCHEDULED -> FontAwesome5Icon.CLOCK; case RUNNING -> FontAwesome5Icon.SPINNER; case ERROR -> FontAwesome5Icon.TIMES; case CANCELLED -> FontAwesome5Icon.BAN; - case SUCCEEDED -> severity.map(se -> DiagnosticResult.Severity.GOOD.compareTo(se) >= 0 ? FontAwesome5Icon.CHECK : FontAwesome5Icon.EXCLAMATION_TRIANGLE).orElse(null); - }).orElse(null); + case SUCCEEDED -> glyphIconForSeverity(); + }; + } + + private FontAwesome5Icon glyphIconForSeverity() { + if (severity.getValue() == null) { + return null; + } + return switch (severity.getValue()) { + case GOOD, INFO -> FontAwesome5Icon.CHECK; + case WARN, CRITICAL -> FontAwesome5Icon.EXCLAMATION_TRIANGLE; + }; } public ObjectProperty checkProperty() { diff --git a/src/main/java/org/cryptomator/ui/health/ResultListCellController.java b/src/main/java/org/cryptomator/ui/health/ResultListCellController.java index b656a944f..812fb97c5 100644 --- a/src/main/java/org/cryptomator/ui/health/ResultListCellController.java +++ b/src/main/java/org/cryptomator/ui/health/ResultListCellController.java @@ -2,7 +2,7 @@ package org.cryptomator.ui.health; import com.tobiasdiez.easybind.EasyBind; import com.tobiasdiez.easybind.Subscription; -import com.tobiasdiez.easybind.optional.OptionalBinding; +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; @@ -17,6 +17,7 @@ import javafx.beans.binding.BooleanBinding; import javafx.beans.binding.ObjectBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.value.ObservableObjectValue; import javafx.fxml.FXML; import javafx.scene.control.Tooltip; import javafx.util.Duration; @@ -35,9 +36,10 @@ public class ResultListCellController implements FxController { private final Logger LOG = LoggerFactory.getLogger(ResultListCellController.class); private final ObjectProperty result; + private final ObservableObjectValue severity; private final Binding description; private final ResultFixApplier fixApplier; - private final OptionalBinding fixState; + private final ObservableObjectValue fixState; private final ObjectBinding severityGlyph; private final ObjectBinding fixGlyph; private final BooleanBinding fixable; @@ -56,9 +58,10 @@ public class ResultListCellController implements FxController { @Inject public ResultListCellController(ResultFixApplier fixApplier, ResourceBundle resourceBundle) { this.result = new SimpleObjectProperty<>(null); + this.severity = EasyBind.wrapNullable(result).map(r -> r.diagnosis().getSeverity()).asOrdinary(); this.description = EasyBind.wrapNullable(result).map(Result::getDescription).orElse(""); this.fixApplier = fixApplier; - this.fixState = EasyBind.wrapNullable(result).mapObservable(Result::fixState); + this.fixState = EasyBind.wrapNullable(result).mapObservable(Result::fixState).asOrdinary(); this.severityGlyph = Bindings.createObjectBinding(this::getSeverityGlyph, result); this.fixGlyph = Bindings.createObjectBinding(this::getFixGlyph, fixState); this.fixable = Bindings.createBooleanBinding(this::isFixable, fixState); @@ -76,12 +79,12 @@ public class ResultListCellController implements FxController { @FXML public void initialize() { // see getGlyph() for relevant glyphs: - subscriptions.addAll(List.of(EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-muted", severityView.glyphProperty().isEqualTo(INFO_ICON)), // - EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-primary", severityView.glyphProperty().isEqualTo(GOOD_ICON)), // - EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-orange", severityView.glyphProperty().isEqualTo(WARN_ICON)), // - EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-red", severityView.glyphProperty().isEqualTo(CRIT_ICON)), // - EasyBind.includeWhen(fixView.getStyleClass(), "glyph-icon-muted", fixView.glyphProperty().isNotNull())) // - ); + subscriptions.addAll(List.of(EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-muted", Bindings.equal(severity, DiagnosticResult.Severity.INFO)), // + EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-primary", Bindings.equal(severity, DiagnosticResult.Severity.GOOD)), // + EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-orange", Bindings.equal(severity, DiagnosticResult.Severity.WARN)), // + EasyBind.includeWhen(severityView.getStyleClass(), "glyph-icon-red", Bindings.equal(severity, DiagnosticResult.Severity.CRITICAL)) // + // EasyBind.includeWhen(fixView.getStyleClass(), "glyph-icon-muted", fixView.glyphProperty().isNotNull())) // TODO not really needed, right? + )); } @FXML @@ -146,12 +149,15 @@ public class ResultListCellController implements FxController { } public FontAwesome5Icon getFixGlyph() { - return fixState.get().map(s -> switch (s) { + if (fixState.getValue() == null) { + return null; + } + return switch (fixState.getValue()) { case NOT_FIXABLE, FIXABLE -> null; case FIXING -> FontAwesome5Icon.SPINNER; case FIXED -> FontAwesome5Icon.CHECK; case FIX_FAILED -> FontAwesome5Icon.TIMES; - }).orElse(null); + }; } public BooleanBinding fixableProperty() { @@ -159,7 +165,7 @@ public class ResultListCellController implements FxController { } public boolean isFixable() { - return fixState.get().map(Result.FixState.FIXABLE::equals).orElse(false); + return Result.FixState.FIXABLE.equals(fixState.get()); } public BooleanBinding fixingProperty() { @@ -167,7 +173,7 @@ public class ResultListCellController implements FxController { } public boolean isFixing() { - return fixState.get().map(Result.FixState.FIXING::equals).orElse(false); + return Result.FixState.FIXING.equals(fixState.get()); } public BooleanBinding fixedProperty() { @@ -175,7 +181,7 @@ public class ResultListCellController implements FxController { } public boolean isFixed() { - return fixState.get().map(Result.FixState.FIXED::equals).orElse(false); + return Result.FixState.FIXED.equals(fixState.get()); } public BooleanBinding fixFailedProperty() { @@ -183,7 +189,7 @@ public class ResultListCellController implements FxController { } public Boolean isFixFailed() { - return fixState.get().map(Result.FixState.FIX_FAILED::equals).orElse(false); + return Result.FixState.FIX_FAILED.equals(fixState.get()); } public BooleanBinding fixRunningOrDoneProperty() { diff --git a/src/main/resources/fxml/health_result_listcell.fxml b/src/main/resources/fxml/health_result_listcell.fxml index 6ef86b486..0a6744870 100644 --- a/src/main/resources/fxml/health_result_listcell.fxml +++ b/src/main/resources/fxml/health_result_listcell.fxml @@ -26,7 +26,7 @@