diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index df712fe24..41e5d1cd6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -23,11 +23,9 @@ import javafx.application.Platform; import javafx.beans.InvalidationListener; import javafx.beans.Observable; import javafx.beans.WeakInvalidationListener; +import javafx.beans.property.BooleanProperty; import javafx.beans.property.Property; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; -import javafx.beans.value.WeakChangeListener; -import javafx.beans.value.WritableValue; +import javafx.beans.value.*; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; @@ -657,6 +655,61 @@ public final class FXUtils { comboBox.getSelectionModel().selectedIndexProperty().removeListener(listener); } + public static void bindAllEnabled(BooleanProperty allEnabled, BooleanProperty... children) { + int itemCount = children.length; + int childSelectedCount = 0; + for (BooleanProperty child : children) { + if (child.get()) + childSelectedCount++; + } + + allEnabled.set(childSelectedCount == itemCount); + + class Listener implements InvalidationListener { + private int childSelectedCount; + private boolean updating = false; + + public Listener(int childSelectedCount) { + this.childSelectedCount = childSelectedCount; + } + + @Override + public void invalidated(Observable observable) { + if (updating) + return; + + updating = true; + try { + boolean value = ((BooleanProperty) observable).get(); + + if (observable == allEnabled) { + for (BooleanProperty child : children) { + child.setValue(value); + } + childSelectedCount = value ? itemCount : 0; + } else { + if (value) + childSelectedCount++; + else + childSelectedCount--; + + allEnabled.set(childSelectedCount == itemCount); + } + } finally { + updating = false; + } + } + } + + InvalidationListener listener = new Listener(childSelectedCount); + + WeakInvalidationListener weakListener = new WeakInvalidationListener(listener); + allEnabled.addListener(listener); + for (BooleanProperty child : children) { + child.addListener(weakListener); + } + } + public static void setIcon(Stage stage) { String icon; if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) { @@ -925,7 +978,7 @@ public final class FXUtils { Element r = doc.getDocumentElement(); NodeList children = r.getChildNodes(); - List texts = new ArrayList<>(); + List texts = new ArrayList<>(); for (int i = 0; i < children.getLength(); i++) { org.w3c.dom.Node node = children.item(i); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java index 0d080f731..791ba21c4 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java @@ -24,6 +24,7 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.scene.control.CheckBox; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.CheckBoxTableCell; @@ -73,6 +74,8 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage { getStyleClass().add("gray-background"); TableColumn enabledColumn = new TableColumn<>(); + CheckBox allEnabledBox = new CheckBox(); + enabledColumn.setGraphic(allEnabledBox); enabledColumn.setCellFactory(CheckBoxTableCell.forTableColumn(enabledColumn)); setupCellValueFactory(enabledColumn, ModUpdateObject::enabledProperty); enabledColumn.setEditable(true); @@ -95,6 +98,7 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage { setupCellValueFactory(sourceColumn, ModUpdateObject::sourceProperty); objects = FXCollections.observableList(updates.stream().map(ModUpdateObject::new).collect(Collectors.toList())); + FXUtils.bindAllEnabled(allEnabledBox.selectedProperty(), objects.stream().map(o -> o.enabled).toArray(BooleanProperty[]::new)); TableView table = new TableView<>(objects); table.setEditable(true); @@ -170,7 +174,7 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage { csvTable.write(Files.newOutputStream(path)); FXUtils.showFileInExplorer(path); - }).whenComplete(Schedulers.javafx() ,exception -> { + }).whenComplete(Schedulers.javafx(), exception -> { if (exception == null) { Controllers.dialog(path.toString(), i18n("message.success")); } else {