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 a5592e6a9b..59720ab5fd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/java/JavaManager.java @@ -45,8 +45,10 @@ import java.io.InputStreamReader; import java.nio.file.*; import java.util.*; +import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.jackhuang.hmcl.util.logging.Logger.LOG; @@ -176,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; + + List binaryList = new ArrayList<>(); + Queue queue = new ArrayDeque<>(64); + try(Stream subDirs = Files.list(dir)) { + subDirs.filter(Files::isDirectory).filter(Files::isReadable).forEach(queue::add); + } + final Path 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"); + Path binary = directory.resolve(relative); + if(Files.exists(binary)) { + JavaRuntime 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(Stream subDirs = Files.list(directory)) { + subDirs.filter(Files::isDirectory).filter(Files::isReadable).forEach(queue::add); + } + } + return Collections.unmodifiableList(binaryList); + } + }.thenApplyAsync("Add Java", Schedulers.javafx(), javaRuntimes -> { + ArrayList 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 6eb9c2d450..e34c66e596 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; @@ -106,25 +106,40 @@ 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 DirectoryChooser chooser = new DirectoryChooser(); chooser.setTitle(i18n("settings.game.java_directory.choose")); - File file = chooser.showOpenDialog(Controllers.getStage()); - if (file != null) { - JavaManager.getAddJavaTask(file.toPath()).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(); + File dir = chooser.showDialog(Controllers.getStage()); + if(dir == null) return; + Path directory = dir.toPath(); + + Path file = directory.resolve(OperatingSystem.CURRENT_OS.getJavaExecutable()); + file = Files.exists(file)? file + : directory.resolve("bin").resolve(OperatingSystem.CURRENT_OS.getJavaExecutable()); + if(Files.exists(file)) { + onAddJavaBinary(file); + return; } + + onSearchAndAddJavaBinary(directory); } void onShowRestoreJavaPage() { Controllers.navigate(new JavaRestorePage(ConfigHolder.globalConfig().getDisabledJava())); } + private void onSearchAndAddJavaBinary(Path directory) { + Task task = 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); + }); + Controllers.taskDialog(task, 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 79f5b8394b..4122eb918a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -705,6 +705,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 20122a125d..812d7ef21a 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -600,6 +600,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 170d0c691f..ecbc27002e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -462,6 +462,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 15f88033d9..40384385fa 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -480,6 +480,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 4058fadbfb..bc417935b1 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -519,6 +519,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 a521d602fd..5a81f84280 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -530,6 +530,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