在缺失 javafx.web 的环境使用替代方案 (#1022)

* When WebView is missing, use JEditorPane instead

* Open update log with browser when WebView is missing

* Remove unnecessary prompt messages

* Update error message

* fix: checkstyle

* Add HyperlinkListener to JEditorPane
This commit is contained in:
Glavo 2021-09-12 01:12:50 +08:00 committed by GitHub
parent 2d543e69ff
commit edd4add76e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 73 additions and 30 deletions

View File

@ -33,6 +33,7 @@ import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
@ -44,6 +45,7 @@ import javafx.scene.shape.Rectangle;
import javafx.util.Callback;
import javafx.util.Duration;
import javafx.util.StringConverter;
import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.util.Logging;
import org.jackhuang.hmcl.util.ResourceNotFoundError;
import org.jackhuang.hmcl.util.i18n.I18n;
@ -52,6 +54,9 @@ import org.jackhuang.hmcl.util.javafx.ExtendedProperties;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Constructor;
@ -68,6 +73,7 @@ import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class FXUtils {
@ -427,6 +433,52 @@ public final class FXUtils {
}
}
public static void showWebDialog(String title, String content) {
showWebDialog(title, content, 800, 480);
}
public static void showWebDialog(String title, String content, int width, int height) {
try {
WebStage stage = new WebStage(width, height);
stage.getWebView().getEngine().loadContent(content);
stage.setTitle(title);
stage.showAndWait();
} catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
LOG.log(Level.WARNING, "WebView is missing or initialization failed, use JEditorPane replaced", e);
SwingUtilities.invokeLater(() -> {
final JFrame frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
//noinspection ConstantConditions
frame.setIconImage(new ImageIcon(FXUtils.class.getResource("/assets/img/icon.png")).getImage());
frame.setLayout(new BorderLayout());
final JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
frame.add(progressBar, BorderLayout.PAGE_START);
Schedulers.defaultScheduler().execute(() -> {
final JEditorPane pane = new JEditorPane("text/html", content);
pane.setEditable(false);
pane.addHyperlinkListener(event -> {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
openLink(event.getURL().toExternalForm());
}
});
SwingUtilities.invokeLater(() -> {
progressBar.setVisible(false);
frame.add(new JScrollPane(pane), BorderLayout.CENTER);
});
});
frame.setVisible(true);
frame.toFront();
});
}
}
public static void bindInt(JFXTextField textField, Property<Number> property) {
textField.textProperty().bindBidirectional(property, SafeStringConverter.fromInteger());
}

View File

@ -25,9 +25,12 @@ import javafx.scene.web.WebView;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.ui.construct.DialogCloseEvent;
import java.util.logging.Level;
import static org.jackhuang.hmcl.Metadata.CHANGELOG_URL;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
import static org.jackhuang.hmcl.util.Logging.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class UpgradeDialog extends JFXDialogLayout {
@ -37,17 +40,23 @@ public class UpgradeDialog extends JFXDialogLayout {
}
{
String url = CHANGELOG_URL + config().getUpdateChannel().channelName + ".html";
WebView webView = new WebView();
webView.getEngine().setUserDataDirectory(Metadata.HMCL_DIRECTORY.toFile());
WebEngine engine = webView.getEngine();
engine.load(CHANGELOG_URL + config().getUpdateChannel().channelName);
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
String url = engine.getLoadWorker().getMessage().trim();
if (!url.startsWith(CHANGELOG_URL)) {
engine.getLoadWorker().cancel();
FXUtils.openLink(url);
}
});
try {
WebEngine engine = webView.getEngine();
engine.load(CHANGELOG_URL + config().getUpdateChannel().channelName);
engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
String viewURL = engine.getLoadWorker().getMessage().trim();
if (!viewURL.startsWith(CHANGELOG_URL)) {
engine.getLoadWorker().cancel();
FXUtils.openLink(viewURL);
}
});
} catch (NoClassDefFoundError | UnsatisfiedLinkError e) {
LOG.log(Level.WARNING, "WebView is missing or initialization failed", e);
FXUtils.openLink(url);
}
setBody(webView);
}

View File

@ -34,7 +34,6 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.WebStage;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
@ -156,10 +155,7 @@ public final class LocalModpackPage extends StackPane implements WizardPage {
@FXML
private void onDescribe() {
if (manifest != null) {
WebStage stage = new WebStage();
stage.getWebView().getEngine().loadContent(manifest.getDescription());
stage.setTitle(i18n("modpack.description"));
stage.showAndWait();
FXUtils.showWebDialog(i18n("modpack.description"), manifest.getDescription());
}
}

View File

@ -30,7 +30,6 @@ import org.jackhuang.hmcl.mod.server.ServerModpackManifest;
import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.WebStage;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.RequiredValidator;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
@ -130,10 +129,7 @@ public class RemoteModpackPage extends StackPane implements WizardPage {
@FXML
private void onDescribe() {
WebStage stage = new WebStage();
stage.getWebView().getEngine().loadContent(manifest.getDescription());
stage.setTitle(i18n("modpack.description"));
stage.showAndWait();
FXUtils.showWebDialog(i18n("modpack.description"), manifest.getDescription());
}
@Override

View File

@ -257,14 +257,7 @@ public final class SelfDependencyPatcher {
final JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
final String chooserText;
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.CURRENT == Architecture.ARM) {
chooserText = i18n("repositories.chooser.linux_arm32");
} else {
chooserText = i18n("repositories.chooser");
}
for (String line : chooserText.split("\n")) {
for (String line : i18n("repositories.chooser").split("\n")) {
panel.add(new JLabel(line));
}

View File

@ -572,7 +572,6 @@ repositories.custom=Custom Maven Repository (%s)
repositories.maven_central=Universal (Maven Central)
repositories.aliyun_mirror=Chinese mainland (Aliyun Maven Repository)
repositories.chooser=JavaFX is missing. Do you want to automatically download and load JavaFX runtime components from web?\nSelect 'Yes' to download the JavaFX runtime components from the specified download source and start the HMCL, or select 'No' to exit the program.\nDownload Source:
repositories.chooser.linux_arm32=JavaFX is missing. Do you want to automatically download and load JavaFX runtime components from web?\nSelect 'Yes' to download the JavaFX runtime components from the specified download source and start the HMCL, or select 'No' to exit the program.\nNote: Some components cannot be downloaded temporarily on Linux ARM32 platform, so HMCL may crash at runtime.\nDownload Source:
repositories.chooser.title=Do you want to download JavaFX?
resourcepack=Resource Pack

View File

@ -579,7 +579,6 @@ repositories.custom=自定義 Maven 倉庫(%s
repositories.maven_central=全球Maven Central
repositories.aliyun_mirror=中國大陸(阿里雲 Maven 倉庫)
repositories.chooser=缺少 JavaFX 運行環境。是否需要從網絡下載並加載 JavaFX 運行時組件?\n選擇“是”從指定下載源下載 JavaFX 運行時組件並啟動HMCL選擇“否”退出程式。\n下載源
repositories.chooser.linux_arm32=缺少 JavaFX 運行環境。是否需要從網絡下載並加載 JavaFX 運行時組件?\n選擇“是”從指定下載源下載 JavaFX 運行時組件並啟動HMCL選擇“否”退出程式。\n注意Linux ARM32 平臺下暫時無法下載部分組件運行時可能造成HMCL崩潰。\n下載源
repositories.chooser.title=是否下載 JavaFX
resourcepack=資源包

View File

@ -575,7 +575,6 @@ repositories.custom=自定义 Maven 仓库(%s
repositories.maven_central=全球Maven Central
repositories.aliyun_mirror=中国大陆(阿里云 Maven 仓库)
repositories.chooser=缺少 JavaFX 运行环境,是否需要从网络下载并加载 JavaFX 运行时组件?\n选择“是”从指定下载源下载 JavaFX 运行时组件并启动 HMCL选择“否”退出程序。\n下载源
repositories.chooser.linux_arm32=缺少 JavaFX 运行环境,是否需要从网络下载并加载 JavaFX 运行时组件?\n选择“是”从指定下载源下载 JavaFX 运行时组件并启动 HMCL选择“否”退出程序。\n注意Linux ARM32 平台下暂时无法下载部分组件,运行时可能造成 HMCL 崩溃。\n下载源
repositories.chooser.title=是否下载 JavaFX
resourcepack=资源包