Refactor CheckListCell to display ellipsis rather than allow horizontal scrolling

This commit is contained in:
Armin Schrenk
2021-07-15 12:48:39 +02:00
parent 8d9c33f7df
commit 3f76a04b38
6 changed files with 162 additions and 50 deletions

View File

@@ -1,48 +0,0 @@
package org.cryptomator.ui.health;
import javafx.beans.binding.Bindings;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.layout.StackPane;
class CheckListCell extends ListCell<Check> {
private final CheckStateIconView stateIcon = new CheckStateIconView();
private CheckBox checkBox = new CheckBox();
private final StackPane graphicContainer = new StackPane(stateIcon, checkBox);
CheckListCell() {
setPadding(new Insets(6));
setAlignment(Pos.CENTER_LEFT);
setContentDisplay(ContentDisplay.LEFT);
getStyleClass().add("label");
graphicContainer.minWidth(20);
graphicContainer.maxWidth(20);
graphicContainer.setAlignment(Pos.CENTER);
}
@Override
protected void updateItem(Check item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
setText(item.getLocalizedName());
setGraphic(graphicContainer);
stateIcon.setCheck(item);
checkBox.visibleProperty().bind(Bindings.createBooleanBinding(() -> item.getState() == Check.CheckState.RUNNABLE, item.stateProperty()));
stateIcon.visibleProperty().bind(Bindings.createBooleanBinding(() -> item.getState() != Check.CheckState.RUNNABLE, item.stateProperty()));
checkBox.selectedProperty().bindBidirectional(item.chosenForExecutionProperty());
} else {
graphicProperty();
checkBox.visibleProperty().unbind();
stateIcon.visibleProperty().unbind();
stateIcon.setCheck(null);
setGraphic(null);
setText(null);
checkBox.selectedProperty().unbind();
}
}
}

View File

@@ -0,0 +1,70 @@
package org.cryptomator.ui.health;
import com.tobiasdiez.easybind.EasyBind;
import com.tobiasdiez.easybind.Subscription;
import org.cryptomator.ui.common.FxController;
import javax.inject.Inject;
import javafx.beans.binding.Binding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.CheckBox;
import java.util.ArrayList;
import java.util.List;
public class CheckListCellController implements FxController {
private final ObjectProperty<Check> check;
private final Binding<String> checkName;
private final Binding<Boolean> checkRunnable;
private final List<Subscription> subscriptions;
/* FXML */
public CheckBox forRunSelectedCheckBox;
@Inject
public CheckListCellController() {
check = new SimpleObjectProperty<>();
checkRunnable = EasyBind.wrapNullable(check).mapObservable(Check::stateProperty).map(Check.CheckState.RUNNABLE::equals).orElse(false);
checkName = EasyBind.wrapNullable(check).map(Check::getLocalizedName).orElse("");
subscriptions = new ArrayList<>();
}
public void initialize() {
subscriptions.add(EasyBind.subscribe(check, c -> {
forRunSelectedCheckBox.selectedProperty().unbind();
if (c != null) {
forRunSelectedCheckBox.selectedProperty().bindBidirectional(c.chosenForExecutionProperty());
}
}));
}
public ObjectProperty<Check> checkProperty() {
return check;
}
public Check getCheck() {
return check.get();
}
public void setCheck(Check c) {
check.set(c);
}
public Binding<String> checkNameProperty() {
return checkName;
}
public String getCheckName() {
return checkName.getValue();
}
public Binding<Boolean> checkRunnableProperty() {
return checkRunnable;
}
public boolean isCheckRunnable() {
return checkRunnable.getValue();
}
}

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;
// unscoped because each cell needs its own controller
public class CheckListCellFactory implements Callback<ListView<Check>, ListCell<Check>> {
private final FxmlLoaderFactory fxmlLoaders;
@Inject
CheckListCellFactory(@HealthCheckWindow FxmlLoaderFactory fxmlLoaders) {
this.fxmlLoaders = fxmlLoaders;
}
@Override
public ListCell<Check> call(ListView<Check> param) {
try {
FXMLLoader fxmlLoader = fxmlLoaders.load("/fxml/health_check_listcell.fxml");
return new CheckListCellFactory.Cell(fxmlLoader.getRoot(), fxmlLoader.getController());
} catch (IOException e) {
throw new UncheckedIOException("Failed to load /fxml/health_check_listcell.fxml.", e);
}
}
private static class Cell extends ListCell<Check> {
private final Parent node;
private final CheckListCellController controller;
public Cell(Parent node, CheckListCellController controller) {
this.node = node;
this.controller = controller;
}
@Override
protected void updateItem(Check item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setGraphic(null);
} else {
controller.setCheck(item);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
setGraphic(node);
}
}
}
}

View File

@@ -40,15 +40,17 @@ public class CheckListController implements FxController {
private final Lazy<ErrorComponent.Builder> errorComponentBuilder;
private final IntegerBinding chosenTaskCount;
private final BooleanBinding anyCheckSelected;
private final CheckListCellFactory listCellFactory;
/* FXML */
public ListView<Check> checksListView;
@Inject
public CheckListController(@HealthCheckWindow Stage window, List<Check> checks, CheckExecutor checkExecutor, ReportWriter reportWriteTask, ObjectProperty<Check> selectedCheck, Lazy<ErrorComponent.Builder> errorComponentBuilder) {
public CheckListController(@HealthCheckWindow Stage window, List<Check> checks, CheckExecutor checkExecutor, ReportWriter reportWriteTask, ObjectProperty<Check> selectedCheck, Lazy<ErrorComponent.Builder> errorComponentBuilder, CheckListCellFactory listCellFactory) {
this.window = window;
this.checks = FXCollections.observableList(checks, Check::observables);
this.checkExecutor = checkExecutor;
this.listCellFactory = listCellFactory;
this.chosenChecks = this.checks.filtered(Check::isChosenForExecution);
this.reportWriter = reportWriteTask;
this.selectedCheck = selectedCheck;
@@ -63,7 +65,7 @@ public class CheckListController implements FxController {
public void initialize() {
checksListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
checksListView.setItems(checks);
checksListView.setCellFactory(view -> new CheckListCell());
checksListView.setCellFactory(listCellFactory);
selectedCheck.bind(checksListView.getSelectionModel().selectedItemProperty());
}

View File

@@ -166,4 +166,8 @@ abstract class HealthCheckModule {
@FxControllerKey(ResultListCellController.class)
abstract FxController bindResultListCellController(ResultListCellController controller);
@Binds
@IntoMap
@FxControllerKey(CheckListCellController.class)
abstract FxController bindCheckListCellController(CheckListCellController controller);
}