diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java index 4fa82750b49..91708902f60 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java @@ -32,7 +32,10 @@ import org.jackhuang.hmcl.util.CacheRepository; import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.io.FileUtils; -import org.jackhuang.hmcl.util.platform.*; +import org.jackhuang.hmcl.util.platform.Architecture; +import org.jackhuang.hmcl.util.platform.OperatingSystem; +import org.jackhuang.hmcl.util.platform.Platform; +import org.jackhuang.hmcl.util.platform.UnsupportedPlatformException; import org.jackhuang.hmcl.util.platform.windows.WinReg; import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jetbrains.annotations.Nullable; @@ -42,6 +45,7 @@ import java.io.IOException; import java.nio.file.*; import java.util.*; +import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; @@ -174,6 +178,74 @@ public static void refresh() { }).start(); } + public static Task> getSearchAndAddJavaTask(Path directory) { + return new Task>() { + + private final Path dir = directory; + { setName("Search Java"); } + + @Override + public void execute() throws Exception { + setResult(searchJava()); + } + + private List searchJava() throws IOException, InterruptedException { + final int maxDepth = 3; + + final var binaryList = new ArrayList(); + final var queue = new ArrayDeque(64); + try (final var subDirs = Files.list(dir)) { + subDirs.filter(Files::isDirectory).filter(Files::isReadable).forEach(queue::add); + } + final var relative = Paths.get("bin", OperatingSystem.CURRENT_OS.getJavaExecutable()); + queue.add(relative); // relative also as a sign of the end of the layer + int depth = 1; + while (!queue.isEmpty()) { + final Path directory = queue.poll(); + if (directory == relative) { + depth++; + if (!queue.isEmpty() && depth < maxDepth) + queue.add(relative); + continue; + } + if (isCancelled()) + throw new CancellationException("Cancelled by user"); + var binary = directory.resolve(relative); + if (Files.exists(binary)) { + var java = JavaManager.getJava(binary); + if (java.getParsedVersion() <= 8 && java.isJDK()) { + binary = directory.resolve("jre").resolve(relative); + if (Files.exists(binary)) + java = JavaManager.getJava(binary); + } + binaryList.add(java); + } else if (depth < maxDepth) + try (final var subDirs = Files.list(directory)) { + subDirs.filter(Files::isDirectory).filter(Files::isReadable).forEach(queue::add); + } + } + return Collections.unmodifiableList(binaryList); + } + }.thenApplyAsync("Add Java", Schedulers.javafx(), javaRuntimes -> { + final var failedJavaRuntimes = new ArrayList(); + for (JavaRuntime javaRuntime: javaRuntimes) { + if (!JavaManager.isCompatible(javaRuntime.getPlatform())) + failedJavaRuntimes.add(javaRuntime); + String pathString = javaRuntime.getBinary().toString(); + ConfigHolder.globalConfig().getDisabledJava().remove(pathString); + if (ConfigHolder.globalConfig().getUserJava().add(pathString)) + addJava(javaRuntime); + } + if (!failedJavaRuntimes.isEmpty()) { + StringBuilder sb = new StringBuilder("Incompatible platform: "); + for (JavaRuntime javaRuntime :javaRuntimes) + sb.append('\n').append(javaRuntime.getPlatform()).append(": ").append(javaRuntime.getBinary()); + throw new UnsupportedPlatformException(sb.toString()); + } + return javaRuntimes; + }); + } + public static Task getAddJavaTask(Path binary) { return Task.supplyAsync("Get Java", () -> JavaManager.getJava(binary)) .thenApplyAsync(Schedulers.javafx(), javaRuntime -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaManagementPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaManagementPage.java index 50ec4dbae87..99064b237fa 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaManagementPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaManagementPage.java @@ -29,7 +29,7 @@ import javafx.scene.control.SkinBase; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; -import javafx.stage.FileChooser; +import javafx.stage.DirectoryChooser; import org.jackhuang.hmcl.java.JavaInfo; import org.jackhuang.hmcl.java.JavaManager; import org.jackhuang.hmcl.java.JavaRuntime; @@ -107,25 +107,39 @@ protected Skin createDefaultSkin() { } void onAddJava() { - FileChooser chooser = new FileChooser(); - if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) - chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Java", "java.exe")); + final var chooser = new DirectoryChooser(); chooser.setTitle(i18n("settings.game.java_directory.choose")); - Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage())); - if (file != null) { - JavaManager.getAddJavaTask(file).whenComplete(Schedulers.javafx(), exception -> { - if (exception != null) { - LOG.warning("Failed to add java", exception); - Controllers.dialog(i18n("java.add.failed"), i18n("message.error"), MessageDialogPane.MessageType.ERROR); - } - }).start(); + final var dir = FileUtils.toPath(chooser.showDialog(Controllers.getStage())); + if (dir == null) return; + + var file = dir.resolve(OperatingSystem.CURRENT_OS.getJavaExecutable()); + file = Files.exists(file) ? file + : dir.resolve("bin").resolve(OperatingSystem.CURRENT_OS.getJavaExecutable()); + if (Files.exists(file)) { + onAddJavaBinary(file); + return; } + + onSearchAndAddJavaBinary(dir); } void onShowRestoreJavaPage() { Controllers.navigate(new JavaRestorePage(ConfigHolder.globalConfig().getDisabledJava())); } + private void onSearchAndAddJavaBinary(Path directory) { + Controllers.taskDialog( + JavaManager.getSearchAndAddJavaTask(directory).thenAcceptAsync(Schedulers.javafx(), javaRuntimes -> { + if (javaRuntimes.isEmpty()) + Controllers.dialog(i18n("java.add.not_found"), i18n("message.warning"), MessageDialogPane.MessageType.WARNING); + }).whenComplete(Schedulers.javafx(), exception -> { + if (exception instanceof UnsupportedPlatformException) { + LOG.warning("Failed to add java", exception); + Controllers.dialog(i18n("java.add.failed.some"), i18n("message.error"), MessageDialogPane.MessageType.ERROR); + } else if (exception != null) LOG.warning("Other exception when add java", exception); + }), i18n("java.add"), TaskCancellationAction.NORMAL); + } + private void onAddJavaBinary(Path file) { JavaManager.getAddJavaTask(file).whenComplete(Schedulers.javafx(), exception -> { if (exception != null) { diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 823a2eeb20d..1e45b49a4e2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -742,6 +742,8 @@ install.success=Successfully installed. java.add=Add Java java.add.failed=This Java is invalid or incompatible with the current platform. +java.add.failed.some=Some of the found Java is invalid or incompatible with the current platform. +java.add.not_found=Java not found in specified directory, or the Java directory is too deep. java.disable=Disable Java java.disable.confirm=Are you sure you want to disable this Java? java.disabled.management=Disabled Java diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index e457b9bfc38..2d1c0f8b0c2 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -748,6 +748,8 @@ install.success=Instalado con éxito. java.add=Añadir Java java.add.failed=Este Java no es válido o es incompatible con la plataforma actual. +java.add.failed.some=Parte del Java encontrado no es válido o es incompatible con la plataforma actual. +java.add.not_found=Java no se encuentra en el directorio especificado, o el directorio Java es demasiado profundo. java.disable=Deshabilitar este Java java.disable.confirm=¿Está seguro de que desea desactivar este Java? java.disabled.management=Java desactivado diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index e5c9e5e7849..9e37b0b0435 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -465,6 +465,8 @@ install.success=正常にインストールされました java.add=Javaの追加 java.add.failed=このJavaは無効であるか、現在のプラットフォームと互換性がない。 +java.add.failed.some=見つかったJavaのいくつかは無効であるか、現在のプラットフォームと互換性がありません。 +java.add.not_found=指定されたディレクトリにJavaが見つからないか、Javaディレクトリが深すぎます。 java.disable=無効化 java.disable.confirm=本当にこのJavaを無効にしますか? java.disabled.management=無効なJava diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 0cab29cef7f..f813207ad25 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -739,6 +739,8 @@ install.success=Успешно установлено. java.add=Добавить Java java.add.failed=Этот Java недопустим или несовместим с текущей платформой. +java.add.failed.some=Некоторые из найденных Java недопустимы или несовместимы с текущей платформой. +java.add.not_found=Java не найдена в указанном каталоге, или каталог Java находится слишком глубоко. java.disable=Отключить Java java.disable.confirm=Вы уверены, что хотите отключить эту Java? java.disabled.management=Отключенная Java diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 96eeab477e0..16acb05aa4a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -549,6 +549,8 @@ install.success=安裝成功 java.add=添加 Java java.add.failed=Java 無效或與目前平臺不相容 +java.add.failed.some=找到的某些 Java 無效或與目前平臺不相容 +java.add.not_found=在指定目錄中找不到 Java,或 Java 目錄太深。 java.disable=停用此 Java java.disable.confirm=你確定要停用此 Java 嗎? java.disabled.management=管理已停用的 Java diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index 9596687c65b..4fd7578d297 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -559,6 +559,8 @@ install.success=安装成功 java.add=添加 Java java.add.failed=Java 无效或与当前平台不兼容。 +java.add.failed.some=找到的部分 Java 无效或与当前平台不兼容。 +java.add.not_found=在指定目录中找不到 Java,或 Java 目录太深。 java.disable=禁用此 Java java.disable.confirm=你确定要禁用此 Java 吗? java.disabled.management=管理已禁用的 Java