diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java index c8e9ddf34..d1a6d5e02 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/VersionSetting.java @@ -81,7 +81,7 @@ public final class VersionSetting { } /** - * Java version or null if user customizes java directory. + * Java version or "Custom" if user customizes java directory, "Default" if the jvm that this app relies on. */ public String getJava() { return javaProperty.get(); @@ -91,6 +91,15 @@ public final class VersionSetting { javaProperty.set(java); } + public boolean isUsesCustomJavaDir() { + return "Custom".equals(getJava()); + } + + public void setUsesCustomJavaDir() { + setJava("Custom"); + setDefaultJavaPath(null); + } + private final ImmediateStringProperty defaultJavaPathProperty = new ImmediateStringProperty(this, "defaultJavaPath", ""); /** @@ -455,7 +464,7 @@ public final class VersionSetting { if (StringUtils.isBlank(getJava())) setJava(StringUtils.isBlank(getJavaDir()) ? "Default" : "Custom"); if ("Default".equals(getJava())) return JavaVersion.fromCurrentEnvironment(); - else if ("Custom".equals(getJava())) { + else if (isUsesCustomJavaDir()) { try { return JavaVersion.fromExecutable(new File(getJavaDir())); } catch (IOException e) { @@ -477,6 +486,11 @@ public final class VersionSetting { } else throw new Error(); } + public void setJavaVersion(JavaVersion java) { + setJava(java.getVersion()); + setDefaultJavaPath(java.getBinary().toString()); + } + public void addPropertyChangedListener(InvalidationListener listener) { usesGlobalProperty.addListener(listener); javaProperty.addListener(listener); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java index 63670a673..d17d04419 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/VersionSettingsController.java @@ -22,6 +22,7 @@ import com.jfoenix.controls.JFXComboBox; import com.jfoenix.controls.JFXTextField; import com.jfoenix.controls.JFXToggleButton; import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; @@ -72,9 +73,9 @@ public final class VersionSettingsController { @FXML private JFXToggleButton chkNoJVMArgs; @FXML private JFXToggleButton chkNoCommon; @FXML private JFXToggleButton chkNoGameCheck; - @FXML private MultiFileItem globalItem; - @FXML private MultiFileItem javaItem; - @FXML private MultiFileItem gameDirItem; + @FXML private MultiFileItem globalItem; + @FXML private MultiFileItem javaItem; + @FXML private MultiFileItem gameDirItem; @FXML private JFXToggleButton chkShowLogs; @FXML private ImagePickerItem iconPickerItem; @@ -94,9 +95,12 @@ public final class VersionSettingsController { initializeSelectedJava(); }); + javaItem.setSelectedData(null); + javaItem.setFallbackData(JavaVersion.fromCurrentEnvironment()); if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) javaItem.getExtensionFilters().add(new FileChooser.ExtensionFilter("Java", "java.exe", "javaw.exe")); + gameDirItem.setCustomUserData(EnumGameDirectory.CUSTOM); gameDirItem.loadChildren(Arrays.asList( gameDirItem.createChildren(i18n("settings.advanced.game_dir.default"), EnumGameDirectory.ROOT_FOLDER), gameDirItem.createChildren(i18n("settings.advanced.game_dir.independent"), EnumGameDirectory.VERSION_FOLDER) @@ -136,12 +140,16 @@ public final class VersionSettingsController { FXUtils.unbindBoolean(chkNoJVMArgs, lastVersionSetting.noJVMArgsProperty()); FXUtils.unbindBoolean(chkShowLogs, lastVersionSetting.showLogsProperty()); FXUtils.unbindEnum(cboLauncherVisibility); + + globalItem.selectedDataProperty().unbindBidirectional(lastVersionSetting.usesGlobalProperty()); + + gameDirItem.selectedDataProperty().unbindBidirectional(lastVersionSetting.gameDirTypeProperty()); + gameDirItem.subtitleProperty().unbind(); } // unbind data fields globalItem.setToggleSelectedListener(null); javaItem.setToggleSelectedListener(null); - gameDirItem.setToggleSelectedListener(null); // bind new data fields FXUtils.bindInt(txtWidth, versionSetting.widthProperty()); @@ -164,12 +172,9 @@ public final class VersionSettingsController { javaItem.setToggleSelectedListener(newValue -> { if (javaItem.isCustomToggle(newValue)) { - versionSetting.setJava("Custom"); - versionSetting.setDefaultJavaPath(null); + versionSetting.setUsesCustomJavaDir(); } else { - JavaVersion java = (JavaVersion) newValue.getUserData(); - versionSetting.setJava(java.getVersion()); - versionSetting.setDefaultJavaPath(java.getBinary().toString()); + versionSetting.setJavaVersion((JavaVersion) newValue.getUserData()); } }); @@ -177,13 +182,13 @@ public final class VersionSettingsController { versionSetting.javaProperty().setChangedListener(it -> initJavaSubtitle(versionSetting)); initJavaSubtitle(versionSetting); - if (versionSetting.isUsesGlobal()) - globalItem.getGroup().getToggles().stream().filter(it -> it.getUserData() == Boolean.TRUE).findFirst().ifPresent(it -> it.setSelected(true)); - else - globalItem.getGroup().getToggles().stream().filter(it -> it.getUserData() == Boolean.FALSE).findFirst().ifPresent(it -> it.setSelected(true)); + globalItem.selectedDataProperty().bindBidirectional(versionSetting.usesGlobalProperty()); + globalItem.subtitleProperty().bind(Bindings.createStringBinding(() -> i18n(versionSetting.isUsesGlobal() ? "settings.type.global" : "settings.type.special"), + versionSetting.usesGlobalProperty())); globalItem.setToggleSelectedListener(newValue -> { // do not call versionSettings.setUsesGlobal(true/false) // because versionSettings can be the global one. + // global versionSettings.usesGlobal is always true. if ((Boolean) newValue.getUserData()) profile.globalizeVersionSetting(versionId); else @@ -192,19 +197,9 @@ public final class VersionSettingsController { Platform.runLater(() -> loadVersionSetting(profile, versionId)); }); - versionSetting.usesGlobalProperty().setChangedListenerAndOperate(it -> - globalItem.setSubtitle(i18n(versionSetting.isUsesGlobal() ? "settings.type.global" : "settings.type.special"))); - - gameDirItem.getGroup().getToggles().stream() - .filter(it -> it.getUserData() == versionSetting.getGameDirType()) - .findFirst().ifPresent(toggle -> toggle.setSelected(true)); - - gameDirItem.setCustomUserData(EnumGameDirectory.CUSTOM); - gameDirItem.setToggleSelectedListener(newValue -> versionSetting.setGameDirType((EnumGameDirectory) newValue.getUserData())); - - versionSetting.gameDirProperty().setChangedListener(it -> initGameDirSubtitle(versionSetting)); - versionSetting.gameDirTypeProperty().setChangedListener(it -> initGameDirSubtitle(versionSetting)); - initGameDirSubtitle(versionSetting); + gameDirItem.selectedDataProperty().bindBidirectional(versionSetting.gameDirTypeProperty()); + gameDirItem.subtitleProperty().bind(Bindings.createStringBinding(() -> profile.getRepository().getRunDirectory(versionId).getAbsolutePath(), + versionSetting.gameDirProperty(), versionSetting.gameDirTypeProperty())); lastVersionSetting = versionSetting; @@ -219,30 +214,14 @@ public final class VersionSettingsController { return; } - List toggles = javaItem.getGroup().getToggles(); - if ("Custom".equals(lastVersionSetting.getJava())) { - toggles.stream() - .filter(javaItem::isCustomToggle) - .findFirst() - .get().setSelected(true); + if (lastVersionSetting.isUsesCustomJavaDir()) { + javaItem.setSelectedData(null); } else { - JavaVersion selectedJava; try { - selectedJava = lastVersionSetting.getJavaVersion(); + javaItem.setSelectedData(lastVersionSetting.getJavaVersion()); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - return; } - toggles.stream() - .filter(it -> it.getUserData() == selectedJava) - .findFirst() - .orElseGet( // fallback to select current java - () -> toggles.stream() - .filter(it -> it.getUserData() == JavaVersion.fromCurrentEnvironment()) - .findFirst() - .get()) - .setSelected(true); - ; } } @@ -253,10 +232,6 @@ public final class VersionSettingsController { .map(JavaVersion::getBinary).map(File::getAbsolutePath).orElse("Invalid Java Directory")))); } - private void initGameDirSubtitle(VersionSetting versionSetting) { - gameDirItem.setSubtitle(profile.getRepository().getRunDirectory(versionId).getAbsolutePath()); - } - @FXML private void onExploreIcon() { FileChooser chooser = new FileChooser(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java index 39d246d01..759bf153b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/MultiFileItem.java @@ -21,10 +21,7 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXRadioButton; import com.jfoenix.controls.JFXTextField; import javafx.beans.NamedArg; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; +import javafx.beans.property.*; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.Pos; @@ -46,12 +43,15 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.io.File; import java.util.Collection; +import java.util.Optional; import java.util.function.Consumer; -public class MultiFileItem extends ComponentList { +public class MultiFileItem extends ComponentList { private final StringProperty customTitle = new SimpleStringProperty(this, "customTitle", i18n("selector.custom")); private final StringProperty chooserTitle = new SimpleStringProperty(this, "chooserTitle", i18n("selector.choose_file")); private final BooleanProperty directory = new SimpleBooleanProperty(this, "directory", false); + private final ObjectProperty selectedData = new SimpleObjectProperty<>(this, "selectedData"); + private final ObjectProperty fallbackData = new SimpleObjectProperty<>(this, "fallbackData"); private final ObservableList extensionFilters = FXCollections.observableArrayList(); private final ToggleGroup group = new ToggleGroup(); @@ -64,6 +64,7 @@ public class MultiFileItem extends ComponentList { private Consumer toggleSelectedListener; + @SuppressWarnings("unchecked") public MultiFileItem(@NamedArg(value = "hasCustom", defaultValue = "true") boolean hasCustom) { this.hasCustom = hasCustom; @@ -110,6 +111,20 @@ public class MultiFileItem extends ComponentList { group.selectedToggleProperty().addListener((a, b, newValue) -> { if (toggleSelectedListener != null) toggleSelectedListener.accept(newValue); + + selectedData.set((T) newValue.getUserData()); + }); + selectedData.addListener((a, b, newValue) -> { + Optional selecting = group.getToggles().stream() + .filter(it -> it.getUserData() == newValue) + .findFirst(); + if (!selecting.isPresent()) { + selecting = group.getToggles().stream() + .filter(it -> it.getUserData() == getFallbackData()) + .findFirst(); + } + + selecting.ifPresent(toggle -> toggle.setSelected(true)); }); } @@ -117,11 +132,11 @@ public class MultiFileItem extends ComponentList { return createChildren(title, null); } - public Node createChildren(String title, Object userData) { + public Node createChildren(String title, T userData) { return createChildren(title, "", userData); } - public Node createChildren(String title, String subtitle, Object userData) { + public Node createChildren(String title, String subtitle, T userData) { BorderPane pane = new BorderPane(); pane.setStyle("-fx-padding: 3;"); FXUtils.setLimitHeight(pane, 20); @@ -146,14 +161,6 @@ public class MultiFileItem extends ComponentList { pane.getChildren().add(custom); } - public void onExploreJavaDir() { - DirectoryChooser chooser = new DirectoryChooser(); - chooser.setTitle(i18n(getChooserTitle())); - File selectedDir = chooser.showDialog(Controllers.getStage()); - if (selectedDir != null) - txtCustom.setText(selectedDir.getAbsolutePath()); - } - public ToggleGroup getGroup() { return group; } @@ -182,7 +189,7 @@ public class MultiFileItem extends ComponentList { this.chooserTitle.set(chooserTitle); } - public void setCustomUserData(Object userData) { + public void setCustomUserData(T userData) { radioCustom.setUserData(userData); } @@ -225,4 +232,28 @@ public class MultiFileItem extends ComponentList { public ObservableList getExtensionFilters() { return extensionFilters; } + + public T getSelectedData() { + return selectedData.get(); + } + + public ObjectProperty selectedDataProperty() { + return selectedData; + } + + public void setSelectedData(T selectedData) { + this.selectedData.set(selectedData); + } + + public T getFallbackData() { + return fallbackData.get(); + } + + public ObjectProperty fallbackDataProperty() { + return fallbackData; + } + + public void setFallbackData(T fallbackData) { + this.fallbackData.set(fallbackData); + } }