重构 JavaManagementPage 以使用 ListCell 展示元素 (#5223)

This commit is contained in:
Glavo
2026-01-13 21:35:34 +08:00
committed by GitHub
parent ea407be5f0
commit ccc64db805

View File

@@ -18,17 +18,19 @@
package org.jackhuang.hmcl.ui.main; package org.jackhuang.hmcl.ui.main;
import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import javafx.beans.binding.Bindings; import javafx.beans.binding.Bindings;
import javafx.beans.value.ChangeListener; import javafx.beans.value.ChangeListener;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Node; import javafx.scene.Node;
import javafx.scene.control.Control; import javafx.scene.control.ListCell;
import javafx.scene.control.Skin; import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase; import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.FileChooser; import javafx.stage.FileChooser;
import org.jackhuang.hmcl.java.JavaInfo; import org.jackhuang.hmcl.java.JavaInfo;
import org.jackhuang.hmcl.java.JavaManager; import org.jackhuang.hmcl.java.JavaManager;
@@ -42,6 +44,7 @@ import org.jackhuang.hmcl.ui.construct.MessageDialogPane;
import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.ui.construct.TwoLineListItem;
import org.jackhuang.hmcl.ui.wizard.SinglePageWizardProvider; import org.jackhuang.hmcl.ui.wizard.SinglePageWizardProvider;
import org.jackhuang.hmcl.util.FXThread;
import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.Pair;
import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
@@ -62,7 +65,7 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/** /**
* @author Glavo * @author Glavo
*/ */
public final class JavaManagementPage extends ListPageBase<JavaManagementPage.JavaItem> { public final class JavaManagementPage extends ListPageBase<JavaRuntime> {
@SuppressWarnings("FieldCanBeLocal") @SuppressWarnings("FieldCanBeLocal")
private final ChangeListener<Collection<JavaRuntime>> listener; private final ChangeListener<Collection<JavaRuntime>> listener;
@@ -172,130 +175,17 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
}).start(); }).start();
} }
// FXThread @FXThread
private void loadJava(Collection<JavaRuntime> javaRuntimes) { private void loadJava(Collection<JavaRuntime> javaRuntimes) {
if (javaRuntimes != null) { if (javaRuntimes != null) {
List<JavaItem> items = new ArrayList<>(); this.setItems(FXCollections.observableArrayList(javaRuntimes));
for (JavaRuntime java : javaRuntimes) {
items.add(new JavaItem(java));
}
this.setItems(FXCollections.observableList(items));
this.setLoading(false); this.setLoading(false);
} else } else {
this.setLoading(true); this.setLoading(true);
}
static final class JavaItem extends Control {
private final JavaRuntime java;
public JavaItem(JavaRuntime java) {
this.java = java;
}
public JavaRuntime getJava() {
return java;
}
public void onReveal() {
Path target;
Path parent = java.getBinary().getParent();
if (parent != null
&& parent.getParent() != null
&& parent.getFileName() != null
&& parent.getFileName().toString().equals("bin")
&& Files.exists(parent.getParent().resolve("release"))) {
target = parent.getParent();
} else {
target = java.getBinary();
}
FXUtils.showFileInExplorer(target);
}
public void onRemove() {
if (java.isManaged()) {
Controllers.taskDialog(JavaManager.getUninstallJavaTask(java), i18n("java.uninstall"), TaskCancellationAction.NORMAL);
} else {
String path = java.getBinary().toString();
ConfigHolder.globalConfig().getUserJava().remove(path);
ConfigHolder.globalConfig().getDisabledJava().add(path);
try {
JavaManager.removeJava(java);
} catch (InterruptedException ignored) {
}
}
}
@Override
protected Skin<?> createDefaultSkin() {
return new JavaRuntimeItemSkin(this);
}
}
private static final class JavaRuntimeItemSkin extends SkinBase<JavaItem> {
JavaRuntimeItemSkin(JavaItem control) {
super(control);
JavaRuntime java = control.getJava();
String vendor = JavaInfo.normalizeVendor(java.getVendor());
BorderPane root = new BorderPane();
HBox center = new HBox();
center.setMouseTransparent(true);
center.setSpacing(8);
center.setAlignment(Pos.CENTER_LEFT);
TwoLineListItem item = new TwoLineListItem();
item.setTitle((java.isJDK() ? "JDK" : "JRE") + " " + java.getVersion());
item.setSubtitle(java.getBinary().toString());
item.addTag(i18n("java.info.architecture") + ": " + java.getArchitecture().getDisplayName());
if (vendor != null)
item.addTag(i18n("java.info.vendor") + ": " + vendor);
BorderPane.setAlignment(item, Pos.CENTER);
center.getChildren().setAll(item);
root.setCenter(center);
HBox right = new HBox();
right.setAlignment(Pos.CENTER_RIGHT);
{
JFXButton revealButton = new JFXButton();
revealButton.getStyleClass().add("toggle-icon4");
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(24), 24, 24));
revealButton.setOnAction(e -> control.onReveal());
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
JFXButton removeButton = new JFXButton();
removeButton.getStyleClass().add("toggle-icon4");
removeButton.setOnAction(e -> Controllers.confirm(
java.isManaged() ? i18n("java.uninstall.confirm") : i18n("java.disable.confirm"),
i18n("message.warning"),
control::onRemove,
null
));
if (java.isManaged()) {
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE_FOREVER.createIcon(24), 24, 24));
FXUtils.installFastTooltip(removeButton, i18n("java.uninstall"));
if (JavaRuntime.CURRENT_JAVA != null && java.getBinary().equals(JavaRuntime.CURRENT_JAVA.getBinary()))
removeButton.setDisable(true);
} else {
removeButton.setGraphic(FXUtils.limitingSize(SVG.DELETE.createIcon(24), 24, 24));
FXUtils.installFastTooltip(removeButton, i18n("java.disable"));
}
right.getChildren().setAll(revealButton, removeButton);
}
root.setRight(right);
root.getStyleClass().add("md-list-cell");
root.setPadding(new Insets(8));
getChildren().setAll(new RipplerContainer(root));
} }
} }
private static final class JavaPageSkin extends ToolbarListPageSkin<JavaItem, JavaManagementPage> { private static final class JavaPageSkin extends ToolbarListPageSkin<JavaRuntime, JavaManagementPage> {
JavaPageSkin(JavaManagementPage skinnable) { JavaPageSkin(JavaManagementPage skinnable) {
super(skinnable); super(skinnable);
@@ -317,5 +207,139 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
return res; return res;
} }
@Override
protected ListCell<JavaRuntime> createListCell(JFXListView<JavaRuntime> listView) {
return new JavaItemCell();
}
}
private static final class JavaItemCell extends ListCell<JavaRuntime> {
private final Node graphic;
private final TwoLineListItem content;
private SVG removeIcon;
private final StackPane removeIconPane;
private final Tooltip removeTooltip = new Tooltip();
JavaItemCell() {
BorderPane root = new BorderPane();
HBox center = new HBox();
center.setMouseTransparent(true);
center.setSpacing(8);
center.setAlignment(Pos.CENTER_LEFT);
this.content = new TwoLineListItem();
BorderPane.setAlignment(content, Pos.CENTER);
center.getChildren().setAll(content);
root.setCenter(center);
HBox right = new HBox();
right.setAlignment(Pos.CENTER_RIGHT);
{
JFXButton revealButton = new JFXButton();
revealButton.setGraphic(FXUtils.limitingSize(SVG.FOLDER_OPEN.createIcon(24), 24, 24));
revealButton.getStyleClass().add("toggle-icon4");
revealButton.setOnAction(e -> {
JavaRuntime java = getItem();
if (java != null)
onReveal(java);
});
FXUtils.installFastTooltip(revealButton, i18n("reveal.in_file_manager"));
JFXButton removeButton = new JFXButton();
removeButton.getStyleClass().add("toggle-icon4");
removeButton.setOnAction(e -> {
JavaRuntime java = getItem();
if (java != null)
onRemove(java);
});
FXUtils.installFastTooltip(removeButton, removeTooltip);
this.removeIconPane = new StackPane();
removeIconPane.setAlignment(Pos.CENTER);
FXUtils.setLimitWidth(removeIconPane, 24);
FXUtils.setLimitHeight(removeIconPane, 24);
removeButton.setGraphic(removeIconPane);
right.getChildren().setAll(revealButton, removeButton);
}
root.setRight(right);
root.getStyleClass().add("md-list-cell");
root.setPadding(new Insets(8));
this.graphic = new RipplerContainer(root);
}
@Override
protected void updateItem(JavaRuntime item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
content.setTitle((item.isJDK() ? "JDK" : "JRE") + " " + item.getVersion());
content.setSubtitle(item.getBinary().toString());
content.getTags().clear();
content.addTag(i18n("java.info.architecture") + ": " + item.getArchitecture().getDisplayName());
String vendor = JavaInfo.normalizeVendor(item.getVendor());
if (vendor != null)
content.addTag(i18n("java.info.vendor") + ": " + vendor);
SVG newRemoveIcon = item.isManaged() ? SVG.DELETE_FOREVER : SVG.DELETE;
if (removeIcon != newRemoveIcon) {
removeIcon = newRemoveIcon;
removeIconPane.getChildren().setAll(removeIcon.createIcon(24));
removeTooltip.setText(item.isManaged() ? i18n("java.uninstall") : i18n("java.disable"));
}
setGraphic(graphic);
}
}
private void onReveal(JavaRuntime java) {
Path target;
Path parent = java.getBinary().getParent();
if (parent != null
&& parent.getParent() != null
&& parent.getFileName() != null
&& parent.getFileName().toString().equals("bin")
&& Files.exists(parent.getParent().resolve("release"))) {
target = parent.getParent();
} else {
target = java.getBinary();
}
FXUtils.showFileInExplorer(target);
}
private void onRemove(JavaRuntime java) {
if (java.isManaged()) {
Controllers.confirm(
i18n("java.uninstall.confirm"),
i18n("message.warning"),
() -> Controllers.taskDialog(JavaManager.getUninstallJavaTask(java), i18n("java.uninstall"), TaskCancellationAction.NORMAL),
null
);
} else {
Controllers.confirm(
i18n("java.disable.confirm"),
i18n("message.warning"),
() -> {
String path = java.getBinary().toString();
ConfigHolder.globalConfig().getUserJava().remove(path);
ConfigHolder.globalConfig().getDisabledJava().add(path);
try {
JavaManager.removeJava(java);
} catch (InterruptedException ignored) {
}
},
null
);
}
}
} }
} }