diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java index ce34357a3..33935476b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameDownloadTask.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.game; import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.Task; @@ -29,6 +30,7 @@ import java.io.File; import java.io.IOException; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import static org.jackhuang.hmcl.setting.ConfigHolder.CONFIG; @@ -59,7 +61,11 @@ public class HMCLGameDownloadTask extends Task { public void execute() { File jar = profile.getRepository().getVersionJar(version); - File cache = new File(CONFIG.getCommonDirectory(), "jars/" + gameVersion + ".jar"); + // Force using common directory will not affect the behaviour that repository acts + // Since we always copy the downloaded jar to .minecraft/versions// + File cache = new File(Optional.ofNullable(Settings.INSTANCE.getCommonDirectory()) + .orElse(Settings.getDefaultCommonDirectory()), + "jars/" + gameVersion + ".jar"); if (cache.exists()) try { FileUtils.copyFile(cache, jar); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java index 2aff2a527..c2a3717c9 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/HMCLGameRepository.java @@ -24,6 +24,7 @@ import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.event.RefreshingVersionsEvent; import org.jackhuang.hmcl.setting.EnumGameDirectory; import org.jackhuang.hmcl.setting.Profile; +import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.setting.VersionSetting; import org.jackhuang.hmcl.util.FileUtils; import org.jackhuang.hmcl.util.Logging; @@ -51,17 +52,16 @@ public class HMCLGameRepository extends DefaultGameRepository { return profile; } - private boolean useSelf(String version, String assetId) { - VersionSetting vs = profile.getVersionSetting(version); - return new File(getBaseDirectory(), "assets/indexes/" + assetId + ".json").exists() || vs.isNoCommon(); + private boolean useSelf(String assetId) { + return new File(getBaseDirectory(), "assets/indexes/" + assetId + ".json").exists(); } @Override public File getAssetDirectory(String version, String assetId) { - if (useSelf(version, assetId)) + if (Settings.INSTANCE.isCommonDirectoryDisabled() || useSelf(assetId)) return super.getAssetDirectory(version, assetId); else - return new File(CONFIG.getCommonDirectory(), "assets"); + return new File(Settings.INSTANCE.getCommonDirectory(), "assets"); } @Override @@ -83,10 +83,10 @@ public class HMCLGameRepository extends DefaultGameRepository { public File getLibraryFile(Version version, Library lib) { VersionSetting vs = profile.getVersionSetting(version.getId()); File self = super.getLibraryFile(version, lib); - if (self.exists() || vs.isNoCommon()) + if (Settings.INSTANCE.isCommonDirectoryDisabled() || self.exists()) return self; else - return new File(CONFIG.getCommonDirectory(), "libraries/" + lib.getPath()); + return new File(Settings.INSTANCE.getCommonDirectory(), "libraries/" + lib.getPath()); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java index e3dbfecb2..d7e90427a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Config.java @@ -89,6 +89,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("bgpath") private StringProperty backgroundImage = new SimpleStringProperty(); + @SerializedName("commonDirType") + private ObjectProperty commonDirType = new SimpleObjectProperty<>(EnumCommonDirectory.DEFAULT); + @SerializedName("commonpath") private StringProperty commonDirectory = new SimpleStringProperty(Launcher.MINECRAFT_DIRECTORY.getAbsolutePath()); @@ -146,6 +149,9 @@ public final class Config implements Cloneable, Observable { @SerializedName("authlibInjectorServers") private ObservableList authlibInjectorServers = FXCollections.observableArrayList(); + @SerializedName("_version") + private IntegerProperty configVersion = new SimpleIntegerProperty(0); + private transient ObservableHelper helper = new ObservableHelper(this); public Config() { @@ -225,6 +231,18 @@ public final class Config implements Cloneable, Observable { return backgroundImage; } + public EnumCommonDirectory getCommonDirType() { + return commonDirType.get(); + } + + public ObjectProperty commonDirTypeProperty() { + return commonDirType; + } + + public void setCommonDirType(EnumCommonDirectory commonDirType) { + this.commonDirType.set(commonDirType); + } + public String getCommonDirectory() { return commonDirectory.get(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java index 88827939f..c07bf7ec6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/ConfigHolder.java @@ -24,8 +24,10 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; import java.util.logging.Level; +import com.google.gson.Gson; import com.google.gson.JsonParseException; public final class ConfigHolder { @@ -36,15 +38,23 @@ public final class ConfigHolder { public static final Path CONFIG_PATH = Paths.get(CONFIG_FILENAME).toAbsolutePath(); public static final Config CONFIG = initSettings(); + private static Config upgradeSettings(Config deserialized, Map rawJson) { + if (!rawJson.containsKey("commonDirType")) + deserialized.setCommonDirType(deserialized.getCommonDirectory().equals(Settings.getDefaultCommonDirectory()) ? EnumCommonDirectory.DEFAULT : EnumCommonDirectory.CUSTOM); + return deserialized; + } + private static Config initSettings() { Config config = new Config(); if (Files.exists(CONFIG_PATH)) { try { - Config deserialized = Config.fromJson(new String(Files.readAllBytes(CONFIG_PATH), UTF_8)); + String json = new String(Files.readAllBytes(CONFIG_PATH), UTF_8); + Map raw = new Gson().fromJson(json, Map.class); + Config deserialized = Config.fromJson(json); if (deserialized == null) { LOG.finer("Settings file is empty, use the default settings."); } else { - config = deserialized; + config = upgradeSettings(deserialized, raw); } LOG.finest("Initialized settings."); } catch (IOException | JsonParseException e) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java new file mode 100644 index 000000000..5ca9fd426 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/EnumCommonDirectory.java @@ -0,0 +1,33 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.setting; + +public enum EnumCommonDirectory { + /** + * same to game directory + */ + DISABLED, + /** + * %appdata%/.minecraft or ~/.minecraft + */ + DEFAULT, + /** + * user customized common directory. + */ + CUSTOM +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java index 08cfb0532..9e9039460 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Settings.java @@ -27,6 +27,7 @@ import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.i18n.Locales; +import java.io.File; import java.util.*; import java.util.stream.Collectors; @@ -94,6 +95,27 @@ public class Settings { CONFIG.setLogLines(logLines); } + public boolean isCommonDirectoryDisabled() { + return CONFIG.getCommonDirType() == EnumCommonDirectory.DISABLED; + } + + public static String getDefaultCommonDirectory() { + return Launcher.MINECRAFT_DIRECTORY.getAbsolutePath(); + } + + public String getCommonDirectory() { + switch (CONFIG.getCommonDirType()) { + case DISABLED: + return null; + case DEFAULT: + return getDefaultCommonDirectory(); + case CUSTOM: + return CONFIG.getCommonDirectory(); + default: + return null; + } + } + /**************************************** * DOWNLOAD PROVIDERS * ****************************************/ 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..761dce2bf 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", ""); /** @@ -278,23 +287,6 @@ public final class VersionSetting { notCheckGameProperty.set(notCheckGame); } - private final ImmediateBooleanProperty noCommonProperty = new ImmediateBooleanProperty(this, "noCommon", false); - - public ImmediateBooleanProperty noCommonProperty() { - return noCommonProperty; - } - - /** - * True if HMCL does not find/download libraries in/to common path. - */ - public boolean isNoCommon() { - return noCommonProperty.get(); - } - - public void setNoCommon(boolean noCommon) { - noCommonProperty.set(noCommon); - } - private final ImmediateBooleanProperty showLogsProperty = new ImmediateBooleanProperty(this, "showLogs", false); public ImmediateBooleanProperty showLogsProperty() { @@ -455,7 +447,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 +469,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); @@ -490,7 +487,6 @@ public final class VersionSetting { minecraftArgsProperty.addListener(listener); noJVMArgsProperty.addListener(listener); notCheckGameProperty.addListener(listener); - noCommonProperty.addListener(listener); showLogsProperty.addListener(listener); serverIpProperty.addListener(listener); fullscreenProperty.addListener(listener); @@ -555,7 +551,6 @@ public final class VersionSetting { obj.addProperty("fullscreen", src.isFullscreen()); obj.addProperty("noJVMArgs", src.isNoJVMArgs()); obj.addProperty("notCheckGame", src.isNotCheckGame()); - obj.addProperty("noCommon", src.isNoCommon()); obj.addProperty("showLogs", src.isShowLogs()); obj.addProperty("gameDir", src.getGameDir()); obj.addProperty("launcherVisibility", src.getLauncherVisibility().ordinal()); @@ -593,7 +588,6 @@ public final class VersionSetting { vs.setFullscreen(Optional.ofNullable(obj.get("fullscreen")).map(JsonElement::getAsBoolean).orElse(false)); vs.setNoJVMArgs(Optional.ofNullable(obj.get("noJVMArgs")).map(JsonElement::getAsBoolean).orElse(false)); vs.setNotCheckGame(Optional.ofNullable(obj.get("notCheckGame")).map(JsonElement::getAsBoolean).orElse(false)); - vs.setNoCommon(Optional.ofNullable(obj.get("noCommon")).map(JsonElement::getAsBoolean).orElse(false)); vs.setShowLogs(Optional.ofNullable(obj.get("showLogs")).map(JsonElement::getAsBoolean).orElse(false)); vs.setLauncherVisibility(LauncherVisibility.values()[Optional.ofNullable(obj.get("launcherVisibility")).map(JsonElement::getAsInt).orElse(1)]); vs.setGameDirType(EnumGameDirectory.values()[Optional.ofNullable(obj.get("gameDirType")).map(JsonElement::getAsInt).orElse(0)]); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java index 3c1274c44..5acc657cc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Decorator.java @@ -69,6 +69,7 @@ import org.jackhuang.hmcl.ui.wizard.*; import org.jackhuang.hmcl.util.Lang; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; @@ -227,7 +228,7 @@ public final class Decorator extends StackPane implements TaskExecutorDialogWiza Bindings.createObjectBinding( () -> { Image image = null; - if (CONFIG.getBackgroundImageType() == EnumBackgroundImage.CUSTOM) { + if (CONFIG.getBackgroundImageType() == EnumBackgroundImage.CUSTOM && CONFIG.getBackgroundImage() != null) { image = tryLoadImage(Paths.get(CONFIG.getBackgroundImage())) .orElse(null); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java index f60a38b3f..8ff2a3d94 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/SettingsPage.java @@ -20,6 +20,7 @@ package org.jackhuang.hmcl.ui; import com.jfoenix.controls.*; import com.jfoenix.effects.JFXDepthManager; import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.beans.binding.When; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; @@ -50,8 +51,10 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.CONFIG; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.net.Proxy; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; +import java.util.Optional; public final class SettingsPage extends StackPane implements DecoratorPage { private final StringProperty title = new SimpleStringProperty(this, "title", i18n("settings.launcher")); @@ -73,7 +76,7 @@ public final class SettingsPage extends StackPane implements DecoratorPage { @FXML private FontComboBox cboFont; @FXML - private FileItem fileCommonLocation; + private MultiFileItem fileCommonLocation; @FXML private Label lblDisplay; @FXML @@ -85,7 +88,7 @@ public final class SettingsPage extends StackPane implements DecoratorPage { @FXML private ScrollPane scroll; @FXML - private MultiFileItem backgroundItem; + private MultiFileItem backgroundItem; @FXML private StackPane themeColorPickerContainer; @FXML @@ -102,7 +105,6 @@ public final class SettingsPage extends StackPane implements DecoratorPage { private Pane proxyPane; private ObjectProperty selectedProxyType; - private ObjectProperty backgroundType; public SettingsPage() { FXUtils.loadFXML(this, "/assets/fxml/setting.fxml"); @@ -182,7 +184,16 @@ public final class SettingsPage extends StackPane implements DecoratorPage { })); // ==== - fileCommonLocation.pathProperty().bindBidirectional(CONFIG.commonDirectoryProperty()); + fileCommonLocation.loadChildren(Arrays.asList( + fileCommonLocation.createChildren(i18n("launcher.common_directory.disabled"), EnumCommonDirectory.DISABLED), + fileCommonLocation.createChildren(i18n("launcher.common_directory.default"), EnumCommonDirectory.DEFAULT) + ), EnumCommonDirectory.CUSTOM); + fileCommonLocation.selectedDataProperty().bindBidirectional(CONFIG.commonDirTypeProperty()); + fileCommonLocation.customTextProperty().bindBidirectional(CONFIG.commonDirectoryProperty()); + fileCommonLocation.subtitleProperty().bind( + Bindings.createObjectBinding(() -> Optional.ofNullable(Settings.INSTANCE.getCommonDirectory()) + .orElse(i18n("launcher.common_directory.disabled")), + CONFIG.commonDirectoryProperty(), CONFIG.commonDirTypeProperty())); FXUtils.installTooltip(btnUpdate, i18n("update.tooltip")); checkUpdate(); @@ -190,28 +201,11 @@ public final class SettingsPage extends StackPane implements DecoratorPage { // ==== Background ==== backgroundItem.loadChildren(Collections.singletonList( backgroundItem.createChildren(i18n("launcher.background.default"), EnumBackgroundImage.DEFAULT) - )); - backgroundItem.setCustomUserData(EnumBackgroundImage.CUSTOM); - backgroundItem.getTxtCustom().textProperty().bindBidirectional(CONFIG.backgroundImageProperty()); - - backgroundType = new SimpleObjectProperty(EnumBackgroundImage.DEFAULT) { - { - invalidated(); - } - - @Override - protected void invalidated() { - backgroundItem.getGroup().getToggles().stream() - .filter(it -> it.getUserData() == get()) - .findFirst() - .ifPresent(it -> it.setSelected(true)); - } - }; - backgroundItem.getGroup().selectedToggleProperty().addListener((observable, oldValue, newValue) -> backgroundType.set((EnumBackgroundImage) newValue.getUserData())); - backgroundType.bindBidirectional(CONFIG.backgroundImageTypeProperty()); - + ), EnumBackgroundImage.CUSTOM); + backgroundItem.customTextProperty().bindBidirectional(CONFIG.backgroundImageProperty()); + backgroundItem.selectedDataProperty().bindBidirectional(CONFIG.backgroundImageTypeProperty()); backgroundItem.subtitleProperty().bind( - new When(backgroundType.isEqualTo(EnumBackgroundImage.DEFAULT)) + new When(backgroundItem.selectedDataProperty().isEqualTo(EnumBackgroundImage.DEFAULT)) .then(i18n("launcher.background.default")) .otherwise(CONFIG.backgroundImageProperty())); // ==== 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..aea799b94 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; @@ -43,6 +44,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import java.io.File; import java.io.IOException; +import java.nio.file.Paths; import java.util.Arrays; import java.util.List; import java.util.logging.Level; @@ -70,11 +72,10 @@ public final class VersionSettingsController { @FXML private JFXCheckBox chkFullscreen; @FXML private Label lblPhysicalMemory; @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) @@ -132,16 +136,19 @@ public final class VersionSettingsController { FXUtils.unbindString(txtServerIP, lastVersionSetting.serverIpProperty()); FXUtils.unbindBoolean(chkFullscreen, lastVersionSetting.fullscreenProperty()); FXUtils.unbindBoolean(chkNoGameCheck, lastVersionSetting.notCheckGameProperty()); - FXUtils.unbindBoolean(chkNoCommon, lastVersionSetting.noCommonProperty()); 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()); @@ -157,19 +164,15 @@ public final class VersionSettingsController { FXUtils.bindString(txtServerIP, versionSetting.serverIpProperty()); FXUtils.bindBoolean(chkFullscreen, versionSetting.fullscreenProperty()); FXUtils.bindBoolean(chkNoGameCheck, versionSetting.notCheckGameProperty()); - FXUtils.bindBoolean(chkNoCommon, versionSetting.noCommonProperty()); FXUtils.bindBoolean(chkNoJVMArgs, versionSetting.noJVMArgsProperty()); FXUtils.bindBoolean(chkShowLogs, versionSetting.showLogsProperty()); FXUtils.bindEnum(cboLauncherVisibility, versionSetting.launcherVisibilityProperty()); 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 +180,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 +195,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(() -> Paths.get(profile.getRepository().getRunDirectory(versionId).getAbsolutePath()).normalize().toString(), + versionSetting.gameDirProperty(), versionSetting.gameDirTypeProperty())); lastVersionSetting = versionSetting; @@ -219,30 +212,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 +230,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..8bcdf8d80 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,12 +161,9 @@ 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 void loadChildren(Collection list, T customUserData) { + loadChildren(list); + setCustomUserData(customUserData); } public ToggleGroup getGroup() { @@ -182,7 +194,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 +237,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); + } } diff --git a/HMCL/src/main/resources/assets/fxml/setting.fxml b/HMCL/src/main/resources/assets/fxml/setting.fxml index 8b069368f..68c87574b 100644 --- a/HMCL/src/main/resources/assets/fxml/setting.fxml +++ b/HMCL/src/main/resources/assets/fxml/setting.fxml @@ -31,7 +31,7 @@ - + diff --git a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml index 7edc20457..8529695fb 100644 --- a/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml +++ b/HMCL/src/main/resources/assets/fxml/version/version-settings.fxml @@ -139,14 +139,6 @@ - - - - - - -