将 org.jackhuang.hmcl.ui 从 java.io.File 迁移至 NIO (#4501)

This commit is contained in:
Glavo
2025-09-17 21:14:16 +08:00
committed by GitHub
parent e9d7d0a33c
commit 77fadf5d28
26 changed files with 214 additions and 177 deletions

View File

@@ -80,8 +80,8 @@ public final class ModpackHelper {
return providers.get(type); return providers.get(type);
} }
public static boolean isFileModpackByExtension(File file) { public static boolean isFileModpackByExtension(Path file) {
String ext = FileUtils.getExtension(file.getName()); String ext = FileUtils.getExtension(file);
return "zip".equals(ext) || "mrpack".equals(ext); return "zip".equals(ext) || "mrpack".equals(ext);
} }

View File

@@ -62,7 +62,7 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.File; import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -92,7 +92,7 @@ public final class Controllers {
gameListPage.selectedProfileProperty().bindBidirectional(Profiles.selectedProfileProperty()); gameListPage.selectedProfileProperty().bindBidirectional(Profiles.selectedProfileProperty());
gameListPage.profilesProperty().bindContent(Profiles.profilesProperty()); gameListPage.profilesProperty().bindContent(Profiles.profilesProperty());
FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> { FXUtils.applyDragListener(gameListPage, ModpackHelper::isFileModpackByExtension, modpacks -> {
File modpack = modpacks.get(0); Path modpack = modpacks.get(0);
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack")); Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), modpack), i18n("install.modpack"));
}); });
return gameListPage; return gameListPage;

View File

@@ -49,9 +49,7 @@ import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle; import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import javafx.scene.text.TextFlow; import javafx.scene.text.TextFlow;
import javafx.stage.FileChooser; import javafx.stage.*;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Callback; import javafx.util.Callback;
import javafx.util.Duration; import javafx.util.Duration;
import javafx.util.StringConverter; import javafx.util.StringConverter;
@@ -87,6 +85,7 @@ import java.lang.ref.WeakReference;
import java.net.*; import java.net.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.List; import java.util.List;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@@ -96,7 +95,6 @@ import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.util.Lang.thread; import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.Lang.tryCast;
@@ -1255,14 +1253,14 @@ public final class FXUtils {
} }
} }
public static void applyDragListener(Node node, FileFilter filter, Consumer<List<File>> callback) { public static void applyDragListener(Node node, PathMatcher filter, Consumer<List<Path>> callback) {
applyDragListener(node, filter, callback, null); applyDragListener(node, filter, callback, null);
} }
public static void applyDragListener(Node node, FileFilter filter, Consumer<List<File>> callback, Runnable dragDropped) { public static void applyDragListener(Node node, PathMatcher filter, Consumer<List<Path>> callback, Runnable dragDropped) {
node.setOnDragOver(event -> { node.setOnDragOver(event -> {
if (event.getGestureSource() != node && event.getDragboard().hasFiles()) { if (event.getGestureSource() != node && event.getDragboard().hasFiles()) {
if (event.getDragboard().getFiles().stream().anyMatch(filter::accept)) if (event.getDragboard().getFiles().stream().map(File::toPath).anyMatch(filter::matches))
event.acceptTransferModes(TransferMode.COPY_OR_MOVE); event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
} }
event.consume(); event.consume();
@@ -1271,7 +1269,7 @@ public final class FXUtils {
node.setOnDragDropped(event -> { node.setOnDragDropped(event -> {
List<File> files = event.getDragboard().getFiles(); List<File> files = event.getDragboard().getFiles();
if (files != null) { if (files != null) {
List<File> acceptFiles = files.stream().filter(filter::accept).collect(Collectors.toList()); List<Path> acceptFiles = files.stream().map(File::toPath).filter(filter::matches).toList();
if (!acceptFiles.isEmpty()) { if (!acceptFiles.isEmpty()) {
callback.accept(acceptFiles); callback.accept(acceptFiles);
event.setDropCompleted(true); event.setDropCompleted(true);
@@ -1451,6 +1449,13 @@ public final class FXUtils {
return String.format("#%02x%02x%02x", r, g, b); return String.format("#%02x%02x%02x", r, g, b);
} }
public static @Nullable List<Path> showOpenMultipleDialog(FileChooser chooser, Window ownerWindow) {
List<File> files = chooser.showOpenMultipleDialog(ownerWindow);
if (files == null)
return null;
return files.stream().map(File::toPath).toList();
}
public static FileChooser.ExtensionFilter getImageExtensionFilter() { public static FileChooser.ExtensionFilter getImageExtensionFilter() {
return new FileChooser.ExtensionFilter(i18n("extension.png"), return new FileChooser.ExtensionFilter(i18n("extension.png"),
IMAGE_EXTENSIONS.stream().map(ext -> "*." + ext).toArray(String[]::new)); IMAGE_EXTENSIONS.stream().map(ext -> "*." + ext).toArray(String[]::new));

View File

@@ -41,13 +41,14 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.DialogController; import org.jackhuang.hmcl.ui.DialogController;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.skin.InvalidSkinException; import org.jackhuang.hmcl.util.skin.InvalidSkinException;
import org.jackhuang.hmcl.util.skin.NormalizedSkin; import org.jackhuang.hmcl.util.skin.NormalizedSkin;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
@@ -116,8 +117,7 @@ public class AccountListItem extends RadioButton {
} }
public ObservableBooleanValue canUploadSkin() { public ObservableBooleanValue canUploadSkin() {
if (account instanceof AuthlibInjectorAccount) { if (account instanceof AuthlibInjectorAccount aiAccount) {
AuthlibInjectorAccount aiAccount = (AuthlibInjectorAccount) account;
ObjectBinding<Optional<CompleteGameProfile>> profile = aiAccount.getYggdrasilService().getProfileRepository().binding(aiAccount.getUUID()); ObjectBinding<Optional<CompleteGameProfile>> profile = aiAccount.getYggdrasilService().getProfileRepository().binding(aiAccount.getUUID());
return createBooleanBinding(() -> { return createBooleanBinding(() -> {
Set<TextureType> uploadableTextures = profile.get() Set<TextureType> uploadableTextures = profile.get()
@@ -148,7 +148,7 @@ public class AccountListItem extends RadioButton {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("account.skin.upload")); chooser.setTitle(i18n("account.skin.upload"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("account.skin.file"), "*.png")); chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("account.skin.file"), "*.png"));
File selectedFile = chooser.showOpenDialog(Controllers.getStage()); Path selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile == null) { if (selectedFile == null) {
return null; return null;
} }
@@ -156,7 +156,7 @@ public class AccountListItem extends RadioButton {
return refreshAsync() return refreshAsync()
.thenRunAsync(() -> { .thenRunAsync(() -> {
Image skinImg; Image skinImg;
try (FileInputStream input = new FileInputStream(selectedFile)) { try (var input = Files.newInputStream(selectedFile)) {
skinImg = new Image(input); skinImg = new Image(input);
} catch (IOException e) { } catch (IOException e) {
throw new InvalidSkinException("Failed to read skin image", e); throw new InvalidSkinException("Failed to read skin image", e);
@@ -167,7 +167,7 @@ public class AccountListItem extends RadioButton {
NormalizedSkin skin = new NormalizedSkin(skinImg); NormalizedSkin skin = new NormalizedSkin(skinImg);
String model = skin.isSlim() ? "slim" : ""; String model = skin.isSlim() ? "slim" : "";
LOG.info("Uploading skin [" + selectedFile + "], model [" + model + "]"); LOG.info("Uploading skin [" + selectedFile + "], model [" + model + "]");
account.uploadSkin(skin.isSlim(), selectedFile.toPath()); account.uploadSkin(skin.isSlim(), selectedFile);
}) })
.thenComposeAsync(refreshAsync()) .thenComposeAsync(refreshAsync())
.whenComplete(Schedulers.javafx(), e -> { .whenComplete(Schedulers.javafx(), e -> {

View File

@@ -39,8 +39,9 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.*; import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.UUID; import java.util.UUID;
@@ -81,16 +82,16 @@ public class OfflineAccountSkinPane extends StackPane {
canvas.addEventHandler(DragEvent.DRAG_OVER, e -> { canvas.addEventHandler(DragEvent.DRAG_OVER, e -> {
if (e.getDragboard().hasFiles()) { if (e.getDragboard().hasFiles()) {
File file = e.getDragboard().getFiles().get(0); Path file = e.getDragboard().getFiles().get(0).toPath();
if (file.getAbsolutePath().endsWith(".png")) if (FileUtils.getName(file).endsWith(".png"))
e.acceptTransferModes(TransferMode.COPY); e.acceptTransferModes(TransferMode.COPY);
} }
}); });
canvas.addEventHandler(DragEvent.DRAG_DROPPED, e -> { canvas.addEventHandler(DragEvent.DRAG_DROPPED, e -> {
if (e.isAccepted()) { if (e.isAccepted()) {
File skin = e.getDragboard().getFiles().get(0); Path skin = e.getDragboard().getFiles().get(0).toPath();
Platform.runLater(() -> { Platform.runLater(() -> {
skinSelector.setValue(skin.getAbsolutePath()); skinSelector.setValue(FileUtils.getAbsolutePath(skin));
skinItem.setSelectedData(Skin.Type.LOCAL_FILE); skinItem.setSelectedData(Skin.Type.LOCAL_FILE);
}); });
} }

View File

@@ -27,17 +27,19 @@ import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.DirectoryChooser; import javafx.stage.DirectoryChooser;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import java.io.File; import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths;
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class FileItem extends BorderPane { public class FileItem extends BorderPane {
private final Label lblPath = new Label(); private final Label lblPath = new Label();
@@ -77,14 +79,14 @@ public class FileItem extends BorderPane {
private String processPath(String path) { private String processPath(String path) {
Path given; Path given;
try { try {
given = Paths.get(path).toAbsolutePath(); given = Path.of(path).toAbsolutePath().normalize();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return path; return path;
} }
if (isConvertToRelativePath()) { if (isConvertToRelativePath()) {
try { try {
return Paths.get(".").normalize().toAbsolutePath().relativize(given).normalize().toString(); return Metadata.CURRENT_DIRECTORY.relativize(given).normalize().toString();
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// the given path can't be relativized against current path // the given path can't be relativized against current path
} }
@@ -95,17 +97,22 @@ public class FileItem extends BorderPane {
public void onExplore() { public void onExplore() {
DirectoryChooser chooser = new DirectoryChooser(); DirectoryChooser chooser = new DirectoryChooser();
if (path.get() != null) { if (path.get() != null) {
File file = new File(path.get()); Path file;
if (file.exists()) { try {
if (file.isFile()) file = Path.of(path.get());
file = file.getAbsoluteFile().getParentFile(); if (Files.exists(file)) {
else if (file.isDirectory()) if (Files.isRegularFile(file))
file = file.getAbsoluteFile(); file = file.toAbsolutePath().normalize().getParent();
chooser.setInitialDirectory(file); else if (Files.isDirectory(file))
file = file.toAbsolutePath().normalize();
chooser.setInitialDirectory(file.toFile());
}
} catch (InvalidPathException e) {
LOG.warning("Failed to resolve path: " + path.get());
} }
} }
chooser.titleProperty().bind(titleProperty()); chooser.titleProperty().bind(titleProperty());
File selectedDir = chooser.showDialog(Controllers.getStage()); var selectedDir = chooser.showDialog(Controllers.getStage());
if (selectedDir != null) { if (selectedDir != null) {
path.set(processPath(selectedDir.toString())); path.set(processPath(selectedDir.toString()));
} }

View File

@@ -31,8 +31,9 @@ import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File; import java.nio.file.Path;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -86,9 +87,9 @@ public class FileSelector extends HBox {
if (directory) { if (directory) {
DirectoryChooser chooser = new DirectoryChooser(); DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle(chooserTitle); chooser.setTitle(chooserTitle);
File dir = chooser.showDialog(Controllers.getStage()); Path dir = FileUtils.toPath(chooser.showDialog(Controllers.getStage()));
if (dir != null) { if (dir != null) {
String path = dir.getAbsolutePath(); String path = FileUtils.getAbsolutePath(dir);
customField.setText(path); customField.setText(path);
value.setValue(path); value.setValue(path);
} }
@@ -96,9 +97,9 @@ public class FileSelector extends HBox {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().addAll(getExtensionFilters()); chooser.getExtensionFilters().addAll(getExtensionFilters());
chooser.setTitle(chooserTitle); chooser.setTitle(chooserTitle);
File file = chooser.showOpenDialog(Controllers.getStage()); Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (file != null) { if (file != null) {
String path = file.getAbsolutePath(); String path = FileUtils.getAbsolutePath(file);
customField.setText(path); customField.setText(path);
value.setValue(path); value.setValue(path);
} }

View File

@@ -40,8 +40,8 @@ import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@@ -82,15 +82,15 @@ public final class LocalModpackPage extends ModpackPage {
btnDescription.setVisible(false); btnDescription.setVisible(false);
File selectedFile; Path selectedFile;
Optional<File> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), File.class); Optional<Path> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), Path.class);
if (filePath.isPresent()) { if (filePath.isPresent()) {
selectedFile = filePath.get(); selectedFile = filePath.get();
} else { } else {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("modpack.choose")); chooser.setTitle(i18n("modpack.choose"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip")); chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
selectedFile = chooser.showOpenDialog(Controllers.getStage()); selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile == null) { if (selectedFile == null) {
controller.onEnd(); controller.onEnd();
return; return;
@@ -100,21 +100,21 @@ public final class LocalModpackPage extends ModpackPage {
} }
showSpinner(); showSpinner();
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile.toPath())) Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile))
.thenApplyAsync(encoding -> { .thenApplyAsync(encoding -> {
charset = encoding; charset = encoding;
manifest = ModpackHelper.readModpackManifest(selectedFile.toPath(), encoding); manifest = ModpackHelper.readModpackManifest(selectedFile, encoding);
return manifest; return manifest;
}) })
.whenComplete(Schedulers.javafx(), (manifest, exception) -> { .whenComplete(Schedulers.javafx(), (manifest, exception) -> {
if (exception instanceof ManuallyCreatedModpackException) { if (exception instanceof ManuallyCreatedModpackException) {
hideSpinner(); hideSpinner();
lblName.setText(selectedFile.getName()); lblName.setText(FileUtils.getName(selectedFile));
installAsVersion.set(false); installAsVersion.set(false);
if (!name.isPresent()) { if (name.isEmpty()) {
// trim: https://github.com/HMCL-dev/HMCL/issues/962 // trim: https://github.com/HMCL-dev/HMCL/issues/962
txtModpackName.setText(FileUtils.getNameWithoutExtension(selectedFile.getName())); txtModpackName.setText(FileUtils.getNameWithoutExtension(selectedFile));
} }
Controllers.confirm(i18n("modpack.type.manual.warning"), i18n("install.modpack"), MessageDialogPane.MessageType.WARNING, Controllers.confirm(i18n("modpack.type.manual.warning"), i18n("install.modpack"), MessageDialogPane.MessageType.WARNING,
@@ -133,7 +133,7 @@ public final class LocalModpackPage extends ModpackPage {
lblVersion.setText(manifest.getVersion()); lblVersion.setText(manifest.getVersion());
lblAuthor.setText(manifest.getAuthor()); lblAuthor.setText(manifest.getAuthor());
if (!name.isPresent()) { if (name.isEmpty()) {
// trim: https://github.com/HMCL-dev/HMCL/issues/962 // trim: https://github.com/HMCL-dev/HMCL/issues/962
txtModpackName.setText(manifest.getName().trim()); txtModpackName.setText(manifest.getName().trim());
} }

View File

@@ -32,26 +32,27 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardProvider; import org.jackhuang.hmcl.ui.wizard.WizardProvider;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Map; import java.util.Map;
import static org.jackhuang.hmcl.util.Lang.tryCast; import static org.jackhuang.hmcl.util.Lang.tryCast;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class ModpackInstallWizardProvider implements WizardProvider { public final class ModpackInstallWizardProvider implements WizardProvider {
private final Profile profile; private final Profile profile;
private final File file; private final Path file;
private final String updateVersion; private final String updateVersion;
public ModpackInstallWizardProvider(Profile profile) { public ModpackInstallWizardProvider(Profile profile) {
this(profile, null, null); this(profile, null, null);
} }
public ModpackInstallWizardProvider(Profile profile, File modpackFile) { public ModpackInstallWizardProvider(Profile profile, Path modpackFile) {
this(profile, modpackFile, null); this(profile, modpackFile, null);
} }
@@ -59,7 +60,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
this(profile, null, updateVersion); this(profile, null, updateVersion);
} }
public ModpackInstallWizardProvider(Profile profile, File modpackFile, String updateVersion) { public ModpackInstallWizardProvider(Profile profile, Path modpackFile, String updateVersion) {
this.profile = profile; this.profile = profile;
this.file = modpackFile; this.file = modpackFile;
this.updateVersion = updateVersion; this.updateVersion = updateVersion;
@@ -75,7 +76,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
} }
private Task<?> finishModpackInstallingAsync(Map<String, Object> settings) { private Task<?> finishModpackInstallingAsync(Map<String, Object> settings) {
File selected = tryCast(settings.get(LocalModpackPage.MODPACK_FILE), File.class).orElse(null); Path selected = tryCast(settings.get(LocalModpackPage.MODPACK_FILE), Path.class).orElse(null);
ServerModpackManifest serverModpackManifest = tryCast(settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST), ServerModpackManifest.class).orElse(null); ServerModpackManifest serverModpackManifest = tryCast(settings.get(RemoteModpackPage.MODPACK_SERVER_MANIFEST), ServerModpackManifest.class).orElse(null);
Modpack modpack = tryCast(settings.get(LocalModpackPage.MODPACK_MANIFEST), Modpack.class).orElse(null); Modpack modpack = tryCast(settings.get(LocalModpackPage.MODPACK_MANIFEST), Modpack.class).orElse(null);
String name = tryCast(settings.get(LocalModpackPage.MODPACK_NAME), String.class).orElse(null); String name = tryCast(settings.get(LocalModpackPage.MODPACK_NAME), String.class).orElse(null);
@@ -83,7 +84,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
boolean isManuallyCreated = tryCast(settings.get(LocalModpackPage.MODPACK_MANUALLY_CREATED), Boolean.class).orElse(false); boolean isManuallyCreated = tryCast(settings.get(LocalModpackPage.MODPACK_MANUALLY_CREATED), Boolean.class).orElse(false);
if (isManuallyCreated) { if (isManuallyCreated) {
return ModpackHelper.getInstallManuallyCreatedModpackTask(profile, selected, name, charset); return ModpackHelper.getInstallManuallyCreatedModpackTask(profile, FileUtils.toFile(selected), name, charset);
} }
if ((selected == null && serverModpackManifest == null) || modpack == null || name == null) return null; if ((selected == null && serverModpackManifest == null) || modpack == null || name == null) return null;
@@ -97,7 +98,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
if (serverModpackManifest != null) { if (serverModpackManifest != null) {
return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile())); return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile()));
} else { } else {
return ModpackHelper.getUpdateTask(profile, selected, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile())); return ModpackHelper.getUpdateTask(profile, selected.toFile(), modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile()));
} }
} catch (UnsupportedModpackException | ManuallyCreatedModpackException e) { } catch (UnsupportedModpackException | ManuallyCreatedModpackException e) {
Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageType.ERROR); Controllers.dialog(i18n("modpack.unsupported"), i18n("message.error"), MessageType.ERROR);
@@ -112,7 +113,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
return ModpackHelper.getInstallTask(profile, serverModpackManifest, name, modpack) return ModpackHelper.getInstallTask(profile, serverModpackManifest, name, modpack)
.thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name));
} else { } else {
return ModpackHelper.getInstallTask(profile, selected, name, modpack) return ModpackHelper.getInstallTask(profile, selected.toFile(), name, modpack)
.thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name)); .thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name));
} }
} }

View File

@@ -38,8 +38,8 @@ import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage; import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -71,14 +71,14 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
createButton("repository", this::onChooseRepository) createButton("repository", this::onChooseRepository)
); );
Optional<File> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), File.class); Optional<Path> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), Path.class);
if (filePath.isPresent()) { if (filePath.isPresent()) {
controller.getSettings().put(MODPACK_FILE, filePath.get()); controller.getSettings().put(MODPACK_FILE, filePath.get());
Platform.runLater(controller::onNext); Platform.runLater(controller::onNext);
} }
FXUtils.applyDragListener(this, ModpackHelper::isFileModpackByExtension, modpacks -> { FXUtils.applyDragListener(this, ModpackHelper::isFileModpackByExtension, modpacks -> {
File modpack = modpacks.get(0); Path modpack = modpacks.get(0);
controller.getSettings().put(MODPACK_FILE, modpack); controller.getSettings().put(MODPACK_FILE, modpack);
controller.onNext(); controller.onNext();
}); });
@@ -112,7 +112,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("modpack.choose")); chooser.setTitle(i18n("modpack.choose"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip", "*.mrpack")); chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip", "*.mrpack"));
File selectedFile = chooser.showOpenDialog(Controllers.getStage()); Path selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile == null) { if (selectedFile == null) {
Platform.runLater(controller::onEnd); Platform.runLater(controller::onEnd);
return; return;
@@ -150,7 +150,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
.whenComplete(Schedulers.javafx(), e -> { .whenComplete(Schedulers.javafx(), e -> {
if (e == null) { if (e == null) {
resolve.run(); resolve.run();
controller.getSettings().put(MODPACK_FILE, modpack.toFile()); controller.getSettings().put(MODPACK_FILE, modpack);
controller.onNext(); controller.onNext();
} else { } else {
reject.accept(e.getMessage()); reject.accept(e.getMessage());

View File

@@ -38,7 +38,6 @@ import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.io.Zipper; import org.jackhuang.hmcl.util.io.Zipper;
import java.io.File;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
@@ -62,7 +61,7 @@ public final class ExportWizardProvider implements WizardProvider {
public Object finish(Map<String, Object> settings) { public Object finish(Map<String, Object> settings) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<String> whitelist = (List<String>) settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION); List<String> whitelist = (List<String>) settings.get(ModpackFileSelectionPage.MODPACK_FILE_SELECTION);
File modpackFile = (File) settings.get(ModpackInfoPage.MODPACK_FILE); Path modpackFile = (Path) settings.get(ModpackInfoPage.MODPACK_FILE);
ModpackExportInfo exportInfo = (ModpackExportInfo) settings.get(ModpackInfoPage.MODPACK_INFO); ModpackExportInfo exportInfo = (ModpackExportInfo) settings.get(ModpackInfoPage.MODPACK_INFO);
exportInfo.setWhitelist(whitelist); exportInfo.setWhitelist(whitelist);
String modpackType = (String) settings.get(ModpackTypeSelectionPage.MODPACK_TYPE); String modpackType = (String) settings.get(ModpackTypeSelectionPage.MODPACK_TYPE);
@@ -70,11 +69,11 @@ public final class ExportWizardProvider implements WizardProvider {
return exportWithLauncher(modpackType, exportInfo, modpackFile); return exportWithLauncher(modpackType, exportInfo, modpackFile);
} }
private Task<?> exportWithLauncher(String modpackType, ModpackExportInfo exportInfo, File modpackFile) { private Task<?> exportWithLauncher(String modpackType, ModpackExportInfo exportInfo, Path modpackFile) {
Path launcherJar = JarUtils.thisJarPath(); Path launcherJar = JarUtils.thisJarPath();
boolean packWithLauncher = exportInfo.isPackWithLauncher() && launcherJar != null; boolean packWithLauncher = exportInfo.isPackWithLauncher() && launcherJar != null;
return new Task<Object>() { return new Task<>() {
File tempModpack; Path tempModpack;
Task<?> exportTask; Task<?> exportTask;
{ {
@@ -88,9 +87,9 @@ public final class ExportWizardProvider implements WizardProvider {
@Override @Override
public void preExecute() throws Exception { public void preExecute() throws Exception {
File dest; Path dest;
if (packWithLauncher) { if (packWithLauncher) {
dest = tempModpack = Files.createTempFile("hmcl", ".zip").toFile(); dest = tempModpack = Files.createTempFile("hmcl", ".zip");
} else { } else {
dest = modpackFile; dest = modpackFile;
} }
@@ -122,7 +121,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override @Override
public void execute() throws Exception { public void execute() throws Exception {
if (!packWithLauncher) return; if (!packWithLauncher) return;
try (Zipper zip = new Zipper(modpackFile.toPath())) { try (Zipper zip = new Zipper(modpackFile)) {
Config exported = new Config(); Config exported = new Config();
exported.setBackgroundImageType(config().getBackgroundImageType()); exported.setBackgroundImageType(config().getBackgroundImageType());
@@ -165,7 +164,7 @@ public final class ExportWizardProvider implements WizardProvider {
}; };
} }
private Task<?> exportAsMcbbs(ModpackExportInfo exportInfo, File modpackFile) { private Task<?> exportAsMcbbs(ModpackExportInfo exportInfo, Path modpackFile) {
return new Task<Void>() { return new Task<Void>() {
Task<?> dependency = null; Task<?> dependency = null;
@@ -175,7 +174,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override @Override
public void execute() { public void execute() {
dependency = new McbbsModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile.toPath()); dependency = new McbbsModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile);
} }
@Override @Override
@@ -185,7 +184,7 @@ public final class ExportWizardProvider implements WizardProvider {
}; };
} }
private Task<?> exportAsMultiMC(ModpackExportInfo exportInfo, File modpackFile) { private Task<?> exportAsMultiMC(ModpackExportInfo exportInfo, Path modpackFile) {
return new Task<Void>() { return new Task<Void>() {
Task<?> dependency; Task<?> dependency;
@@ -223,7 +222,7 @@ public final class ExportWizardProvider implements WizardProvider {
/* overrideCommands */ true, /* overrideCommands */ true,
/* overrideWindow */ true, /* overrideWindow */ true,
/* iconKey */ null // TODO /* iconKey */ null // TODO
), modpackFile.toPath()); ), modpackFile);
} }
@Override @Override
@@ -233,7 +232,7 @@ public final class ExportWizardProvider implements WizardProvider {
}; };
} }
private Task<?> exportAsServer(ModpackExportInfo exportInfo, File modpackFile) { private Task<?> exportAsServer(ModpackExportInfo exportInfo, Path modpackFile) {
return new Task<Void>() { return new Task<Void>() {
Task<?> dependency; Task<?> dependency;
@@ -243,7 +242,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override @Override
public void execute() { public void execute() {
dependency = new ServerModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile.toPath()); dependency = new ServerModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile);
} }
@Override @Override
@@ -253,7 +252,7 @@ public final class ExportWizardProvider implements WizardProvider {
}; };
} }
private Task<?> exportAsModrinth(ModpackExportInfo exportInfo, File modpackFile) { private Task<?> exportAsModrinth(ModpackExportInfo exportInfo, Path modpackFile) {
return new Task<Void>() { return new Task<Void>() {
Task<?> dependency; Task<?> dependency;
@@ -267,7 +266,7 @@ public final class ExportWizardProvider implements WizardProvider {
profile.getRepository(), profile.getRepository(),
version, version,
exportInfo, exportInfo,
modpackFile.toPath() modpackFile
); );
} }
@@ -280,16 +279,12 @@ public final class ExportWizardProvider implements WizardProvider {
@Override @Override
public Node createPage(WizardController controller, int step, Map<String, Object> settings) { public Node createPage(WizardController controller, int step, Map<String, Object> settings) {
switch (step) { return switch (step) {
case 0: case 0 -> new ModpackTypeSelectionPage(controller);
return new ModpackTypeSelectionPage(controller); case 1 -> new ModpackInfoPage(controller, profile.getRepository(), version);
case 1: case 2 -> new ModpackFileSelectionPage(controller, profile, version, ModAdviser::suggestMod);
return new ModpackInfoPage(controller, profile.getRepository(), version); default -> throw new IllegalArgumentException("step");
case 2: };
return new ModpackFileSelectionPage(controller, profile, version, ModAdviser::suggestMod);
default:
throw new IllegalArgumentException("step");
}
} }
@Override @Override

View File

@@ -36,7 +36,9 @@ import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -45,6 +47,7 @@ import java.util.Objects;
import static org.jackhuang.hmcl.util.Lang.mapOf; import static org.jackhuang.hmcl.util.Lang.mapOf;
import static org.jackhuang.hmcl.util.Pair.pair; import static org.jackhuang.hmcl.util.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/** /**
* @author huangyuhui * @author huangyuhui
@@ -61,7 +64,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
this.adviser = adviser; this.adviser = adviser;
JFXTreeView<String> treeView = new JFXTreeView<>(); JFXTreeView<String> treeView = new JFXTreeView<>();
rootNode = getTreeItem(profile.getRepository().getRunDirectory(version).toFile(), "minecraft"); rootNode = getTreeItem(profile.getRepository().getRunDirectory(version), "minecraft");
treeView.setRoot(rootNode); treeView.setRoot(rootNode);
treeView.setSelectionModel(new NoneMultipleSelectionModel<>()); treeView.setSelectionModel(new NoneMultipleSelectionModel<>());
this.setCenter(treeView); this.setCenter(treeView);
@@ -80,15 +83,18 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
this.setBottom(nextPane); this.setBottom(nextPane);
} }
private CheckBoxTreeItem<String> getTreeItem(File file, String basePath) { private CheckBoxTreeItem<String> getTreeItem(Path file, String basePath) {
if (!file.exists()) if (Files.notExists(file))
return null; return null;
boolean isDirectory = Files.isDirectory(file);
ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED; ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED;
if (basePath.length() > "minecraft/".length()) { if (basePath.length() > "minecraft/".length()) {
state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (file.isDirectory() ? "/" : ""), file.isDirectory()); state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (isDirectory ? "/" : ""), isDirectory);
if (file.isFile() && Objects.equals(FileUtils.getNameWithoutExtension(file.getName()), version)) state = ModAdviser.ModSuggestion.HIDDEN; if (!isDirectory && Objects.equals(FileUtils.getNameWithoutExtension(file), version))
if (file.isDirectory() && Objects.equals(file.getName(), version + "-natives")) // Ignore <version>-natives state = ModAdviser.ModSuggestion.HIDDEN;
if (isDirectory && Objects.equals(FileUtils.getName(file), version + "-natives")) // Ignore <version>-natives
state = ModAdviser.ModSuggestion.HIDDEN; state = ModAdviser.ModSuggestion.HIDDEN;
if (state == ModAdviser.ModSuggestion.HIDDEN) if (state == ModAdviser.ModSuggestion.HIDDEN)
return null; return null;
@@ -98,11 +104,10 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
if (state == ModAdviser.ModSuggestion.SUGGESTED) if (state == ModAdviser.ModSuggestion.SUGGESTED)
node.setSelected(true); node.setSelected(true);
if (file.isDirectory()) { if (isDirectory) {
File[] files = file.listFiles(); try (var stream = Files.list(file)) {
if (files != null) { stream.forEach(it -> {
for (File it : files) { CheckBoxTreeItem<String> subNode = getTreeItem(it, basePath + "/" + FileUtils.getName(it));
CheckBoxTreeItem<String> subNode = getTreeItem(it, basePath + "/" + it.getName());
if (subNode != null) { if (subNode != null) {
node.setSelected(subNode.isSelected() || node.isSelected()); node.setSelected(subNode.isSelected() || node.isSelected());
if (!subNode.isSelected()) { if (!subNode.isSelected()) {
@@ -110,8 +115,11 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
} }
node.getChildren().add(subNode); node.getChildren().add(subNode);
} }
});
} catch (IOException e) {
LOG.warning("Failed to list contents of " + file, e);
} }
}
if (!node.isSelected()) node.setIndeterminate(false); if (!node.isSelected()) node.setIndeterminate(false);
// Empty folder need not to be displayed. // Empty folder need not to be displayed.

View File

@@ -42,10 +42,11 @@ import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.wizard.WizardController; import org.jackhuang.hmcl.ui.wizard.WizardController;
import org.jackhuang.hmcl.ui.wizard.WizardPage; import org.jackhuang.hmcl.ui.wizard.WizardPage;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.io.JarUtils;
import org.jackhuang.hmcl.util.platform.SystemInfo; import org.jackhuang.hmcl.util.platform.SystemInfo;
import java.io.File; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -112,7 +113,7 @@ public final class ModpackInfoPage extends Control implements WizardPage {
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip")); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
fileChooser.setInitialFileName(name.get() + ".zip"); fileChooser.setInitialFileName(name.get() + ".zip");
} }
File file = fileChooser.showSaveDialog(Controllers.getStage()); Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (file == null) { if (file == null) {
controller.onEnd(); controller.onEnd();
return; return;

View File

@@ -52,8 +52,9 @@ import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform; import org.jackhuang.hmcl.util.platform.Platform;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.CancellationException; import java.util.concurrent.CancellationException;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -340,8 +341,8 @@ public final class JavaDownloadDialog extends StackPane {
if (StringUtils.isBlank(fileInfo.getDirectDownloadUri())) if (StringUtils.isBlank(fileInfo.getDirectDownloadUri()))
throw new IOException("Missing download URI: " + json); throw new IOException("Missing download URI: " + json);
File targetFile = File.createTempFile("hmcl-java-", "." + version.getArchiveType()); Path targetFile = Files.createTempFile("hmcl-java-", "." + version.getArchiveType());
targetFile.deleteOnExit(); targetFile.toFile().deleteOnExit();
Task<FileDownloadTask.IntegrityCheck> getIntegrityCheck; Task<FileDownloadTask.IntegrityCheck> getIntegrityCheck;
if (StringUtils.isNotBlank(fileInfo.getChecksum())) if (StringUtils.isNotBlank(fileInfo.getChecksum()))
@@ -363,8 +364,8 @@ public final class JavaDownloadDialog extends StackPane {
return getIntegrityCheck return getIntegrityCheck
.thenComposeAsync(integrityCheck -> .thenComposeAsync(integrityCheck ->
new FileDownloadTask(downloadProvider.injectURLWithCandidates(fileInfo.getDirectDownloadUri()), new FileDownloadTask(downloadProvider.injectURLWithCandidates(fileInfo.getDirectDownloadUri()),
targetFile.toPath(), integrityCheck).setName(fileInfo.getFileName())) targetFile, integrityCheck).setName(fileInfo.getFileName()))
.thenSupplyAsync(targetFile::toPath); .thenSupplyAsync(() -> targetFile);
}) })
.whenComplete(Schedulers.javafx(), ((result, exception) -> { .whenComplete(Schedulers.javafx(), ((result, exception) -> {
if (exception == null) { if (exception == null) {

View File

@@ -45,6 +45,7 @@ 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.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.platform.UnsupportedPlatformException; import org.jackhuang.hmcl.util.platform.UnsupportedPlatformException;
import org.jackhuang.hmcl.util.tree.ArchiveFileTree; import org.jackhuang.hmcl.util.tree.ArchiveFileTree;
import org.jackhuang.hmcl.util.platform.Architecture; import org.jackhuang.hmcl.util.platform.Architecture;
@@ -79,19 +80,19 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
} }
FXUtils.applyDragListener(this, it -> { FXUtils.applyDragListener(this, it -> {
String name = it.getName(); String name = FileUtils.getName(it);
return it.isDirectory() || name.endsWith(".zip") || name.endsWith(".tar.gz") || name.equals(OperatingSystem.CURRENT_OS.getJavaExecutable()); return Files.isDirectory(it) || name.endsWith(".zip") || name.endsWith(".tar.gz") || name.equals(OperatingSystem.CURRENT_OS.getJavaExecutable());
}, files -> { }, files -> {
for (File file : files) { for (Path file : files) {
if (file.isDirectory()) { if (Files.isDirectory(file)) {
onAddJavaHome(file.toPath()); onAddJavaHome(file);
} else { } else {
String fileName = file.getName(); String fileName = FileUtils.getName(file);
if (fileName.equals(OperatingSystem.CURRENT_OS.getJavaExecutable())) { if (fileName.equals(OperatingSystem.CURRENT_OS.getJavaExecutable())) {
onAddJavaBinary(file.toPath()); onAddJavaBinary(file);
} else if (fileName.endsWith(".zip") || fileName.endsWith(".tar.gz")) { } else if (fileName.endsWith(".zip") || fileName.endsWith(".tar.gz")) {
onInstallArchive(file.toPath()); onInstallArchive(file);
} else { } else {
throw new AssertionError("Unreachable code"); throw new AssertionError("Unreachable code");
} }

View File

@@ -51,7 +51,8 @@ import org.jackhuang.hmcl.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.CompressingUtils;
import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.File; import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant; import java.time.Instant;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
@@ -92,16 +93,16 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
if (mainPage == null) { if (mainPage == null) {
MainPage mainPage = new MainPage(); MainPage mainPage = new MainPage();
FXUtils.applyDragListener(mainPage, FXUtils.applyDragListener(mainPage,
file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file.toPath()), file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file),
modpacks -> { modpacks -> {
File file = modpacks.get(0); Path file = modpacks.get(0);
if (ModpackHelper.isFileModpackByExtension(file)) { if (ModpackHelper.isFileModpackByExtension(file)) {
Controllers.getDecorator().startWizard( Controllers.getDecorator().startWizard(
new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), file), new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), file),
i18n("install.modpack")); i18n("install.modpack"));
} else if (NBTFileType.isNBTFileByExtension(file.toPath())) { } else if (NBTFileType.isNBTFileByExtension(file)) {
try { try {
Controllers.navigate(new NBTEditorPage(file.toPath())); Controllers.navigate(new NBTEditorPage(file));
} catch (Throwable e) { } catch (Throwable e) {
LOG.warning("Fail to open nbt file", e); LOG.warning("Fail to open nbt file", e);
Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e), Controllers.dialog(i18n("nbt.open.failed") + "\n\n" + StringUtils.getStackTrace(e),
@@ -211,14 +212,13 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
checkedModpack = true; checkedModpack = true;
if (repository.getVersionCount() == 0) { if (repository.getVersionCount() == 0) {
File modpackFile = new File("modpack.zip").getAbsoluteFile(); Path modpackFile = Metadata.CURRENT_DIRECTORY.resolve("modpack.zip");
if (modpackFile.exists()) { if (Files.exists(modpackFile)) {
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath())) Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile))
.thenApplyAsync( .thenApplyAsync(
encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding)) encoding -> ModpackHelper.readModpackManifest(modpackFile, encoding))
.thenApplyAsync(modpack -> ModpackHelper .thenApplyAsync(modpack -> ModpackHelper
.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(), .getInstallTask(repository.getProfile(), modpackFile.toFile(), modpack.getName(), modpack)
modpack)
.executor()) .executor())
.thenAcceptAsync(Schedulers.javafx(), executor -> { .thenAcceptAsync(Schedulers.javafx(), executor -> {
Controllers.taskDialog(executor, i18n("modpack.installing"), TaskCancellationAction.NO_CANCEL); Controllers.taskDialog(executor, i18n("modpack.installing"), TaskCancellationAction.NO_CANCEL);

View File

@@ -29,7 +29,6 @@ import org.jackhuang.hmcl.ui.ListPageBase;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.MappedObservableList; import org.jackhuang.hmcl.util.javafx.MappedObservableList;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List; import java.util.List;
@@ -50,13 +49,13 @@ public final class DatapackListPage extends ListPageBase<DatapackListPageSkin.Da
setItems(MappedObservableList.create(datapack.getInfo(), DatapackListPageSkin.DatapackInfoObject::new)); setItems(MappedObservableList.create(datapack.getInfo(), DatapackListPageSkin.DatapackInfoObject::new));
FXUtils.applyDragListener(this, it -> Objects.equals("zip", FileUtils.getExtension(it.getName())), FXUtils.applyDragListener(this, it -> Objects.equals("zip", FileUtils.getExtension(it)),
mods -> mods.forEach(this::installSingleDatapack), this::refresh); mods -> mods.forEach(this::installSingleDatapack), this::refresh);
} }
private void installSingleDatapack(File datapack) { private void installSingleDatapack(Path datapack) {
try { try {
Datapack zip = new Datapack(datapack.toPath()); Datapack zip = new Datapack(datapack);
zip.loadFromZip(); zip.loadFromZip();
zip.installTo(worldDir); zip.installTo(worldDir);
} catch (IOException | IllegalArgumentException e) { } catch (IOException | IllegalArgumentException e) {
@@ -82,7 +81,7 @@ public final class DatapackListPage extends ListPageBase<DatapackListPageSkin.Da
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("datapack.choose_datapack")); chooser.setTitle(i18n("datapack.choose_datapack"));
chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("datapack.extension"), "*.zip")); chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("datapack.extension"), "*.zip"));
List<File> res = chooser.showOpenMultipleDialog(Controllers.getStage()); List<Path> res = FileUtils.toPaths(chooser.showOpenMultipleDialog(Controllers.getStage()));
if (res != null) if (res != null)
res.forEach(this::installSingleDatapack); res.forEach(this::installSingleDatapack);

View File

@@ -49,11 +49,12 @@ import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.*; import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.i18n.I18n; import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.BindingMapping;
import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -172,14 +173,14 @@ public class DownloadPage extends Control implements DecoratorPage {
fileChooser.setTitle(i18n("button.save_as")); fileChooser.setTitle(i18n("button.save_as"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("file"), "*." + extension)); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("file"), "*." + extension));
fileChooser.setInitialFileName(file.getFile().getFilename()); fileChooser.setInitialFileName(file.getFile().getFilename());
File dest = fileChooser.showSaveDialog(Controllers.getStage()); Path dest = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (dest == null) { if (dest == null) {
return; return;
} }
Controllers.taskDialog( Controllers.taskDialog(
Task.composeAsync(() -> { Task.composeAsync(() -> {
var task = new FileDownloadTask(file.getFile().getUrl(), dest.toPath(), file.getFile().getIntegrityCheck()); var task = new FileDownloadTask(file.getFile().getUrl(), dest, file.getFile().getIntegrityCheck());
task.setName(file.getName()); task.setName(file.getName());
return task; return task;
}), }),

View File

@@ -33,7 +33,7 @@ import org.jackhuang.hmcl.ui.download.UpdateInstallerWizardProvider;
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;
import java.io.File; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -49,7 +49,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
private String gameVersion; private String gameVersion;
{ {
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "exe").contains(FileUtils.getExtension(it.getName())), mods -> { FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "exe").contains(FileUtils.getExtension(it)), mods -> {
if (!mods.isEmpty()) if (!mods.isEmpty())
doInstallOffline(mods.get(0)); doInstallOffline(mods.get(0));
}); });
@@ -137,12 +137,12 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
public void installOffline() { public void installOffline() {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("install.installer.install_offline.extension"), "*.jar", "*.exe")); chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("install.installer.install_offline.extension"), "*.jar", "*.exe"));
File file = chooser.showOpenDialog(Controllers.getStage()); Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (file != null) doInstallOffline(file); if (file != null) doInstallOffline(file);
} }
private void doInstallOffline(File file) { private void doInstallOffline(Path file) {
Task<?> task = profile.getDependency().installLibraryAsync(version, file.toPath()) Task<?> task = profile.getDependency().installLibraryAsync(version, file)
.thenComposeAsync(profile.getRepository()::saveAsync) .thenComposeAsync(profile.getRepository()::saveAsync)
.thenComposeAsync(profile.getRepository().refreshVersionsAsync()); .thenComposeAsync(profile.getRepository().refreshVersionsAsync());
task.setName(i18n("install.installer.install_offline")); task.setName(i18n("install.installer.install_offline"));

View File

@@ -39,9 +39,9 @@ import org.jackhuang.hmcl.ui.construct.PageAware;
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;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -59,10 +59,10 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
private String versionId; private String versionId;
public ModListPage() { public ModListPage() {
FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "zip", "litemod").contains(FileUtils.getExtension(it.getName())), mods -> { FXUtils.applyDragListener(this, it -> Arrays.asList("jar", "zip", "litemod").contains(FileUtils.getExtension(it)), mods -> {
mods.forEach(it -> { mods.forEach(it -> {
try { try {
modManager.addMod(it.toPath()); modManager.addMod(it);
} catch (IOException | IllegalArgumentException e) { } catch (IOException | IllegalArgumentException e) {
LOG.warning("Unable to parse mod file " + it, e); LOG.warning("Unable to parse mod file " + it, e);
} }
@@ -117,7 +117,7 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("mods.choose_mod")); chooser.setTitle(i18n("mods.choose_mod"));
chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("extension.mod"), "*.jar", "*.zip", "*.litemod")); chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("extension.mod"), "*.jar", "*.zip", "*.litemod"));
List<File> res = chooser.showOpenMultipleDialog(Controllers.getStage()); List<Path> res = FileUtils.toPaths(chooser.showOpenMultipleDialog(Controllers.getStage()));
if (res == null) return; if (res == null) return;
@@ -126,13 +126,13 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
List<String> failed = new ArrayList<>(); List<String> failed = new ArrayList<>();
Task.runAsync(() -> { Task.runAsync(() -> {
for (File file : res) { for (Path file : res) {
try { try {
modManager.addMod(file.toPath()); modManager.addMod(file);
succeeded.add(file.getName()); succeeded.add(FileUtils.getName(file));
} catch (Exception e) { } catch (Exception e) {
LOG.warning("Unable to add mod " + file, e); LOG.warning("Unable to add mod " + file, e);
failed.add(file.getName()); failed.add(FileUtils.getName(file));
// Actually addMod will not throw exceptions because FileChooser has already filtered files. // Actually addMod will not throw exceptions because FileChooser has already filtered files.
} }

View File

@@ -45,14 +45,12 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
@@ -76,8 +74,8 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
public SchematicsPage() { public SchematicsPage() {
FXUtils.applyDragListener(this, FXUtils.applyDragListener(this,
file -> currentDirectory != null && file.isFile() && file.getName().endsWith(".litematic"), file -> currentDirectory != null && Files.isRegularFile(file) && FileUtils.getName(file).endsWith(".litematic"),
files -> addFiles(files.stream().map(File::toPath).collect(Collectors.toList())) this::addFiles
); );
} }
@@ -149,9 +147,9 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
fileChooser.setTitle(i18n("schematics.add")); fileChooser.setTitle(i18n("schematics.add"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter( fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(
i18n("schematics"), "*.litematic")); i18n("schematics"), "*.litematic"));
List<File> files = fileChooser.showOpenMultipleDialog(Controllers.getStage()); List<Path> files = FileUtils.toPaths(fileChooser.showOpenMultipleDialog(Controllers.getStage()));
if (files != null && !files.isEmpty()) { if (files != null && !files.isEmpty()) {
addFiles(files.stream().map(File::toPath).collect(Collectors.toList())); addFiles(files);
} }
} }

View File

@@ -31,9 +31,10 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG; import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.DialogPane; import org.jackhuang.hmcl.ui.construct.DialogPane;
import org.jackhuang.hmcl.ui.construct.RipplerContainer; import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path;
import static org.jackhuang.hmcl.util.logging.Logger.LOG; import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -75,10 +76,10 @@ public class VersionIconDialog extends DialogPane {
private void exploreIcon() { private void exploreIcon() {
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().add(FXUtils.getImageExtensionFilter()); chooser.getExtensionFilters().add(FXUtils.getImageExtensionFilter());
File selectedFile = chooser.showOpenDialog(Controllers.getStage()); Path selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile != null) { if (selectedFile != null) {
try { try {
profile.getRepository().setVersionIconFile(versionId, selectedFile.toPath()); profile.getRepository().setVersionIconFile(versionId, selectedFile);
if (vs != null) { if (vs != null) {
vs.setVersionIcon(VersionIconType.DEFAULT); vs.setVersionIcon(VersionIconType.DEFAULT);

View File

@@ -44,7 +44,6 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.OperatingSystem;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.nio.file.Files; import java.nio.file.Files;
@@ -89,9 +88,9 @@ public final class Versions {
.whenComplete(Schedulers.javafx(), e -> { .whenComplete(Schedulers.javafx(), e -> {
if (e == null) { if (e == null) {
if (version != null) { if (version != null) {
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack.toFile(), version)); Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack, version));
} else { } else {
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack.toFile())); Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack));
} }
} else if (e instanceof CancellationException) { } else if (e instanceof CancellationException) {
Controllers.showToast(i18n("message.cancelled")); Controllers.showToast(i18n("message.cancelled"));
@@ -200,9 +199,9 @@ public final class Versions {
? new FileChooser.ExtensionFilter(i18n("extension.bat"), "*.bat") ? new FileChooser.ExtensionFilter(i18n("extension.bat"), "*.bat")
: new FileChooser.ExtensionFilter(i18n("extension.sh"), "*.sh")); : new FileChooser.ExtensionFilter(i18n("extension.sh"), "*.sh"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.ps1"), "*.ps1")); chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("extension.ps1"), "*.ps1"));
File file = chooser.showSaveDialog(Controllers.getStage()); Path file = FileUtils.toPath(chooser.showSaveDialog(Controllers.getStage()));
if (file != null) if (file != null)
new LauncherHelper(profile, account, id).makeLaunchScript(file); new LauncherHelper(profile, account, id).makeLaunchScript(file.toFile());
}); });
} }

View File

@@ -29,8 +29,8 @@ import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType; import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.wizard.SinglePageWizardProvider; import org.jackhuang.hmcl.ui.wizard.SinglePageWizardProvider;
import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.StringUtils;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n; import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@@ -60,12 +60,12 @@ public final class WorldListItem extends Control {
fileChooser.setTitle(i18n("world.export.title")); fileChooser.setTitle(i18n("world.export.title"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip")); fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip"));
fileChooser.setInitialFileName(world.getWorldName()); fileChooser.setInitialFileName(world.getWorldName());
File file = fileChooser.showSaveDialog(Controllers.getStage()); Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (file == null) { if (file == null) {
return; return;
} }
Controllers.getDecorator().startWizard(new SinglePageWizardProvider(controller -> new WorldExportPage(world, file.toPath(), controller::onFinish))); Controllers.getDecorator().startWizard(new SinglePageWizardProvider(controller -> new WorldExportPage(world, file, controller::onFinish)));
} }
public void delete() { public void delete() {

View File

@@ -29,7 +29,6 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.*; import org.jackhuang.hmcl.ui.*;
import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileAlreadyExistsException;
import java.nio.file.InvalidPathException; import java.nio.file.InvalidPathException;
@@ -53,7 +52,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
private String gameVersion; private String gameVersion;
public WorldListPage() { public WorldListPage() {
FXUtils.applyDragListener(this, it -> "zip".equals(FileUtils.getExtension(it.getName())), modpacks -> { FXUtils.applyDragListener(this, it -> "zip".equals(FileUtils.getExtension(it)), modpacks -> {
installWorld(modpacks.get(0)); installWorld(modpacks.get(0));
}); });
@@ -112,7 +111,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
FileChooser chooser = new FileChooser(); FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("world.import.choose")); chooser.setTitle(i18n("world.import.choose"));
chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("world.extension"), "*.zip")); chooser.getExtensionFilters().setAll(new FileChooser.ExtensionFilter(i18n("world.extension"), "*.zip"));
List<File> res = chooser.showOpenMultipleDialog(Controllers.getStage()); List<Path> res = FileUtils.toPaths(chooser.showOpenMultipleDialog(Controllers.getStage()));
if (res == null || res.isEmpty()) return; if (res == null || res.isEmpty()) return;
installWorld(res.get(0)); installWorld(res.get(0));
@@ -123,10 +122,10 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
Controllers.navigate(Controllers.getDownloadPage()); Controllers.navigate(Controllers.getDownloadPage());
} }
private void installWorld(File zipFile) { private void installWorld(Path zipFile) {
// Only accept one world file because user is required to confirm the new world name // Only accept one world file because user is required to confirm the new world name
// Or too many input dialogs are popped. // Or too many input dialogs are popped.
Task.supplyAsync(() -> new World(zipFile.toPath())) Task.supplyAsync(() -> new World(zipFile))
.whenComplete(Schedulers.javafx(), world -> { .whenComplete(Schedulers.javafx(), world -> {
Controllers.prompt(i18n("world.name.enter"), (name, resolve, reject) -> { Controllers.prompt(i18n("world.name.enter"), (name, resolve, reject) -> {
Task.runAsync(() -> world.install(savesDir, name)) Task.runAsync(() -> world.install(savesDir, name))

View File

@@ -26,10 +26,7 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.BufferedWriter; import java.io.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.*; import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
@@ -50,6 +47,28 @@ public final class FileUtils {
private FileUtils() { private FileUtils() {
} }
public static @Nullable Path toPath(@Nullable File file) {
try {
return file != null ? file.toPath() : null;
} catch (InvalidPathException e) {
LOG.warning("Invalid path: " + file);
return null;
}
}
public static @Nullable List<Path> toPaths(@Nullable List<File> files) {
if (files == null) return null;
return files.stream().map(FileUtils::toPath).filter(Objects::nonNull).toList();
}
public static @Nullable File toFile(@Nullable Path file) {
try {
return file != null ? file.toFile() : null;
} catch (UnsupportedOperationException ignored) {
return null;
}
}
public static boolean canCreateDirectory(String path) { public static boolean canCreateDirectory(String path) {
try { try {
return canCreateDirectory(Paths.get(path)); return canCreateDirectory(Paths.get(path));