mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-12 05:16:13 -04:00
Refactor ModListPage and InstallerListPage
This commit is contained in:
parent
d8a34aac1c
commit
daa1a38a63
@ -17,7 +17,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui;
|
package org.jackhuang.hmcl.ui;
|
||||||
|
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
import javafx.beans.property.ListProperty;
|
import javafx.beans.property.ListProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
import javafx.beans.property.SimpleListProperty;
|
import javafx.beans.property.SimpleListProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
@ -26,6 +28,7 @@ import javafx.scene.control.Skin;
|
|||||||
|
|
||||||
public abstract class ListPage<T extends Node> extends Control {
|
public abstract class ListPage<T extends Node> extends Control {
|
||||||
private final ListProperty<T> items = new SimpleListProperty<>(FXCollections.observableArrayList());
|
private final ListProperty<T> items = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||||
|
private final BooleanProperty loading = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
public abstract void add();
|
public abstract void add();
|
||||||
|
|
||||||
@ -33,6 +36,10 @@ public abstract class ListPage<T extends Node> extends Control {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BooleanProperty loadingProperty() {
|
||||||
|
return loading;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Skin<?> createDefaultSkin() {
|
protected Skin<?> createDefaultSkin() {
|
||||||
return new ListPageSkin(this);
|
return new ListPageSkin(this);
|
||||||
|
@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXScrollPane;
|
import com.jfoenix.controls.JFXScrollPane;
|
||||||
|
import com.jfoenix.controls.JFXSpinner;
|
||||||
import javafx.beans.binding.Bindings;
|
import javafx.beans.binding.Bindings;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
@ -33,43 +34,57 @@ public class ListPageSkin extends SkinBase<ListPage> {
|
|||||||
public ListPageSkin(ListPage<?> skinnable) {
|
public ListPageSkin(ListPage<?> skinnable) {
|
||||||
super(skinnable);
|
super(skinnable);
|
||||||
|
|
||||||
StackPane root = new StackPane();
|
StackPane rootPane = new StackPane();
|
||||||
|
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
JFXSpinner spinner = new JFXSpinner();
|
||||||
|
spinner.setRadius(16);
|
||||||
|
spinner.getStyleClass().setAll("materialDesign-purple", "first-spinner");
|
||||||
|
|
||||||
|
StackPane contentPane = new StackPane();
|
||||||
{
|
{
|
||||||
scrollPane.setFitToWidth(true);
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
{
|
||||||
|
scrollPane.setFitToWidth(true);
|
||||||
|
|
||||||
VBox accountList = new VBox();
|
VBox accountList = new VBox();
|
||||||
accountList.maxWidthProperty().bind(scrollPane.widthProperty());
|
accountList.maxWidthProperty().bind(scrollPane.widthProperty());
|
||||||
accountList.setSpacing(10);
|
accountList.setSpacing(10);
|
||||||
accountList.setStyle("-fx-padding: 10 10 10 10;");
|
accountList.setStyle("-fx-padding: 10 10 10 10;");
|
||||||
|
|
||||||
Bindings.bindContent(accountList.getChildren(), skinnable.itemsProperty());
|
Bindings.bindContent(accountList.getChildren(), skinnable.itemsProperty());
|
||||||
|
|
||||||
scrollPane.setContent(accountList);
|
scrollPane.setContent(accountList);
|
||||||
JFXScrollPane.smoothScrolling(scrollPane);
|
JFXScrollPane.smoothScrolling(scrollPane);
|
||||||
|
}
|
||||||
|
|
||||||
|
VBox vBox = new VBox();
|
||||||
|
{
|
||||||
|
vBox.setAlignment(Pos.BOTTOM_RIGHT);
|
||||||
|
vBox.setPickOnBounds(false);
|
||||||
|
vBox.setPadding(new Insets(15));
|
||||||
|
vBox.setSpacing(15);
|
||||||
|
|
||||||
|
JFXButton btnAdd = new JFXButton();
|
||||||
|
FXUtils.setLimitWidth(btnAdd, 40);
|
||||||
|
FXUtils.setLimitHeight(btnAdd, 40);
|
||||||
|
btnAdd.getStyleClass().setAll("jfx-button-raised-round");
|
||||||
|
btnAdd.setButtonType(JFXButton.ButtonType.RAISED);
|
||||||
|
btnAdd.setGraphic(SVG.plus(Theme.whiteFillBinding(), -1, -1));
|
||||||
|
btnAdd.setOnMouseClicked(e -> skinnable.add());
|
||||||
|
|
||||||
|
vBox.getChildren().setAll(btnAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
contentPane.getChildren().setAll(scrollPane, vBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
VBox vBox = new VBox();
|
rootPane.getChildren().setAll(contentPane);
|
||||||
{
|
|
||||||
vBox.setAlignment(Pos.BOTTOM_RIGHT);
|
|
||||||
vBox.setPickOnBounds(false);
|
|
||||||
vBox.setPadding(new Insets(15));
|
|
||||||
vBox.setSpacing(15);
|
|
||||||
|
|
||||||
JFXButton btnAdd = new JFXButton();
|
skinnable.loadingProperty().addListener((a, b, newValue) -> {
|
||||||
FXUtils.setLimitWidth(btnAdd, 40);
|
if (newValue) rootPane.getChildren().setAll(spinner);
|
||||||
FXUtils.setLimitHeight(btnAdd, 40);
|
else rootPane.getChildren().setAll(contentPane);
|
||||||
btnAdd.getStyleClass().setAll("jfx-button-raised-round");
|
});
|
||||||
btnAdd.setButtonType(JFXButton.ButtonType.RAISED);
|
|
||||||
btnAdd.setGraphic(SVG.plus(Theme.whiteFillBinding(), -1, -1));
|
|
||||||
btnAdd.setOnMouseClicked(e -> skinnable.add());
|
|
||||||
|
|
||||||
vBox.getChildren().setAll(btnAdd);
|
getChildren().setAll(rootPane);
|
||||||
}
|
|
||||||
|
|
||||||
root.getChildren().setAll(scrollPane, vBox);
|
|
||||||
|
|
||||||
getChildren().setAll(root);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.ui.versions;
|
package org.jackhuang.hmcl.ui.versions;
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
import org.jackhuang.hmcl.download.LibraryAnalyzer;
|
||||||
import org.jackhuang.hmcl.download.MaintainTask;
|
import org.jackhuang.hmcl.download.MaintainTask;
|
||||||
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
import org.jackhuang.hmcl.download.game.VersionJsonSaveTask;
|
||||||
@ -30,8 +27,8 @@ import org.jackhuang.hmcl.setting.Profile;
|
|||||||
import org.jackhuang.hmcl.task.Schedulers;
|
import org.jackhuang.hmcl.task.Schedulers;
|
||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
import org.jackhuang.hmcl.ui.Controllers;
|
import org.jackhuang.hmcl.ui.Controllers;
|
||||||
import org.jackhuang.hmcl.ui.FXUtils;
|
|
||||||
import org.jackhuang.hmcl.ui.InstallerItem;
|
import org.jackhuang.hmcl.ui.InstallerItem;
|
||||||
|
import org.jackhuang.hmcl.ui.ListPage;
|
||||||
import org.jackhuang.hmcl.ui.download.InstallerWizardProvider;
|
import org.jackhuang.hmcl.ui.download.InstallerWizardProvider;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -41,26 +38,16 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class InstallerController {
|
public class InstallerListPage extends ListPage<InstallerItem> {
|
||||||
private Profile profile;
|
private Profile profile;
|
||||||
private String versionId;
|
private String versionId;
|
||||||
private Version version;
|
private Version version;
|
||||||
@FXML
|
|
||||||
private ScrollPane scrollPane;
|
|
||||||
@FXML private VBox contentPane;
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
private void initialize() {
|
|
||||||
FXUtils.smoothScrolling(scrollPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadVersion(Profile profile, String versionId) {
|
public void loadVersion(Profile profile, String versionId) {
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
this.versionId = versionId;
|
this.versionId = versionId;
|
||||||
this.version = profile.getRepository().getResolvedVersion(versionId);
|
this.version = profile.getRepository().getResolvedVersion(versionId);
|
||||||
|
|
||||||
contentPane.getChildren().clear();
|
|
||||||
|
|
||||||
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
LibraryAnalyzer analyzer = LibraryAnalyzer.analyze(version);
|
||||||
|
|
||||||
Function<Library, Consumer<InstallerItem>> removeAction = library -> x -> {
|
Function<Library, Consumer<InstallerItem>> removeAction = library -> x -> {
|
||||||
@ -73,13 +60,13 @@ public class InstallerController {
|
|||||||
.start();
|
.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
analyzer.getForge().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("Forge", library.getVersion(), removeAction.apply(library))));
|
analyzer.getForge().ifPresent(library -> itemsProperty().add(new InstallerItem("Forge", library.getVersion(), removeAction.apply(library))));
|
||||||
analyzer.getLiteLoader().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction.apply(library))));
|
analyzer.getLiteLoader().ifPresent(library -> itemsProperty().add(new InstallerItem("LiteLoader", library.getVersion(), removeAction.apply(library))));
|
||||||
analyzer.getOptiFine().ifPresent(library -> contentPane.getChildren().add(new InstallerItem("OptiFine", library.getVersion(), removeAction.apply(library))));
|
analyzer.getOptiFine().ifPresent(library -> itemsProperty().add(new InstallerItem("OptiFine", library.getVersion(), removeAction.apply(library))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@Override
|
||||||
private void onAdd() {
|
public void add() {
|
||||||
Optional<String> gameVersion = GameVersion.minecraftVersion(profile.getRepository().getVersionJar(version));
|
Optional<String> gameVersion = GameVersion.minecraftVersion(profile.getRepository().getVersionJar(version));
|
||||||
|
|
||||||
if (!gameVersion.isPresent())
|
if (!gameVersion.isPresent())
|
@ -18,13 +18,8 @@
|
|||||||
package org.jackhuang.hmcl.ui.versions;
|
package org.jackhuang.hmcl.ui.versions;
|
||||||
|
|
||||||
import com.jfoenix.concurrency.JFXUtilities;
|
import com.jfoenix.concurrency.JFXUtilities;
|
||||||
import com.jfoenix.controls.JFXSpinner;
|
|
||||||
import com.jfoenix.controls.JFXTabPane;
|
import com.jfoenix.controls.JFXTabPane;
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.scene.control.ScrollPane;
|
|
||||||
import javafx.scene.input.TransferMode;
|
import javafx.scene.input.TransferMode;
|
||||||
import javafx.scene.layout.StackPane;
|
|
||||||
import javafx.scene.layout.VBox;
|
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.mod.ModInfo;
|
import org.jackhuang.hmcl.mod.ModInfo;
|
||||||
import org.jackhuang.hmcl.mod.ModManager;
|
import org.jackhuang.hmcl.mod.ModManager;
|
||||||
@ -32,6 +27,7 @@ import org.jackhuang.hmcl.task.Schedulers;
|
|||||||
import org.jackhuang.hmcl.task.Task;
|
import org.jackhuang.hmcl.task.Task;
|
||||||
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.ListPage;
|
||||||
import org.jackhuang.hmcl.ui.ModItem;
|
import org.jackhuang.hmcl.ui.ModItem;
|
||||||
import org.jackhuang.hmcl.util.FileUtils;
|
import org.jackhuang.hmcl.util.FileUtils;
|
||||||
import org.jackhuang.hmcl.util.Logging;
|
import org.jackhuang.hmcl.util.Logging;
|
||||||
@ -47,32 +43,20 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public final class ModController {
|
public final class ModListPage extends ListPage<ModItem> {
|
||||||
@FXML
|
|
||||||
private ScrollPane scrollPane;
|
|
||||||
|
|
||||||
@FXML private StackPane rootPane;
|
|
||||||
|
|
||||||
@FXML private VBox modPane;
|
|
||||||
|
|
||||||
@FXML private StackPane contentPane;
|
|
||||||
@FXML private JFXSpinner spinner;
|
|
||||||
|
|
||||||
private JFXTabPane parentTab;
|
private JFXTabPane parentTab;
|
||||||
private ModManager modManager;
|
private ModManager modManager;
|
||||||
private String versionId;
|
private String versionId;
|
||||||
|
|
||||||
@FXML
|
public ModListPage() {
|
||||||
private void initialize() {
|
setOnDragOver(event -> {
|
||||||
FXUtils.smoothScrolling(scrollPane);
|
if (event.getGestureSource() != this && event.getDragboard().hasFiles())
|
||||||
|
|
||||||
rootPane.setOnDragOver(event -> {
|
|
||||||
if (event.getGestureSource() != rootPane && event.getDragboard().hasFiles())
|
|
||||||
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
|
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
|
||||||
event.consume();
|
event.consume();
|
||||||
});
|
});
|
||||||
|
|
||||||
rootPane.setOnDragDropped(event -> {
|
setOnDragDropped(event -> {
|
||||||
List<File> files = event.getDragboard().getFiles();
|
List<File> files = event.getDragboard().getFiles();
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
Collection<File> mods = files.stream()
|
Collection<File> mods = files.stream()
|
||||||
@ -98,11 +82,8 @@ public final class ModController {
|
|||||||
this.modManager = modManager;
|
this.modManager = modManager;
|
||||||
this.versionId = versionId;
|
this.versionId = versionId;
|
||||||
Task.of(variables -> {
|
Task.of(variables -> {
|
||||||
synchronized (ModController.this) {
|
synchronized (ModListPage.this) {
|
||||||
JFXUtilities.runInFX(() -> {
|
JFXUtilities.runInFX(() -> loadingProperty().set(true));
|
||||||
rootPane.getChildren().remove(contentPane);
|
|
||||||
spinner.setVisible(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
modManager.refreshMods(versionId);
|
modManager.refreshMods(versionId);
|
||||||
|
|
||||||
@ -130,18 +111,17 @@ public final class ModController {
|
|||||||
variables.set("list", list);
|
variables.set("list", list);
|
||||||
}
|
}
|
||||||
}).finalized(Schedulers.javafx(), (variables, isDependentsSucceeded) -> {
|
}).finalized(Schedulers.javafx(), (variables, isDependentsSucceeded) -> {
|
||||||
rootPane.getChildren().add(contentPane);
|
loadingProperty().set(false);
|
||||||
spinner.setVisible(false);
|
|
||||||
if (isDependentsSucceeded)
|
if (isDependentsSucceeded)
|
||||||
FXUtils.onWeakChangeAndOperate(parentTab.getSelectionModel().selectedItemProperty(), newValue -> {
|
FXUtils.onWeakChangeAndOperate(parentTab.getSelectionModel().selectedItemProperty(), newValue -> {
|
||||||
if (newValue != null && newValue.getUserData() == ModController.this)
|
if (newValue != null && newValue.getUserData() == ModListPage.this)
|
||||||
modPane.getChildren().setAll(variables.<List<ModItem>>get("list"));
|
itemsProperty().setAll(variables.<List<ModItem>>get("list"));
|
||||||
});
|
});
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@Override
|
||||||
private void onAdd() {
|
public void add() {
|
||||||
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"));
|
@ -44,9 +44,9 @@ public final class VersionPage extends StackPane implements DecoratorPage {
|
|||||||
@FXML
|
@FXML
|
||||||
private Tab modTab;
|
private Tab modTab;
|
||||||
@FXML
|
@FXML
|
||||||
private ModController modController;
|
private ModListPage mod;
|
||||||
@FXML
|
@FXML
|
||||||
private InstallerController installerController;
|
private InstallerListPage installer;
|
||||||
@FXML
|
@FXML
|
||||||
private JFXListView<?> browseList;
|
private JFXListView<?> browseList;
|
||||||
@FXML
|
@FXML
|
||||||
@ -93,10 +93,10 @@ public final class VersionPage extends StackPane implements DecoratorPage {
|
|||||||
title.set(i18n("settings.game") + " - " + id);
|
title.set(i18n("settings.game") + " - " + id);
|
||||||
|
|
||||||
versionSettings.loadVersionSetting(profile, id);
|
versionSettings.loadVersionSetting(profile, id);
|
||||||
modController.setParentTab(tabPane);
|
mod.setParentTab(tabPane);
|
||||||
modTab.setUserData(modController);
|
modTab.setUserData(mod);
|
||||||
modController.loadMods(profile.getModManager(), id);
|
mod.loadMods(profile.getModManager(), id);
|
||||||
installerController.loadVersion(profile, id);
|
installer.loadVersion(profile, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
|
||||||
<?import javafx.scene.control.ScrollPane?>
|
|
||||||
<?import javafx.scene.layout.StackPane?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<StackPane xmlns="http://javafx.com/javafx"
|
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
|
||||||
fx:controller="org.jackhuang.hmcl.ui.versions.InstallerController">
|
|
||||||
<ScrollPane fx:id="scrollPane" fitToWidth="true" fitToHeight="true">
|
|
||||||
<VBox fx:id="contentPane" spacing="10" style="-fx-padding: 20;">
|
|
||||||
|
|
||||||
</VBox>
|
|
||||||
</ScrollPane>
|
|
||||||
<VBox style="-fx-padding: 15;" spacing="15" pickOnBounds="false" alignment="BOTTOM_RIGHT">
|
|
||||||
<JFXButton prefWidth="40" prefHeight="40" buttonType="RAISED" onMouseClicked="#onAdd" styleClass="jfx-button-raised-round">
|
|
||||||
<graphic>
|
|
||||||
<fx:include source="/assets/svg/plus.fxml" />
|
|
||||||
</graphic>
|
|
||||||
</JFXButton>
|
|
||||||
</VBox>
|
|
||||||
</StackPane>
|
|
@ -1,27 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<?import com.jfoenix.controls.JFXButton?>
|
|
||||||
<?import com.jfoenix.controls.JFXSpinner?>
|
|
||||||
<?import javafx.scene.control.ScrollPane?>
|
|
||||||
<?import javafx.scene.layout.StackPane?>
|
|
||||||
<?import javafx.scene.layout.VBox?>
|
|
||||||
<StackPane xmlns="http://javafx.com/javafx"
|
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
|
||||||
fx:id="rootPane"
|
|
||||||
fx:controller="org.jackhuang.hmcl.ui.versions.ModController">
|
|
||||||
<JFXSpinner fx:id="spinner" style="-fx-radius:16" styleClass="materialDesign-purple, first-spinner" />
|
|
||||||
<StackPane fx:id="contentPane">
|
|
||||||
<ScrollPane fx:id="scrollPane" fitToWidth="true" fitToHeight="true">
|
|
||||||
<VBox fx:id="modPane" spacing="10" style="-fx-padding: 20 20 70 20;">
|
|
||||||
|
|
||||||
</VBox>
|
|
||||||
</ScrollPane>
|
|
||||||
<VBox style="-fx-padding: 15;" spacing="15" pickOnBounds="false" alignment="BOTTOM_RIGHT">
|
|
||||||
<JFXButton prefWidth="40" prefHeight="40" buttonType="RAISED" onMouseClicked="#onAdd" styleClass="jfx-button-raised-round">
|
|
||||||
<graphic>
|
|
||||||
<fx:include source="/assets/svg/plus.fxml"/>
|
|
||||||
</graphic>
|
|
||||||
</JFXButton>
|
|
||||||
</VBox>
|
|
||||||
</StackPane>
|
|
||||||
</StackPane>
|
|
@ -5,6 +5,8 @@
|
|||||||
<?import javafx.scene.layout.HBox?>
|
<?import javafx.scene.layout.HBox?>
|
||||||
<?import javafx.scene.layout.StackPane?>
|
<?import javafx.scene.layout.StackPane?>
|
||||||
<?import org.jackhuang.hmcl.ui.versions.VersionSettingsPage?>
|
<?import org.jackhuang.hmcl.ui.versions.VersionSettingsPage?>
|
||||||
|
<?import org.jackhuang.hmcl.ui.versions.ModListPage?>
|
||||||
|
<?import org.jackhuang.hmcl.ui.versions.InstallerListPage?>
|
||||||
<fx:root xmlns="http://javafx.com/javafx"
|
<fx:root xmlns="http://javafx.com/javafx"
|
||||||
xmlns:fx="http://javafx.com/fxml"
|
xmlns:fx="http://javafx.com/fxml"
|
||||||
fx:id="rootPane"
|
fx:id="rootPane"
|
||||||
@ -16,10 +18,10 @@
|
|||||||
<VersionSettingsPage fx:id="versionSettings" />
|
<VersionSettingsPage fx:id="versionSettings" />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab fx:id="modTab" text="%mods">
|
<Tab fx:id="modTab" text="%mods">
|
||||||
<fx:include source="mod.fxml" fx:id="mod"/>
|
<ModListPage fx:id="mod" />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab text="%settings.tabs.installers">
|
<Tab text="%settings.tabs.installers">
|
||||||
<fx:include source="installer.fxml" fx:id="installer"/>
|
<InstallerListPage fx:id="installer" />
|
||||||
</Tab>
|
</Tab>
|
||||||
</JFXTabPane>
|
</JFXTabPane>
|
||||||
|
|
||||||
|
61
HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java
Normal file
61
HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package org.jackhuang.hmcl.game;
|
||||||
|
|
||||||
|
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||||
|
import org.jackhuang.hmcl.util.FileUtils;
|
||||||
|
import org.jackhuang.hmcl.util.Unzipper;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
|
import java.nio.file.FileSystem;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class World {
|
||||||
|
|
||||||
|
private final Path file;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public World(Path file) throws IOException {
|
||||||
|
this.file = file;
|
||||||
|
|
||||||
|
if (Files.isDirectory(file))
|
||||||
|
name = loadFromDirectory();
|
||||||
|
else if (Files.isRegularFile(file))
|
||||||
|
name = loadFromZip();
|
||||||
|
else
|
||||||
|
throw new IOException("Path " + file + " cannot be recognized as a Minecraft world");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String loadFromDirectory() {
|
||||||
|
return FileUtils.getName(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String loadFromZip() throws IOException {
|
||||||
|
try (FileSystem fs = CompressingUtils.createReadOnlyZipFileSystem(file)) {
|
||||||
|
Path root = Files.list(fs.getPath("/")).filter(Files::isDirectory).findAny()
|
||||||
|
.orElseThrow(() -> new IOException("Not a valid world zip file"));
|
||||||
|
|
||||||
|
Path levelDat = root.resolve("level.dat");
|
||||||
|
if (!Files.exists(levelDat))
|
||||||
|
throw new FileNotFoundException("Not a valid world zip file since level.dat cannot be found.");
|
||||||
|
|
||||||
|
return FileUtils.getName(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install(Path savesDir) throws IOException {
|
||||||
|
Path worldDir = savesDir.resolve(name);
|
||||||
|
if (Files.isDirectory(worldDir)) {
|
||||||
|
throw new FileAlreadyExistsException("World already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Files.isRegularFile(file)) {
|
||||||
|
new Unzipper(file, savesDir)
|
||||||
|
.setSubDirectory("/" + name + "/")
|
||||||
|
.unzip();
|
||||||
|
} else if (Files.isDirectory(file)) {
|
||||||
|
FileUtils.copyDirectory(file, worldDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,8 +22,8 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.*;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -54,6 +54,10 @@ public final class FileUtils {
|
|||||||
return StringUtils.addPrefix(StringUtils.removeSuffix(path, "/", "\\"), "/");
|
return StringUtils.addPrefix(StringUtils.removeSuffix(path, "/", "\\"), "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getName(Path path) {
|
||||||
|
return StringUtils.removeSuffix(path.getFileName().toString(), "/", "\\");
|
||||||
|
}
|
||||||
|
|
||||||
public static String readText(File file) throws IOException {
|
public static String readText(File file) throws IOException {
|
||||||
return readText(file, UTF_8);
|
return readText(file, UTF_8);
|
||||||
}
|
}
|
||||||
@ -97,6 +101,26 @@ public final class FileUtils {
|
|||||||
return Lang.test(() -> deleteDirectory(directory));
|
return Lang.test(() -> deleteDirectory(directory));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void copyDirectory(Path src, Path dest) throws IOException {
|
||||||
|
Files.walkFileTree(src, new SimpleFileVisitor<Path>(){
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Path destFile = dest.resolve(src.relativize(file));
|
||||||
|
Files.copy(file, destFile);
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||||
|
Path destDir = dest.resolve(src.relativize(dir));
|
||||||
|
Files.createDirectory(destDir);
|
||||||
|
|
||||||
|
return FileVisitResult.CONTINUE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean moveToTrash(File file) {
|
public static boolean moveToTrash(File file) {
|
||||||
try {
|
try {
|
||||||
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
|
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user