From 5aac4b82fcb15dcc1ec532de1be11a612e166986 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 23 Oct 2024 21:49:35 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20Java=20=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20(#3371)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update * update * update * update --- .../hmcl/ui/main/JavaDownloadDialog.java | 228 +++++++++--------- .../hmcl/download/java/JavaDistribution.java | 7 - .../hmcl/download/java/JavaPackageType.java | 7 + .../java/disco/DiscoFetchJavaListTask.java | 29 +-- .../java/disco/DiscoJavaDistribution.java | 7 - .../java/disco/DiscoJavaRemoteVersion.java | 4 + .../java/mojang/MojangJavaDistribution.java | 9 - 7 files changed, 134 insertions(+), 157 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaDownloadDialog.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaDownloadDialog.java index cb1977547..231be4b2b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaDownloadDialog.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/JavaDownloadDialog.java @@ -21,7 +21,6 @@ import com.jfoenix.controls.*; import javafx.beans.binding.Bindings; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.control.Label; @@ -46,7 +45,6 @@ import org.jackhuang.hmcl.ui.construct.DialogCloseEvent; import org.jackhuang.hmcl.ui.construct.DialogPane; import org.jackhuang.hmcl.ui.construct.JFXHyperlink; import org.jackhuang.hmcl.ui.wizard.SinglePageWizardProvider; -import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.gson.JsonUtils; @@ -56,6 +54,7 @@ import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.CancellationException; +import java.util.function.Consumer; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; import static org.jackhuang.hmcl.util.Lang.resolveException; @@ -118,6 +117,8 @@ public final class JavaDownloadDialog extends StackPane { button.setUserData(version); vbox.getChildren().add(button); toggleGroup.getToggles().add(button); + if (JavaManager.REPOSITORY.isInstalled(platform, version)) + button.setDisable(true); } setBody(vbox); @@ -166,19 +167,6 @@ public final class JavaDownloadDialog extends StackPane { } private final class DownloadDiscoJava extends JFXDialogLayout { - - private boolean isLTS(int major) { - if (major <= 8) { - return true; - } - - if (major < 21) { - return major == 11 || major == 17; - } - - return major % 4 == 1; - } - private final JFXComboBox distributionBox; private final JFXComboBox remoteVersionBox; private final JFXComboBox packageTypeBox; @@ -189,11 +177,8 @@ public final class JavaDownloadDialog extends StackPane { private final DownloadProvider downloadProvider = DownloadProviders.getDownloadProvider(); - private final ObjectProperty currentDiscoJavaVersionList = new SimpleObjectProperty<>(); - - private final Map, DiscoJavaVersionList> javaVersionLists = new HashMap<>(); - - private boolean changingDistribution = false; + private final Map javaVersionLists = new HashMap<>(); + private final ObjectProperty currentJavaVersionList = new SimpleObjectProperty<>(); DownloadDiscoJava() { assert !distributions.isEmpty(); @@ -204,7 +189,7 @@ public final class JavaDownloadDialog extends StackPane { this.remoteVersionBox = new JFXComboBox<>(); this.remoteVersionBox.setConverter(FXUtils.stringConverter(JavaRemoteVersion::getDistributionVersion)); - this.packageTypeBox = new JFXComboBox<>(); + this.packageTypeBox = new JFXComboBox<>(FXCollections.observableArrayList()); this.downloadButton = new JFXButton(i18n("download")); downloadButton.setOnAction(e -> onDownload()); @@ -227,66 +212,91 @@ public final class JavaDownloadDialog extends StackPane { body.addRow(2, new Label(i18n("java.download.packageType")), packageTypeBox); distributionBox.setItems(FXCollections.observableList(new ArrayList<>(distributions))); - ChangeListener updateStatusListener = (observable, oldValue, newValue) -> updateStatus(newValue); - this.currentDiscoJavaVersionList.addListener((observable, oldValue, newValue) -> { - if (oldValue != null) { - oldValue.status.removeListener(updateStatusListener); + + FXUtils.onChange(packageTypeBox.getSelectionModel().selectedItemProperty(), packageType -> { + ObservableList versions; + if (packageType == null + || currentJavaVersionList.get() == null + || (versions = currentJavaVersionList.get().versions.get(packageType)) == null) { + remoteVersionBox.setItems(null); + return; } + remoteVersionBox.setItems(versions); + + for (int i = 0; i < versions.size(); i++) { + DiscoJavaRemoteVersion version = versions.get(i); + if (version.getJdkVersion() == GameJavaVersion.LATEST.getMajorVersion()) { + remoteVersionBox.getSelectionModel().select(i); + return; + } + } + + for (int i = 0; i < versions.size(); i++) { + DiscoJavaRemoteVersion version = versions.get(i); + if (version.isLTS()) { + remoteVersionBox.getSelectionModel().select(i); + return; + } + } + + remoteVersionBox.getSelectionModel().selectFirst(); + }); + + Consumer updateListStatus = list -> { + remoteVersionBox.setItems(null); + packageTypeBox.getItems().clear(); + remoteVersionBox.setDisable(true); + packageTypeBox.setDisable(true); + warningLabel.setText(null); + + if (list == null || (list.versions != null && list.versions.isEmpty())) + downloadButtonPane.getChildren().setAll(downloadButton); + else if (list.status == DiscoJavaVersionList.Status.LOADING) + downloadButtonPane.getChildren().setAll(new JFXSpinner()); + else { + downloadButtonPane.getChildren().setAll(downloadButton); + + if (list.status == DiscoJavaVersionList.Status.SUCCESS) { + packageTypeBox.getItems().setAll(list.versions.keySet()); + packageTypeBox.getSelectionModel().selectFirst(); + + remoteVersionBox.setDisable(false); + packageTypeBox.setDisable(false); + } else + warningLabel.setText(i18n("java.download.load_list.failed")); + } + }; + + currentJavaVersionList.addListener((observable, oldValue, newValue) -> { + if (oldValue != null) + oldValue.listener = null; + if (newValue != null) { - newValue.status.addListener(updateStatusListener); - updateStatus(newValue.status.get()); + updateListStatus.accept(newValue); + + if (newValue.status == DiscoJavaVersionList.Status.LOADING) + newValue.listener = updateListStatus; } else { - updateStatus(null); + currentJavaVersionList.set(null); + updateListStatus.accept(null); } }); - packageTypeBox.getSelectionModel().selectedItemProperty().addListener(ignored -> updateVersions()); - FXUtils.onChangeAndOperate(distributionBox.getSelectionModel().selectedItemProperty(), distribution -> { - if (distribution != null) { - changingDistribution = true; - packageTypeBox.setItems(FXCollections.observableList(new ArrayList<>(distribution.getSupportedPackageTypes()))); - packageTypeBox.getSelectionModel().select(0); - changingDistribution = false; - updateVersions(); - packageTypeBox.setDisable(false); - remoteVersionBox.setDisable(false); - } else { - packageTypeBox.setItems(null); - updateVersions(); - remoteVersionBox.setItems(null); - packageTypeBox.setDisable(true); - remoteVersionBox.setDisable(true); - } - }); + FXUtils.onChange(distributionBox.getSelectionModel().selectedItemProperty(), + it -> currentJavaVersionList.set(getJavaVersionList(it))); setHeading(new Label(i18n("java.download"))); setBody(body); setActions(warningLabel, downloadButtonPane, cancelButton); } - private void updateStatus(DiscoJavaVersionList.Status status) { - if (status == DiscoJavaVersionList.Status.LOADING) { - downloadButtonPane.getChildren().setAll(new JFXSpinner()); - remoteVersionBox.setDisable(true); - warningLabel.setText(null); - } else { - downloadButtonPane.getChildren().setAll(downloadButton); - if (status == DiscoJavaVersionList.Status.SUCCESS || status == null) { - remoteVersionBox.setDisable(false); - warningLabel.setText(null); - } else if (status == DiscoJavaVersionList.Status.FAILED) { - remoteVersionBox.setDisable(true); - warningLabel.setText(i18n("java.download.load_list.failed")); - } - } - } - private void onDownload() { fireEvent(new DialogCloseEvent()); DiscoJavaDistribution distribution = distributionBox.getSelectionModel().getSelectedItem(); DiscoJavaRemoteVersion version = remoteVersionBox.getSelectionModel().getSelectedItem(); + JavaPackageType packageType = packageTypeBox.getSelectionModel().getSelectedItem(); if (version == null) return; @@ -343,7 +353,7 @@ public final class JavaDownloadDialog extends StackPane { if (idx > 0) { javaVersion = javaVersion.substring(0, idx); } - String defaultName = distribution.getApiParameter() + "-" + javaVersion; + String defaultName = distribution.getApiParameter() + "-" + javaVersion + "-" + packageType.name().toLowerCase(Locale.ROOT); Controllers.getDecorator().startWizard(new SinglePageWizardProvider(controller -> new JavaInstallPage(controller::onFinish, info, version, updateInfo, defaultName, result))); } else { @@ -357,65 +367,39 @@ public final class JavaDownloadDialog extends StackPane { } - private void updateVersions() { - if (changingDistribution) return; + private DiscoJavaVersionList getJavaVersionList(DiscoJavaDistribution distribution) { + if (distribution == null) + return null; + return javaVersionLists.computeIfAbsent(distribution, it -> { + DiscoJavaVersionList versionList = new DiscoJavaVersionList(it); + new DiscoFetchJavaListTask(downloadProvider, it, platform).setExecutor(Schedulers.io()).thenApplyAsync(versions -> { + EnumMap> result = new EnumMap<>(JavaPackageType.class); + if (versions.isEmpty()) + return result; - DiscoJavaDistribution distribution = distributionBox.getSelectionModel().getSelectedItem(); - if (distribution == null) { - this.currentDiscoJavaVersionList.set(null); - return; - } + for (Map.Entry> entry : versions.entrySet()) + for (DiscoJavaRemoteVersion version : entry.getValue().values()) + if (version.isLTS() + || version.getJdkVersion() == entry.getValue().lastKey() // latest version + || version.getJdkVersion() == 16) + result.computeIfAbsent(entry.getKey(), ignored -> FXCollections.observableArrayList()) + .add(version); - JavaPackageType packageType = packageTypeBox.getSelectionModel().getSelectedItem(); - - DiscoJavaVersionList list = javaVersionLists.computeIfAbsent(Pair.pair(distribution, packageType), pair -> { - DiscoJavaVersionList res = new DiscoJavaVersionList(); - new DiscoFetchJavaListTask(downloadProvider, distribution, platform, packageType).setExecutor(Schedulers.io()).thenApplyAsync(versions -> { - if (versions.isEmpty()) return Collections.emptyList(); - - int lastLTS = -1; - for (int v : versions.keySet()) { - if (isLTS(v)) { - lastLTS = v; - } - } - - ArrayList remoteVersions = new ArrayList<>(); - for (Map.Entry entry : versions.entrySet()) { - int v = entry.getKey(); - if (v >= lastLTS || isLTS(v) || v == 16) { - remoteVersions.add(entry.getValue()); - } - } - Collections.reverse(remoteVersions); - return remoteVersions; + for (List l : result.values()) + Collections.reverse(l); + return result; }).whenComplete(Schedulers.javafx(), ((result, exception) -> { if (exception == null) { - res.status.set(DiscoJavaVersionList.Status.SUCCESS); - res.versions.setAll(result); - selectLTS(res); + versionList.status = DiscoJavaVersionList.Status.SUCCESS; + versionList.versions = result; } else { LOG.warning("Failed to load java list", exception); - res.status.set(DiscoJavaVersionList.Status.FAILED); + versionList.status = DiscoJavaVersionList.Status.FAILED; } + versionList.invalidate(); })).start(); - return res; + return versionList; }); - this.currentDiscoJavaVersionList.set(list); - this.remoteVersionBox.setItems(list.versions); - selectLTS(list); - } - - private void selectLTS(DiscoJavaVersionList list) { - if (remoteVersionBox.getItems() == list.versions) { - for (int i = 0; i < list.versions.size(); i++) { - JavaRemoteVersion item = list.versions.get(i); - if (item.getJdkVersion() == GameJavaVersion.LATEST.getMajorVersion()) { - remoteVersionBox.getSelectionModel().select(i); - break; - } - } - } } } @@ -424,7 +408,19 @@ public final class JavaDownloadDialog extends StackPane { LOADING, SUCCESS, FAILED } - final ObservableList versions = FXCollections.observableArrayList(); - final ObjectProperty status = new SimpleObjectProperty<>(Status.LOADING); + final DiscoJavaDistribution distribution; + + Status status = Status.LOADING; + EnumMap> versions; + Consumer listener; + + DiscoJavaVersionList(DiscoJavaDistribution distribution) { + this.distribution = distribution; + } + + void invalidate() { + if (listener != null) + listener.accept(this); + } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDistribution.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDistribution.java index f4032bebb..96d02c95c 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDistribution.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaDistribution.java @@ -17,12 +17,7 @@ */ package org.jackhuang.hmcl.download.java; -import org.jackhuang.hmcl.download.DownloadProvider; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.platform.Platform; - import java.util.Set; -import java.util.TreeMap; /** * @author Glavo @@ -31,6 +26,4 @@ public interface JavaDistribution { String getDisplayName(); Set getSupportedPackageTypes(); - - Task> getFetchJavaVersionsTask(DownloadProvider provider, Platform platform, JavaPackageType packageType); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaPackageType.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaPackageType.java index 1512a1705..8fcf4d373 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaPackageType.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/JavaPackageType.java @@ -34,6 +34,13 @@ public enum JavaPackageType { this.javafx = javafx; } + public static JavaPackageType of(boolean jdk, boolean javafx) { + if (jdk) + return javafx ? JDKFX : JDK; + else + return javafx ? JREFX : JRE; + } + public boolean isJDK() { return jdk; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoFetchJavaListTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoFetchJavaListTask.java index adfd14cde..df178fe57 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoFetchJavaListTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoFetchJavaListTask.java @@ -33,7 +33,7 @@ import java.util.*; /** * @author Glavo */ -public final class DiscoFetchJavaListTask extends Task> { +public final class DiscoFetchJavaListTask extends Task>> { public static final String API_ROOT = System.getProperty("hmcl.discoapi.override", "https://api.foojay.io/disco/v3.0"); @@ -46,21 +46,15 @@ public final class DiscoFetchJavaListTask extends Task fetchPackagesTask; - public DiscoFetchJavaListTask(DownloadProvider downloadProvider, DiscoJavaDistribution distribution, Platform platform, JavaPackageType packageType) { + public DiscoFetchJavaListTask(DownloadProvider downloadProvider, DiscoJavaDistribution distribution, Platform platform) { this.distribution = distribution; - this.packageType = packageType.isJDK() ? "jdk" : "jre"; - this.isJavaFXBundled = packageType.isJavaFXBundled(); this.archiveType = platform.getOperatingSystem() == OperatingSystem.WINDOWS ? "zip" : "tar.gz"; HashMap params = new HashMap<>(); params.put("distribution", distribution.getApiParameter()); - params.put("package", this.packageType); - params.put("javafx_bundled", Boolean.toString(isJavaFXBundled)); params.put("operating_system", getOperatingSystemName(platform.getOperatingSystem())); params.put("architecture", getArchitectureName(platform.getArchitecture())); params.put("archive_type", archiveType); @@ -79,29 +73,28 @@ public final class DiscoFetchJavaListTask extends Task result = JsonUtils.fromNonNullJson(json, DiscoResult.typeOf(DiscoJavaRemoteVersion.class)).getResult(); + List list = JsonUtils.fromNonNullJson(json, DiscoResult.typeOf(DiscoJavaRemoteVersion.class)).getResult(); + EnumMap> result = new EnumMap<>(JavaPackageType.class); - TreeMap map = new TreeMap<>(); - - for (DiscoJavaRemoteVersion version : result) { + for (DiscoJavaRemoteVersion version : list) { if (!distribution.getApiParameter().equals(version.getDistribution()) || !version.isDirectlyDownloadable() - || !packageType.equals(version.getPackageType()) - || !archiveType.equals(version.getArchiveType()) - || isJavaFXBundled != version.isJavaFXBundled()) + || !archiveType.equals(version.getArchiveType())) continue; if (!distribution.testVersion(version)) continue; + JavaPackageType packageType = JavaPackageType.of("jdk".equals(version.getPackageType()), version.isJavaFXBundled()); + TreeMap map = result.computeIfAbsent(packageType, ignored -> new TreeMap<>()); + int jdkVersion = version.getJdkVersion(); DiscoJavaRemoteVersion oldVersion = map.get(jdkVersion); - if (oldVersion == null || VersionNumber.compare(version.getDistributionVersion(), oldVersion.getDistributionVersion()) > 0) { + if (oldVersion == null || VersionNumber.compare(version.getDistributionVersion(), oldVersion.getDistributionVersion()) > 0) map.put(jdkVersion, version); - } } - setResult(map); + setResult(result); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaDistribution.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaDistribution.java index 49a5005f3..5a9c696be 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaDistribution.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaDistribution.java @@ -17,10 +17,8 @@ */ package org.jackhuang.hmcl.download.java.disco; -import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.java.JavaDistribution; import org.jackhuang.hmcl.download.java.JavaPackageType; -import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.OperatingSystem; @@ -131,11 +129,6 @@ public enum DiscoJavaDistribution implements JavaDistribution> getFetchJavaVersionsTask(DownloadProvider provider, Platform platform, JavaPackageType packageType) { - return new DiscoFetchJavaListTask(provider, this, platform, packageType); - } - public boolean testVersion(DiscoJavaRemoteVersion version) { return this.getApiParameter().equals(version.getDistribution()); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaRemoteVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaRemoteVersion.java index 6c7448001..ca65643db 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaRemoteVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/disco/DiscoJavaRemoteVersion.java @@ -171,6 +171,10 @@ public final class DiscoJavaRemoteVersion implements JavaRemoteVersion { return termOfSupport; } + public boolean isLTS() { + return "lts".equals(termOfSupport); + } + public String getOperatingSystem() { return operatingSystem; } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDistribution.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDistribution.java index b8de72f72..3f257264f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDistribution.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/java/mojang/MojangJavaDistribution.java @@ -17,16 +17,12 @@ */ package org.jackhuang.hmcl.download.java.mojang; -import org.jackhuang.hmcl.download.DownloadProvider; import org.jackhuang.hmcl.download.java.JavaDistribution; import org.jackhuang.hmcl.download.java.JavaPackageType; import org.jackhuang.hmcl.download.java.JavaRemoteVersion; -import org.jackhuang.hmcl.task.Task; -import org.jackhuang.hmcl.util.platform.Platform; import java.util.Collections; import java.util.Set; -import java.util.TreeMap; /** * @author Glavo @@ -47,9 +43,4 @@ public final class MojangJavaDistribution implements JavaDistribution getSupportedPackageTypes() { return Collections.singleton(JavaPackageType.JRE); } - - @Override - public Task> getFetchJavaVersionsTask(DownloadProvider provider, Platform platform, JavaPackageType packageType) { - return null; - } }