将 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
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 214 additions and 177 deletions

View File

@ -80,8 +80,8 @@ public final class ModpackHelper {
return providers.get(type);
}
public static boolean isFileModpackByExtension(File file) {
String ext = FileUtils.getExtension(file.getName());
public static boolean isFileModpackByExtension(Path file) {
String ext = FileUtils.getExtension(file);
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.OperatingSystem;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@ -92,7 +92,7 @@ public final class Controllers {
gameListPage.selectedProfileProperty().bindBidirectional(Profiles.selectedProfileProperty());
gameListPage.profilesProperty().bindContent(Profiles.profilesProperty());
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"));
});
return gameListPage;

View File

@ -49,9 +49,7 @@ import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.FileChooser;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.*;
import javafx.util.Callback;
import javafx.util.Duration;
import javafx.util.StringConverter;
@ -87,6 +85,7 @@ import java.lang.ref.WeakReference;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.util.List;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@ -96,7 +95,6 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
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.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);
}
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 -> {
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.consume();
@ -1271,7 +1269,7 @@ public final class FXUtils {
node.setOnDragDropped(event -> {
List<File> files = event.getDragboard().getFiles();
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()) {
callback.accept(acceptFiles);
event.setDropCompleted(true);
@ -1451,6 +1449,13 @@ public final class FXUtils {
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() {
return new FileChooser.ExtensionFilter(i18n("extension.png"),
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.DialogController;
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.NormalizedSkin;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CancellationException;
@ -116,8 +117,7 @@ public class AccountListItem extends RadioButton {
}
public ObservableBooleanValue canUploadSkin() {
if (account instanceof AuthlibInjectorAccount) {
AuthlibInjectorAccount aiAccount = (AuthlibInjectorAccount) account;
if (account instanceof AuthlibInjectorAccount aiAccount) {
ObjectBinding<Optional<CompleteGameProfile>> profile = aiAccount.getYggdrasilService().getProfileRepository().binding(aiAccount.getUUID());
return createBooleanBinding(() -> {
Set<TextureType> uploadableTextures = profile.get()
@ -148,7 +148,7 @@ public class AccountListItem extends RadioButton {
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("account.skin.upload"));
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) {
return null;
}
@ -156,7 +156,7 @@ public class AccountListItem extends RadioButton {
return refreshAsync()
.thenRunAsync(() -> {
Image skinImg;
try (FileInputStream input = new FileInputStream(selectedFile)) {
try (var input = Files.newInputStream(selectedFile)) {
skinImg = new Image(input);
} catch (IOException e) {
throw new InvalidSkinException("Failed to read skin image", e);
@ -167,7 +167,7 @@ public class AccountListItem extends RadioButton {
NormalizedSkin skin = new NormalizedSkin(skinImg);
String model = skin.isSlim() ? "slim" : "";
LOG.info("Uploading skin [" + selectedFile + "], model [" + model + "]");
account.uploadSkin(skin.isSlim(), selectedFile.toPath());
account.uploadSkin(skin.isSlim(), selectedFile);
})
.thenComposeAsync(refreshAsync())
.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.FXUtils;
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.UUID;
@ -81,16 +82,16 @@ public class OfflineAccountSkinPane extends StackPane {
canvas.addEventHandler(DragEvent.DRAG_OVER, e -> {
if (e.getDragboard().hasFiles()) {
File file = e.getDragboard().getFiles().get(0);
if (file.getAbsolutePath().endsWith(".png"))
Path file = e.getDragboard().getFiles().get(0).toPath();
if (FileUtils.getName(file).endsWith(".png"))
e.acceptTransferModes(TransferMode.COPY);
}
});
canvas.addEventHandler(DragEvent.DRAG_DROPPED, e -> {
if (e.isAccepted()) {
File skin = e.getDragboard().getFiles().get(0);
Path skin = e.getDragboard().getFiles().get(0).toPath();
Platform.runLater(() -> {
skinSelector.setValue(skin.getAbsolutePath());
skinSelector.setValue(FileUtils.getAbsolutePath(skin));
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.VBox;
import javafx.stage.DirectoryChooser;
import org.jackhuang.hmcl.Metadata;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
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.Paths;
import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
public class FileItem extends BorderPane {
private final Label lblPath = new Label();
@ -77,14 +79,14 @@ public class FileItem extends BorderPane {
private String processPath(String path) {
Path given;
try {
given = Paths.get(path).toAbsolutePath();
given = Path.of(path).toAbsolutePath().normalize();
} catch (IllegalArgumentException e) {
return path;
}
if (isConvertToRelativePath()) {
try {
return Paths.get(".").normalize().toAbsolutePath().relativize(given).normalize().toString();
return Metadata.CURRENT_DIRECTORY.relativize(given).normalize().toString();
} catch (IllegalArgumentException e) {
// the given path can't be relativized against current path
}
@ -95,17 +97,22 @@ public class FileItem extends BorderPane {
public void onExplore() {
DirectoryChooser chooser = new DirectoryChooser();
if (path.get() != null) {
File file = new File(path.get());
if (file.exists()) {
if (file.isFile())
file = file.getAbsoluteFile().getParentFile();
else if (file.isDirectory())
file = file.getAbsoluteFile();
chooser.setInitialDirectory(file);
Path file;
try {
file = Path.of(path.get());
if (Files.exists(file)) {
if (Files.isRegularFile(file))
file = file.toAbsolutePath().normalize().getParent();
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());
File selectedDir = chooser.showDialog(Controllers.getStage());
var selectedDir = chooser.showDialog(Controllers.getStage());
if (selectedDir != null) {
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.FXUtils;
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;
@ -86,9 +87,9 @@ public class FileSelector extends HBox {
if (directory) {
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle(chooserTitle);
File dir = chooser.showDialog(Controllers.getStage());
Path dir = FileUtils.toPath(chooser.showDialog(Controllers.getStage()));
if (dir != null) {
String path = dir.getAbsolutePath();
String path = FileUtils.getAbsolutePath(dir);
customField.setText(path);
value.setValue(path);
}
@ -96,9 +97,9 @@ public class FileSelector extends HBox {
FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().addAll(getExtensionFilters());
chooser.setTitle(chooserTitle);
File file = chooser.showOpenDialog(Controllers.getStage());
Path file = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (file != null) {
String path = file.getAbsolutePath();
String path = FileUtils.getAbsolutePath(file);
customField.setText(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.FileUtils;
import java.io.File;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
@ -82,15 +82,15 @@ public final class LocalModpackPage extends ModpackPage {
btnDescription.setVisible(false);
File selectedFile;
Optional<File> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), File.class);
Path selectedFile;
Optional<Path> filePath = tryCast(controller.getSettings().get(MODPACK_FILE), Path.class);
if (filePath.isPresent()) {
selectedFile = filePath.get();
} else {
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("modpack.choose"));
chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("modpack"), "*.zip"));
selectedFile = chooser.showOpenDialog(Controllers.getStage());
selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile == null) {
controller.onEnd();
return;
@ -100,21 +100,21 @@ public final class LocalModpackPage extends ModpackPage {
}
showSpinner();
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile.toPath()))
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(selectedFile))
.thenApplyAsync(encoding -> {
charset = encoding;
manifest = ModpackHelper.readModpackManifest(selectedFile.toPath(), encoding);
manifest = ModpackHelper.readModpackManifest(selectedFile, encoding);
return manifest;
})
.whenComplete(Schedulers.javafx(), (manifest, exception) -> {
if (exception instanceof ManuallyCreatedModpackException) {
hideSpinner();
lblName.setText(selectedFile.getName());
lblName.setText(FileUtils.getName(selectedFile));
installAsVersion.set(false);
if (!name.isPresent()) {
if (name.isEmpty()) {
// 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,
@ -133,7 +133,7 @@ public final class LocalModpackPage extends ModpackPage {
lblVersion.setText(manifest.getVersion());
lblAuthor.setText(manifest.getAuthor());
if (!name.isPresent()) {
if (name.isEmpty()) {
// trim: https://github.com/HMCL-dev/HMCL/issues/962
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.wizard.WizardController;
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.IOException;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.Map;
import static org.jackhuang.hmcl.util.Lang.tryCast;
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 File file;
private final Path file;
private final String updateVersion;
public ModpackInstallWizardProvider(Profile profile) {
this(profile, null, null);
}
public ModpackInstallWizardProvider(Profile profile, File modpackFile) {
public ModpackInstallWizardProvider(Profile profile, Path modpackFile) {
this(profile, modpackFile, null);
}
@ -59,7 +60,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
this(profile, null, updateVersion);
}
public ModpackInstallWizardProvider(Profile profile, File modpackFile, String updateVersion) {
public ModpackInstallWizardProvider(Profile profile, Path modpackFile, String updateVersion) {
this.profile = profile;
this.file = modpackFile;
this.updateVersion = updateVersion;
@ -75,7 +76,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
}
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);
Modpack modpack = tryCast(settings.get(LocalModpackPage.MODPACK_MANIFEST), Modpack.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);
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;
@ -97,7 +98,7 @@ public class ModpackInstallWizardProvider implements WizardProvider {
if (serverModpackManifest != null) {
return ModpackHelper.getUpdateTask(profile, serverModpackManifest, modpack.getEncoding(), name, ModpackHelper.readModpackConfiguration(profile.getRepository().getModpackConfiguration(name).toFile()));
} 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) {
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)
.thenRunAsync(Schedulers.javafx(), () -> profile.setSelectedVersion(name));
} else {
return ModpackHelper.getInstallTask(profile, selected, name, modpack)
return ModpackHelper.getInstallTask(profile, selected.toFile(), name, modpack)
.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.util.TaskCancellationAction;
import org.jackhuang.hmcl.util.gson.JsonUtils;
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;
@ -71,14 +71,14 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
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()) {
controller.getSettings().put(MODPACK_FILE, filePath.get());
Platform.runLater(controller::onNext);
}
FXUtils.applyDragListener(this, ModpackHelper::isFileModpackByExtension, modpacks -> {
File modpack = modpacks.get(0);
Path modpack = modpacks.get(0);
controller.getSettings().put(MODPACK_FILE, modpack);
controller.onNext();
});
@ -112,7 +112,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("modpack.choose"));
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) {
Platform.runLater(controller::onEnd);
return;
@ -150,7 +150,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage {
.whenComplete(Schedulers.javafx(), e -> {
if (e == null) {
resolve.run();
controller.getSettings().put(MODPACK_FILE, modpack.toFile());
controller.getSettings().put(MODPACK_FILE, modpack);
controller.onNext();
} else {
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.Zipper;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
@ -62,7 +61,7 @@ public final class ExportWizardProvider implements WizardProvider {
public Object finish(Map<String, Object> settings) {
@SuppressWarnings("unchecked")
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);
exportInfo.setWhitelist(whitelist);
String modpackType = (String) settings.get(ModpackTypeSelectionPage.MODPACK_TYPE);
@ -70,11 +69,11 @@ public final class ExportWizardProvider implements WizardProvider {
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();
boolean packWithLauncher = exportInfo.isPackWithLauncher() && launcherJar != null;
return new Task<Object>() {
File tempModpack;
return new Task<>() {
Path tempModpack;
Task<?> exportTask;
{
@ -88,9 +87,9 @@ public final class ExportWizardProvider implements WizardProvider {
@Override
public void preExecute() throws Exception {
File dest;
Path dest;
if (packWithLauncher) {
dest = tempModpack = Files.createTempFile("hmcl", ".zip").toFile();
dest = tempModpack = Files.createTempFile("hmcl", ".zip");
} else {
dest = modpackFile;
}
@ -122,7 +121,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override
public void execute() throws Exception {
if (!packWithLauncher) return;
try (Zipper zip = new Zipper(modpackFile.toPath())) {
try (Zipper zip = new Zipper(modpackFile)) {
Config exported = new Config();
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>() {
Task<?> dependency = null;
@ -175,7 +174,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override
public void execute() {
dependency = new McbbsModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile.toPath());
dependency = new McbbsModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile);
}
@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>() {
Task<?> dependency;
@ -223,7 +222,7 @@ public final class ExportWizardProvider implements WizardProvider {
/* overrideCommands */ true,
/* overrideWindow */ true,
/* iconKey */ null // TODO
), modpackFile.toPath());
), modpackFile);
}
@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>() {
Task<?> dependency;
@ -243,7 +242,7 @@ public final class ExportWizardProvider implements WizardProvider {
@Override
public void execute() {
dependency = new ServerModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile.toPath());
dependency = new ServerModpackExportTask(profile.getRepository(), version, exportInfo, modpackFile);
}
@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>() {
Task<?> dependency;
@ -267,7 +266,7 @@ public final class ExportWizardProvider implements WizardProvider {
profile.getRepository(),
version,
exportInfo,
modpackFile.toPath()
modpackFile
);
}
@ -280,16 +279,12 @@ public final class ExportWizardProvider implements WizardProvider {
@Override
public Node createPage(WizardController controller, int step, Map<String, Object> settings) {
switch (step) {
case 0:
return new ModpackTypeSelectionPage(controller);
case 1:
return new ModpackInfoPage(controller, profile.getRepository(), version);
case 2:
return new ModpackFileSelectionPage(controller, profile, version, ModAdviser::suggestMod);
default:
throw new IllegalArgumentException("step");
}
return switch (step) {
case 0 -> new ModpackTypeSelectionPage(controller);
case 1 -> new ModpackInfoPage(controller, profile.getRepository(), version);
case 2 -> new ModpackFileSelectionPage(controller, profile, version, ModAdviser::suggestMod);
default -> throw new IllegalArgumentException("step");
};
}
@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.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.List;
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.Pair.pair;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
/**
* @author huangyuhui
@ -61,7 +64,7 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
this.adviser = adviser;
JFXTreeView<String> treeView = new JFXTreeView<>();
rootNode = getTreeItem(profile.getRepository().getRunDirectory(version).toFile(), "minecraft");
rootNode = getTreeItem(profile.getRepository().getRunDirectory(version), "minecraft");
treeView.setRoot(rootNode);
treeView.setSelectionModel(new NoneMultipleSelectionModel<>());
this.setCenter(treeView);
@ -80,15 +83,18 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
this.setBottom(nextPane);
}
private CheckBoxTreeItem<String> getTreeItem(File file, String basePath) {
if (!file.exists())
private CheckBoxTreeItem<String> getTreeItem(Path file, String basePath) {
if (Files.notExists(file))
return null;
boolean isDirectory = Files.isDirectory(file);
ModAdviser.ModSuggestion state = ModAdviser.ModSuggestion.SUGGESTED;
if (basePath.length() > "minecraft/".length()) {
state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (file.isDirectory() ? "/" : ""), file.isDirectory());
if (file.isFile() && Objects.equals(FileUtils.getNameWithoutExtension(file.getName()), version)) state = ModAdviser.ModSuggestion.HIDDEN;
if (file.isDirectory() && Objects.equals(file.getName(), version + "-natives")) // Ignore <version>-natives
state = adviser.advise(StringUtils.substringAfter(basePath, "minecraft/") + (isDirectory ? "/" : ""), isDirectory);
if (!isDirectory && Objects.equals(FileUtils.getNameWithoutExtension(file), version))
state = ModAdviser.ModSuggestion.HIDDEN;
if (isDirectory && Objects.equals(FileUtils.getName(file), version + "-natives")) // Ignore <version>-natives
state = ModAdviser.ModSuggestion.HIDDEN;
if (state == ModAdviser.ModSuggestion.HIDDEN)
return null;
@ -98,11 +104,10 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
if (state == ModAdviser.ModSuggestion.SUGGESTED)
node.setSelected(true);
if (file.isDirectory()) {
File[] files = file.listFiles();
if (files != null) {
for (File it : files) {
CheckBoxTreeItem<String> subNode = getTreeItem(it, basePath + "/" + it.getName());
if (isDirectory) {
try (var stream = Files.list(file)) {
stream.forEach(it -> {
CheckBoxTreeItem<String> subNode = getTreeItem(it, basePath + "/" + FileUtils.getName(it));
if (subNode != null) {
node.setSelected(subNode.isSelected() || node.isSelected());
if (!subNode.isSelected()) {
@ -110,8 +115,11 @@ public final class ModpackFileSelectionPage extends BorderPane implements Wizard
}
node.getChildren().add(subNode);
}
}
});
} catch (IOException e) {
LOG.warning("Failed to list contents of " + file, e);
}
if (!node.isSelected()) node.setIndeterminate(false);
// 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.WizardPage;
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.platform.SystemInfo;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
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.setInitialFileName(name.get() + ".zip");
}
File file = fileChooser.showSaveDialog(Controllers.getStage());
Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (file == null) {
controller.onEnd();
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.Platform;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CancellationException;
import java.util.function.Consumer;
@ -340,8 +341,8 @@ public final class JavaDownloadDialog extends StackPane {
if (StringUtils.isBlank(fileInfo.getDirectDownloadUri()))
throw new IOException("Missing download URI: " + json);
File targetFile = File.createTempFile("hmcl-java-", "." + version.getArchiveType());
targetFile.deleteOnExit();
Path targetFile = Files.createTempFile("hmcl-java-", "." + version.getArchiveType());
targetFile.toFile().deleteOnExit();
Task<FileDownloadTask.IntegrityCheck> getIntegrityCheck;
if (StringUtils.isNotBlank(fileInfo.getChecksum()))
@ -363,8 +364,8 @@ public final class JavaDownloadDialog extends StackPane {
return getIntegrityCheck
.thenComposeAsync(integrityCheck ->
new FileDownloadTask(downloadProvider.injectURLWithCandidates(fileInfo.getDirectDownloadUri()),
targetFile.toPath(), integrityCheck).setName(fileInfo.getFileName()))
.thenSupplyAsync(targetFile::toPath);
targetFile, integrityCheck).setName(fileInfo.getFileName()))
.thenSupplyAsync(() -> targetFile);
})
.whenComplete(Schedulers.javafx(), ((result, exception) -> {
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.util.Pair;
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.tree.ArchiveFileTree;
import org.jackhuang.hmcl.util.platform.Architecture;
@ -79,19 +80,19 @@ public final class JavaManagementPage extends ListPageBase<JavaManagementPage.Ja
}
FXUtils.applyDragListener(this, it -> {
String name = it.getName();
return it.isDirectory() || name.endsWith(".zip") || name.endsWith(".tar.gz") || name.equals(OperatingSystem.CURRENT_OS.getJavaExecutable());
String name = FileUtils.getName(it);
return Files.isDirectory(it) || name.endsWith(".zip") || name.endsWith(".tar.gz") || name.equals(OperatingSystem.CURRENT_OS.getJavaExecutable());
}, files -> {
for (File file : files) {
if (file.isDirectory()) {
onAddJavaHome(file.toPath());
for (Path file : files) {
if (Files.isDirectory(file)) {
onAddJavaHome(file);
} else {
String fileName = file.getName();
String fileName = FileUtils.getName(file);
if (fileName.equals(OperatingSystem.CURRENT_OS.getJavaExecutable())) {
onAddJavaBinary(file.toPath());
onAddJavaBinary(file);
} else if (fileName.endsWith(".zip") || fileName.endsWith(".tar.gz")) {
onInstallArchive(file.toPath());
onInstallArchive(file);
} else {
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.versioning.VersionNumber;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.Comparator;
import java.util.List;
@ -92,16 +93,16 @@ public class RootPage extends DecoratorAnimatedPage implements DecoratorPage {
if (mainPage == null) {
MainPage mainPage = new MainPage();
FXUtils.applyDragListener(mainPage,
file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file.toPath()),
file -> ModpackHelper.isFileModpackByExtension(file) || NBTFileType.isNBTFileByExtension(file),
modpacks -> {
File file = modpacks.get(0);
Path file = modpacks.get(0);
if (ModpackHelper.isFileModpackByExtension(file)) {
Controllers.getDecorator().startWizard(
new ModpackInstallWizardProvider(Profiles.getSelectedProfile(), file),
i18n("install.modpack"));
} else if (NBTFileType.isNBTFileByExtension(file.toPath())) {
} else if (NBTFileType.isNBTFileByExtension(file)) {
try {
Controllers.navigate(new NBTEditorPage(file.toPath()));
Controllers.navigate(new NBTEditorPage(file));
} catch (Throwable e) {
LOG.warning("Fail to open nbt file", 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;
if (repository.getVersionCount() == 0) {
File modpackFile = new File("modpack.zip").getAbsoluteFile();
if (modpackFile.exists()) {
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile.toPath()))
Path modpackFile = Metadata.CURRENT_DIRECTORY.resolve("modpack.zip");
if (Files.exists(modpackFile)) {
Task.supplyAsync(() -> CompressingUtils.findSuitableEncoding(modpackFile))
.thenApplyAsync(
encoding -> ModpackHelper.readModpackManifest(modpackFile.toPath(), encoding))
encoding -> ModpackHelper.readModpackManifest(modpackFile, encoding))
.thenApplyAsync(modpack -> ModpackHelper
.getInstallTask(repository.getProfile(), modpackFile, modpack.getName(),
modpack)
.getInstallTask(repository.getProfile(), modpackFile.toFile(), modpack.getName(), modpack)
.executor())
.thenAcceptAsync(Schedulers.javafx(), executor -> {
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.javafx.MappedObservableList;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
@ -50,13 +49,13 @@ public final class DatapackListPage extends ListPageBase<DatapackListPageSkin.Da
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);
}
private void installSingleDatapack(File datapack) {
private void installSingleDatapack(Path datapack) {
try {
Datapack zip = new Datapack(datapack.toPath());
Datapack zip = new Datapack(datapack);
zip.loadFromZip();
zip.installTo(worldDir);
} catch (IOException | IllegalArgumentException e) {
@ -82,7 +81,7 @@ public final class DatapackListPage extends ListPageBase<DatapackListPageSkin.Da
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("datapack.choose_datapack"));
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)
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.util.*;
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.versioning.GameVersionNumber;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -172,14 +173,14 @@ public class DownloadPage extends Control implements DecoratorPage {
fileChooser.setTitle(i18n("button.save_as"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("file"), "*." + extension));
fileChooser.setInitialFileName(file.getFile().getFilename());
File dest = fileChooser.showSaveDialog(Controllers.getStage());
Path dest = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (dest == null) {
return;
}
Controllers.taskDialog(
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());
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.io.FileUtils;
import java.io.File;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -49,7 +49,7 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
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())
doInstallOffline(mods.get(0));
});
@ -137,12 +137,12 @@ public class InstallerListPage extends ListPageBase<InstallerItem> implements Ve
public void installOffline() {
FileChooser chooser = new FileChooser();
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);
}
private void doInstallOffline(File file) {
Task<?> task = profile.getDependency().installLibraryAsync(version, file.toPath())
private void doInstallOffline(Path file) {
Task<?> task = profile.getDependency().installLibraryAsync(version, file)
.thenComposeAsync(profile.getRepository()::saveAsync)
.thenComposeAsync(profile.getRepository().refreshVersionsAsync());
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.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@ -59,10 +59,10 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
private String versionId;
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 -> {
try {
modManager.addMod(it.toPath());
modManager.addMod(it);
} catch (IOException | IllegalArgumentException 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();
chooser.setTitle(i18n("mods.choose_mod"));
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;
@ -126,13 +126,13 @@ public final class ModListPage extends ListPageBase<ModListPageSkin.ModInfoObjec
List<String> failed = new ArrayList<>();
Task.runAsync(() -> {
for (File file : res) {
for (Path file : res) {
try {
modManager.addMod(file.toPath());
succeeded.add(file.getName());
modManager.addMod(file);
succeeded.add(FileUtils.getName(file));
} catch (Exception 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.
}

View File

@ -45,14 +45,12 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
@ -76,8 +74,8 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
public SchematicsPage() {
FXUtils.applyDragListener(this,
file -> currentDirectory != null && file.isFile() && file.getName().endsWith(".litematic"),
files -> addFiles(files.stream().map(File::toPath).collect(Collectors.toList()))
file -> currentDirectory != null && Files.isRegularFile(file) && FileUtils.getName(file).endsWith(".litematic"),
this::addFiles
);
}
@ -149,9 +147,9 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
fileChooser.setTitle(i18n("schematics.add"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(
i18n("schematics"), "*.litematic"));
List<File> files = fileChooser.showOpenMultipleDialog(Controllers.getStage());
List<Path> files = FileUtils.toPaths(fileChooser.showOpenMultipleDialog(Controllers.getStage()));
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.construct.DialogPane;
import org.jackhuang.hmcl.ui.construct.RipplerContainer;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
@ -75,10 +76,10 @@ public class VersionIconDialog extends DialogPane {
private void exploreIcon() {
FileChooser chooser = new FileChooser();
chooser.getExtensionFilters().add(FXUtils.getImageExtensionFilter());
File selectedFile = chooser.showOpenDialog(Controllers.getStage());
Path selectedFile = FileUtils.toPath(chooser.showOpenDialog(Controllers.getStage()));
if (selectedFile != null) {
try {
profile.getRepository().setVersionIconFile(versionId, selectedFile.toPath());
profile.getRepository().setVersionIconFile(versionId, selectedFile);
if (vs != null) {
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.platform.OperatingSystem;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
@ -89,9 +88,9 @@ public final class Versions {
.whenComplete(Schedulers.javafx(), e -> {
if (e == null) {
if (version != null) {
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack.toFile(), version));
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack, version));
} else {
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack.toFile()));
Controllers.getDecorator().startWizard(new ModpackInstallWizardProvider(profile, modpack));
}
} else if (e instanceof CancellationException) {
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.sh"), "*.sh"));
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)
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.wizard.SinglePageWizardProvider;
import org.jackhuang.hmcl.util.StringUtils;
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;
@ -60,12 +60,12 @@ public final class WorldListItem extends Control {
fileChooser.setTitle(i18n("world.export.title"));
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(i18n("world"), "*.zip"));
fileChooser.setInitialFileName(world.getWorldName());
File file = fileChooser.showSaveDialog(Controllers.getStage());
Path file = FileUtils.toPath(fileChooser.showSaveDialog(Controllers.getStage()));
if (file == null) {
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() {

View File

@ -29,7 +29,6 @@ import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.ui.*;
import org.jackhuang.hmcl.util.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.InvalidPathException;
@ -53,7 +52,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
private String gameVersion;
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));
});
@ -112,7 +111,7 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
FileChooser chooser = new FileChooser();
chooser.setTitle(i18n("world.import.choose"));
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;
installWorld(res.get(0));
@ -123,10 +122,10 @@ public final class WorldListPage extends ListPageBase<WorldListItem> implements
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
// Or too many input dialogs are popped.
Task.supplyAsync(() -> new World(zipFile.toPath()))
Task.supplyAsync(() -> new World(zipFile))
.whenComplete(Schedulers.javafx(), world -> {
Controllers.prompt(i18n("world.name.enter"), (name, resolve, reject) -> {
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.Nullable;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.time.ZonedDateTime;
@ -50,6 +47,28 @@ public final class 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) {
try {
return canCreateDirectory(Paths.get(path));