diff --git a/.idea/cssdialects.xml b/.idea/cssdialects.xml new file mode 100644 index 000000000..b802b9774 --- /dev/null +++ b/.idea/cssdialects.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ReadMe.md b/ReadMe.md index 08e39854c..9fe6b3056 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,4 +1,3 @@ - # Minosoft Minosoft is an open source minecraft client, written from scratch in java. It aims to bring more functionality and stability. diff --git a/data/resources/61/61406b8435362ef4ccb88df70d0abf405fddd87b.tar.gz b/data/resources/61/61406b8435362ef4ccb88df70d0abf405fddd87b.tar.gz deleted file mode 100644 index 497480aa8..000000000 Binary files a/data/resources/61/61406b8435362ef4ccb88df70d0abf405fddd87b.tar.gz and /dev/null differ diff --git a/data/resources/72/727af3de71ac164b5f0a3ac575d8c338dd077724.tar.gz b/data/resources/72/727af3de71ac164b5f0a3ac575d8c338dd077724.tar.gz new file mode 100644 index 000000000..bce25cd50 Binary files /dev/null and b/data/resources/72/727af3de71ac164b5f0a3ac575d8c338dd077724.tar.gz differ diff --git a/data/resources/79/793bcaf8cfe749f90718953675b919aaac8b9bd5.tar.gz b/data/resources/9c/9cf2f31e3aa318ce06f3896cf68ee514d75c685d.tar.gz similarity index 51% rename from data/resources/79/793bcaf8cfe749f90718953675b919aaac8b9bd5.tar.gz rename to data/resources/9c/9cf2f31e3aa318ce06f3896cf68ee514d75c685d.tar.gz index 3cd2e68b4..c9773ae53 100644 Binary files a/data/resources/79/793bcaf8cfe749f90718953675b919aaac8b9bd5.tar.gz and b/data/resources/9c/9cf2f31e3aa318ce06f3896cf68ee514d75c685d.tar.gz differ diff --git a/doc/img/server_list.png b/doc/img/server_list.png index 14fc952a0..eb485abe5 100644 Binary files a/doc/img/server_list.png and b/doc/img/server_list.png differ diff --git a/pom.xml b/pom.xml index adb07dab3..a4782cd6a 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,11 @@ 16-ea+4 pom + + com.jfoenix + jfoenix + 9.0.10 + org.apache.commons commons-compress diff --git a/src/main/java/de/bixilon/minosoft/Minosoft.java b/src/main/java/de/bixilon/minosoft/Minosoft.java index 403bb9226..5ed74665b 100644 --- a/src/main/java/de/bixilon/minosoft/Minosoft.java +++ b/src/main/java/de/bixilon/minosoft/Minosoft.java @@ -75,16 +75,16 @@ public final class Minosoft { Launcher.exit(); Platform.runLater(() -> { Dialog dialog = new Dialog<>(); + GUITools.initializePane(dialog.getDialogPane()); // Do not translate this, translations might fail to load... dialog.setTitle("Critical Error"); dialog.setHeaderText("An error occurred while starting Minosoft"); - TextArea text = new TextArea(exception.getClass().getCanonicalName() + ": " + exception.getLocalizedMessage()); + TextArea text = new TextArea(exception.getClass().getCanonicalName() + ": " + exception.getMessage()); text.setEditable(false); text.setWrapText(true); dialog.getDialogPane().setContent(text); Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow(); - stage.getIcons().add(GUITools.logo); stage.setAlwaysOnTop(true); stage.toFront(); stage.setOnCloseRequest(dialogEvent -> { diff --git a/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java b/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java index 7503d4718..436ccb3a1 100644 --- a/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java +++ b/src/main/java/de/bixilon/minosoft/config/StaticConfiguration.java @@ -20,6 +20,7 @@ import java.io.File; public class StaticConfiguration { public static final boolean DEBUG_MODE = false; // if true, additional checks will be made to validate data, ... Decreases performance + public static final boolean DEBUG_SLOW_LOADING = false; // if true, many Thread.sleep will be executed and the start will be delayed (by a lot) public static String CONFIG_FILENAME = "config.json"; // Filename of minosoft's base configuration (located in AppData/Minosoft/config) public static boolean SKIP_MOJANG_AUTHENTICATION = false; // disables all connections to mojang public static boolean COLORED_LOG = true; // the log should be colored with ANSI (does not affect base components) diff --git a/src/main/java/de/bixilon/minosoft/data/assets/AssetsManager.java b/src/main/java/de/bixilon/minosoft/data/assets/AssetsManager.java index cef2b5aa8..7a591ea9c 100644 --- a/src/main/java/de/bixilon/minosoft/data/assets/AssetsManager.java +++ b/src/main/java/de/bixilon/minosoft/data/assets/AssetsManager.java @@ -111,6 +111,9 @@ public class AssetsManager { try { String hash = assets.get(filename); boolean compressed = (source == AssetsSource.MOJANG); + if (StaticConfiguration.DEBUG_SLOW_LOADING) { + Thread.sleep(100L); + } if (!verifyAssetHash(hash, compressed)) { AssetsManager.downloadAsset(source, hash); } diff --git a/src/main/java/de/bixilon/minosoft/data/inventory/InventorySlots.java b/src/main/java/de/bixilon/minosoft/data/inventory/InventorySlots.java index bd35556b3..4beac8d54 100644 --- a/src/main/java/de/bixilon/minosoft/data/inventory/InventorySlots.java +++ b/src/main/java/de/bixilon/minosoft/data/inventory/InventorySlots.java @@ -110,7 +110,11 @@ public class InventorySlots { @Override public int getId(int versionId) { - return valueMap.get(versionId); + Integer value = valueMap.get(versionId); + if (value == null) { + return Integer.MIN_VALUE; + } + return value; } } diff --git a/src/main/java/de/bixilon/minosoft/data/locale/Strings.java b/src/main/java/de/bixilon/minosoft/data/locale/Strings.java index 743a8da54..bd370c541 100644 --- a/src/main/java/de/bixilon/minosoft/data/locale/Strings.java +++ b/src/main/java/de/bixilon/minosoft/data/locale/Strings.java @@ -87,5 +87,7 @@ public enum Strings { BUTTON_LOGIN, BUTTON_SAVE, BUTTON_ADD, - VERSION_AUTOMATIC + VERSION_AUTOMATIC, + + SERVER_ADDRESS_INPUT_REQUIRED } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockProperties.java b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockProperties.java index f3c063af2..c8f078a67 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockProperties.java +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/BlockProperties.java @@ -191,22 +191,22 @@ public enum BlockProperties { FIRE_AGE_LEVEL_25, // noteblock - NOTBLOCK_INSTRUMENT_HARP, - NOTBLOCK_INSTRUMENT_BASEDRUM, - NOTBLOCK_INSTRUMENT_SNARE, - NOTBLOCK_INSTRUMENT_HAT, - NOTBLOCK_INSTRUMENT_BASS, - NOTBLOCK_INSTRUMENT_FLUTE, - NOTBLOCK_INSTRUMENT_BELL, - NOTBLOCK_INSTRUMENT_GUITAR, - NOTBLOCK_INSTRUMENT_CHIME, - NOTBLOCK_INSTRUMENT_XYLOPHONE, - NOTBLOCK_INSTRUMENT_IRON_XYLOPHONE("instrument", "iron_xylophone"), - NOTBLOCK_INSTRUMENT_COW_BELL("instrument", "cow_bell"), - NOTBLOCK_INSTRUMENT_DIDGERIDOO, - NOTBLOCK_INSTRUMENT_BIT, - NOTBLOCK_INSTRUMENT_BANJO, - NOTBLOCK_INSTRUMENT_PLING, + NOTEBLOCK_INSTRUMENT_HARP, + NOTEBLOCK_INSTRUMENT_BASEDRUM, + NOTEBLOCK_INSTRUMENT_SNARE, + NOTEBLOCK_INSTRUMENT_HAT, + NOTEBLOCK_INSTRUMENT_BASS, + NOTEBLOCK_INSTRUMENT_FLUTE, + NOTEBLOCK_INSTRUMENT_BELL, + NOTEBLOCK_INSTRUMENT_GUITAR, + NOTEBLOCK_INSTRUMENT_CHIME, + NOTEBLOCK_INSTRUMENT_XYLOPHONE, + NOTEBLOCK_INSTRUMENT_IRON_XYLOPHONE("instrument", "iron_xylophone"), + NOTEBLOCK_INSTRUMENT_COW_BELL("instrument", "cow_bell"), + NOTEBLOCK_INSTRUMENT_DIDGERIDOO, + NOTEBLOCK_INSTRUMENT_BIT, + NOTEBLOCK_INSTRUMENT_BANJO, + NOTEBLOCK_INSTRUMENT_PLING, NOTEBLOCK_NOTE_LEVEL_0, NOTEBLOCK_NOTE_LEVEL_1, diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.java b/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.java index 4d36dad71..c11bb24d1 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.java +++ b/src/main/java/de/bixilon/minosoft/data/mappings/versions/VersionMapping.java @@ -43,23 +43,23 @@ public class VersionMapping { private final HashSet loaded = new HashSet<>(); private Version version; private VersionMapping parentMapping; - private HashBiMap motiveIdentifierMap; - private HashBiMap particleIdentifierMap; - private HashBiMap statisticIdentifierMap; - private HashBiMap itemMap; - private HashBiMap motiveIdMap; - private HashBiMap mobEffectMap; - private HashBiMap dimensionMap; + private final HashBiMap, EntityInformation> entityInformationMap = HashBiMap.create(); + private final HashMap entityMetaIndexMap = new HashMap<>(); + private final HashMap> entityMetaIndexOffsetParentMapping = new HashMap<>(); + private final HashBiMap> entityIdClassMap = HashBiMap.create(); + private HashBiMap motiveIdentifierMap = HashBiMap.create(); + private HashBiMap particleIdentifierMap = HashBiMap.create(); + private HashBiMap statisticIdentifierMap = HashBiMap.create(); private HashMap> dimensionIdentifierMap = new HashMap<>(); - private HashBiMap blockMap; - private HashBiMap blockIdMap; - private HashBiMap enchantmentMap; - private HashBiMap particleIdMap; - private HashBiMap statisticIdMap; - private HashBiMap, EntityInformation> entityInformationMap; - private HashMap entityMetaIndexMap; - private HashMap> entityMetaIndexOffsetParentMapping; - private HashBiMap> entityIdClassMap; + private HashBiMap itemMap = HashBiMap.create(); + private HashBiMap motiveIdMap = HashBiMap.create(); + private HashBiMap mobEffectMap = HashBiMap.create(); + private HashBiMap dimensionMap = HashBiMap.create(); + private HashBiMap blockMap = HashBiMap.create(); + private HashBiMap blockIdMap = HashBiMap.create(); + private HashBiMap enchantmentMap = HashBiMap.create(); + private HashBiMap particleIdMap = HashBiMap.create(); + private HashBiMap statisticIdMap = HashBiMap.create(); private HashMap> modelMap = new HashMap<>(); private Integer blockTextureId; // OpenGL texture id for all block texture @@ -160,7 +160,11 @@ public class VersionMapping { return dimensionMap.get(versionId); } + @Nullable public Block getBlockById(int versionId) { + if (versionId == ProtocolDefinition.NULL_BLOCK_ID) { + return null; + } if (parentMapping != null) { Block block = parentMapping.getBlockById(versionId); if (block != null) { @@ -348,16 +352,6 @@ public class VersionMapping { dimensionMap = Versions.PRE_FLATTENING_MAPPING.dimensionMap; break; } - itemMap = HashBiMap.create(); - enchantmentMap = HashBiMap.create(); - statisticIdMap = HashBiMap.create(); - statisticIdentifierMap = HashBiMap.create(); - blockIdMap = HashBiMap.create(); - motiveIdMap = HashBiMap.create(); - motiveIdentifierMap = HashBiMap.create(); - particleIdMap = HashBiMap.create(); - particleIdentifierMap = HashBiMap.create(); - mobEffectMap = HashBiMap.create(); if (data == null) { break; @@ -433,17 +427,11 @@ public class VersionMapping { } if (data == null) { - blockMap = HashBiMap.create(); break; } blockMap = Blocks.load(mod, data, !version.isFlattened()); } case ENTITIES -> { - entityInformationMap = HashBiMap.create(); - entityMetaIndexMap = new HashMap<>(); - entityMetaIndexOffsetParentMapping = new HashMap<>(); - entityIdClassMap = HashBiMap.create(); - if (data == null) { break; } @@ -462,7 +450,6 @@ public class VersionMapping { } if (data == null) { - modelMap = new HashMap<>(); break; } Pair, Integer> pair = BlockModelLoader.load(mod, data); diff --git a/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.java b/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.java index f0f1d9a8b..300d0eab9 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.java +++ b/src/main/java/de/bixilon/minosoft/data/text/BaseComponent.java @@ -27,6 +27,7 @@ import java.text.StringCharacterIterator; import java.util.ArrayList; public class BaseComponent extends ChatComponent { + private final static String LEGACY_RESET_SUFFIX = String.valueOf(ProtocolDefinition.TEXT_COMPONENT_SPECIAL_PREFIX_CHAR) + PostChatFormattingCodes.RESET.getChar(); private final ArrayList parts = new ArrayList<>(); public BaseComponent() { @@ -157,18 +158,25 @@ public class BaseComponent extends ChatComponent { return PostChatFormattingCodes.RESET.getANSI() + getANSIColoredMessage(); } + @Override public String getANSIColoredMessage() { StringBuilder builder = new StringBuilder(); parts.forEach((chatPart -> builder.append(chatPart.getANSIColoredMessage()))); return builder.toString(); } + @Override public String getLegacyText() { StringBuilder builder = new StringBuilder(); parts.forEach((chatPart -> builder.append(chatPart.getLegacyText()))); - return builder.toString(); + String string = builder.toString(); + if (string.endsWith(LEGACY_RESET_SUFFIX)) { + string = string.substring(0, string.length() - LEGACY_RESET_SUFFIX.length()); + } + return string; } + @Override public String getMessage() { StringBuilder builder = new StringBuilder(); parts.forEach((chatPart -> builder.append(chatPart.getMessage()))); @@ -195,4 +203,8 @@ public class BaseComponent extends ChatComponent { parts.add(new BaseComponent(message)); return this; } + + public boolean isEmpty() { + return parts.isEmpty(); + } } diff --git a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.java b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.java index b56235c73..a9a607247 100644 --- a/src/main/java/de/bixilon/minosoft/data/text/TextComponent.java +++ b/src/main/java/de/bixilon/minosoft/data/text/TextComponent.java @@ -157,7 +157,9 @@ public class TextComponent extends ChatComponent { @Override public ObservableList getJavaFXText(ObservableList nodes) { Text text = new Text(this.text); - if (color != null) { + if (color == null) { + text.setFill(Color.WHITE); + } else { text.setFill(Color.web(color.toString())); } formatting.forEach((chatFormattingCode -> { diff --git a/src/main/java/de/bixilon/minosoft/gui/main/AccountWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/AccountWindow.java index ed1d7745c..bfff0d48b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/AccountWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/AccountWindow.java @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.*; import de.bixilon.minosoft.Minosoft; import de.bixilon.minosoft.data.locale.LocaleManager; import de.bixilon.minosoft.data.locale.Strings; @@ -26,11 +27,11 @@ import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; -import javafx.scene.Node; -import javafx.scene.control.*; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.input.KeyCode; import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; -import javafx.stage.Stage; import javafx.stage.Window; import java.net.URL; @@ -45,8 +46,7 @@ public class AccountWindow implements Initializable { public void initialize(URL url, ResourceBundle resourceBundle) { AccountListCell.listView.setCellFactory((lv) -> AccountListCell.newInstance()); - ObservableList accounts = FXCollections.observableArrayList(); - accounts.addAll(Minosoft.getAccountList().values()); + ObservableList accounts = FXCollections.observableArrayList(Minosoft.getAccountList().values()); AccountListCell.listView.setItems(accounts); accountPane.setCenter(AccountListCell.listView); @@ -55,35 +55,39 @@ public class AccountWindow implements Initializable { @FXML public void addAccount() { - Dialog dialog = new Dialog<>(); + JFXAlert dialog = new JFXAlert<>(); dialog.setTitle(LocaleManager.translate(Strings.LOGIN_DIALOG_TITLE)); - dialog.setHeaderText(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER)); - ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo); + GUITools.initializePane(dialog.getDialogPane()); + JFXDialogLayout layout = new JFXDialogLayout(); + layout.setHeading(new Label(LocaleManager.translate(Strings.LOGIN_DIALOG_HEADER))); - ButtonType loginButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_LOGIN), ButtonBar.ButtonData.OK_DONE); - dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL); + JFXButton loginButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_LOGIN)); + layout.setActions(loginButton); - GridPane grid = new GridPane(); + GridPane gridPane = new GridPane(); + gridPane.setHgap(15); + gridPane.setVgap(15); - TextField email = new TextField(); - email.setPromptText(LocaleManager.translate(Strings.EMAIL)); - PasswordField password = new PasswordField(); - password.setPromptText(LocaleManager.translate(Strings.PASSWORD)); + JFXTextField emailField = new JFXTextField(); + emailField.setPromptText(LocaleManager.translate(Strings.EMAIL)); - grid.add(new Label(LocaleManager.translate(Strings.EMAIL) + ":"), 0, 0); - grid.add(email, 1, 0); - grid.add(new Label(LocaleManager.translate(Strings.PASSWORD) + ":"), 0, 1); - grid.add(password, 1, 1); - Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType); + JFXPasswordField passwordField = new JFXPasswordField(); + passwordField.setPromptText(LocaleManager.translate(Strings.PASSWORD)); - email.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty())); + gridPane.add(new Label(LocaleManager.translate(Strings.EMAIL) + ":"), 0, 0); + gridPane.add(emailField, 1, 0); + gridPane.add(new Label(LocaleManager.translate(Strings.PASSWORD) + ":"), 0, 1); + gridPane.add(passwordField, 1, 1); + + emailField.textProperty().addListener((observable, oldValue, newValue) -> loginButton.setDisable(newValue.trim().isEmpty())); loginButton.setDisable(true); - dialog.getDialogPane().setContent(grid); + layout.setBody(gridPane); + dialog.setContent(layout); - Platform.runLater(email::requestFocus); + Platform.runLater(emailField::requestFocus); loginButton.addEventFilter(ActionEvent.ACTION, event -> { - MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(email.getText(), password.getText()); + MojangAccountAuthenticationAttempt attempt = MojangAuthentication.login(emailField.getText(), passwordField.getText()); if (attempt.succeeded()) { // login okay MojangAccount account = attempt.getAccount(); @@ -91,6 +95,7 @@ public class AccountWindow implements Initializable { account.saveToConfig(); AccountListCell.listView.getItems().add(account); Log.info(String.format("Added and saved account (playerName=%s, email=%s, uuid=%s)", account.getPlayerName(), account.getMojangUserName(), account.getUUID())); + dialog.close(); return; } event.consume(); @@ -98,14 +103,25 @@ public class AccountWindow implements Initializable { error.setStyle("-fx-text-fill: red"); error.setText(attempt.getError()); - grid.add(new Label(LocaleManager.translate(Strings.ERROR)), 0, 2); - grid.add(error, 1, 2); + gridPane.add(new Label(LocaleManager.translate(Strings.ERROR)), 0, 2); + gridPane.add(error, 1, 2); // ToDo resize window }); Window window = dialog.getDialogPane().getScene().getWindow(); window.setOnCloseRequest(windowEvent -> window.hide()); + + dialog.getDialogPane().setOnKeyReleased(keyEvent -> { + if (keyEvent.getCode() != KeyCode.ENTER) { + return; + } + if (emailField.getText().trim().isEmpty()) { + return; + } + loginButton.fire(); + }); + dialog.showAndWait(); } } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java index ea34ce186..e9b7f7c0a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/GUITools.java @@ -13,29 +13,32 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.JFXComboBox; import de.bixilon.minosoft.data.mappings.versions.Version; import de.bixilon.minosoft.data.mappings.versions.Versions; import de.bixilon.minosoft.logging.LogLevels; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.scene.control.ComboBox; +import javafx.scene.Scene; import javafx.scene.image.Image; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; import java.io.ByteArrayInputStream; import java.util.Arrays; import java.util.Base64; public class GUITools { - public final static Image logo = new Image(GUITools.class.getResourceAsStream("/icons/windowIcon.png")); - public final static ObservableList versions = FXCollections.observableArrayList(); - public final static ComboBox versionList = new ComboBox<>(GUITools.versions); - public final static ObservableList logLevels = FXCollections.observableList(Arrays.asList(LogLevels.values().clone())); + public final static Image MINOSOFT_LOGO = new Image(GUITools.class.getResourceAsStream("/icons/windowIcon.png")); + public final static ObservableList VERSIONS = FXCollections.observableArrayList(); + public final static JFXComboBox VERSION_COMBO_BOX = new JFXComboBox<>(GUITools.VERSIONS); + public final static ObservableList LOG_LEVELS = FXCollections.observableList(Arrays.asList(LogLevels.values().clone())); static { - GUITools.versions.add(Versions.LOWEST_VERSION_SUPPORTED); - Versions.getVersionIdMap().forEach((key, value) -> GUITools.versions.add(value)); + GUITools.VERSIONS.add(Versions.LOWEST_VERSION_SUPPORTED); + Versions.getVersionIdMap().forEach((key, value) -> GUITools.VERSIONS.add(value)); - GUITools.versions.sort((a, b) -> { + GUITools.VERSIONS.sort((a, b) -> { if (a.getVersionId() == -1) { return -Integer.MAX_VALUE; } @@ -66,4 +69,17 @@ public class GUITools { return null; } } + + public static Scene initializeScene(Scene scene) { + scene.getStylesheets().add("/layout/style.css"); + if (scene.getWindow() instanceof Stage stage) { + stage.getIcons().add(GUITools.MINOSOFT_LOGO); + } + return scene; + } + + public static Pane initializePane(Pane pane) { + initializeScene(pane.getScene()); + return pane; + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/Launcher.java b/src/main/java/de/bixilon/minosoft/gui/main/Launcher.java index 9d3fa1245..b0fc5c4f4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/Launcher.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/Launcher.java @@ -44,10 +44,8 @@ public class Launcher { if (exit) { return; } - Stage stage = new Stage(); - stage.getIcons().add(GUITools.logo); - GUITools.versionList.setCellFactory(new Callback<>() { + GUITools.VERSION_COMBO_BOX.setCellFactory(new Callback<>() { @Override public ListCell call(ListView p) { return new ListCell<>() { @@ -76,11 +74,12 @@ public class Launcher { System.exit(1); } + Stage stage = new Stage(); Scene scene = new Scene(root, 600, 800); stage.setScene(scene); stage.setTitle(LocaleManager.translate(Strings.MAIN_WINDOW_TITLE)); - stage.getIcons().add(GUITools.logo); + GUITools.initializeScene(scene); stage.setOnCloseRequest(windowEvent -> System.exit(0)); if (exit) { return; diff --git a/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java index ed971ab4d..c5af7af3a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/MainWindow.java @@ -13,10 +13,16 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.JFXAlert; +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; +import com.jfoenix.controls.JFXTextField; +import com.jfoenix.validation.RequiredFieldValidator; import de.bixilon.minosoft.Minosoft; import de.bixilon.minosoft.data.locale.LocaleManager; import de.bixilon.minosoft.data.locale.Strings; import de.bixilon.minosoft.data.mappings.versions.Versions; +import de.bixilon.minosoft.data.text.BaseComponent; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.protocol.protocol.LANServerListener; import de.bixilon.minosoft.util.DNSUtil; @@ -25,11 +31,12 @@ import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.geometry.Insets; -import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; -import javafx.scene.control.*; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.control.Menu; +import javafx.scene.control.MenuItem; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.BorderPane; @@ -37,6 +44,7 @@ import javafx.scene.layout.GridPane; import javafx.stage.Modality; import javafx.stage.Stage; +import javax.annotation.Nullable; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; @@ -62,22 +70,28 @@ public class MainWindow implements Initializable { Stage stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); stage.setTitle(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_TITLE)); - stage.getIcons().add(GUITools.logo); stage.setScene(new Scene(parent)); + + GUITools.initializeScene(stage.getScene()); Platform.setImplicitExit(false); stage.setOnCloseRequest(event -> { if (Minosoft.getSelectedAccount() == null) { event.consume(); - Alert alert = new Alert(Alert.AlertType.WARNING, LocaleManager.translate(Strings.ERROR), ButtonType.CANCEL, ButtonType.OK); - alert.setHeaderText(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_HEADER)); - alert.setContentText(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_ERROR)); - alert.showAndWait().ifPresent((type) -> { - if (type == ButtonType.OK) { - System.exit(0); - return; - } - alert.close(); - }); + JFXAlert alert = new JFXAlert<>(); + GUITools.initializePane(alert.getDialogPane()); + alert.setTitle(LocaleManager.translate(Strings.ERROR)); + JFXDialogLayout layout = new JFXDialogLayout(); + layout.setHeading(new Label(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_HEADER))); + layout.setBody(new Label(LocaleManager.translate(Strings.MANAGE_ACCOUNTS_NO_ACCOUNT_ERROR_ERROR))); + + JFXButton cancel = new JFXButton(ButtonType.CANCEL.getText()); + cancel.setOnAction((actionEvent -> alert.close())); + JFXButton close = new JFXButton(ButtonType.OK.getText()); + close.setOnAction(actionEvent -> System.exit(0)); + + layout.setActions(cancel, close); + alert.setContent(layout); + alert.showAndWait(); } else { stage.close(); } @@ -106,6 +120,116 @@ public class MainWindow implements Initializable { }); } + public static void addOrEditServer(@Nullable final Server server) { + JFXAlert dialog = new JFXAlert<>(); + GUITools.initializePane(dialog.getDialogPane()); + + + JFXDialogLayout layout = new JFXDialogLayout(); + + GridPane gridPane = new GridPane(); + gridPane.setVgap(15); + gridPane.setHgap(50); + + JFXButton submitButton; + + + JFXTextField serverNameField = new JFXTextField(); + serverNameField.setPromptText(LocaleManager.translate(Strings.SERVER_NAME)); + + JFXTextField serverAddressField = new JFXTextField(); + serverAddressField.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS)); + RequiredFieldValidator serverAddressValidator = new RequiredFieldValidator(); + serverAddressValidator.setMessage(LocaleManager.translate(Strings.SERVER_ADDRESS_INPUT_REQUIRED)); + serverAddressField.getValidators().add(serverAddressValidator); + serverAddressField.focusedProperty().addListener((o, oldValue, newValue) -> { + if (!newValue) { + serverAddressField.validate(); + } + }); + + GUITools.VERSION_COMBO_BOX.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED); + + + if (server == null) { + // add + dialog.setTitle(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_TITLE)); + layout.setHeading(new Label(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_HEADER))); + + submitButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_ADD)); + + serverNameField.setText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_DEFAULT_SERVER_NAME)); + } else { + dialog.setTitle(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_TITLE, server.getName().getMessage())); + layout.setHeading(new Label(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_HEADER))); + + submitButton = new JFXButton(LocaleManager.translate(Strings.BUTTON_SAVE)); + + serverNameField.setText(server.getName().getLegacyText()); + serverAddressField.setText(server.getAddress()); + + if (server.getDesiredVersionId() != -1) { + GUITools.VERSION_COMBO_BOX.getSelectionModel().select(Versions.getVersionById(server.getDesiredVersionId())); + } + } + submitButton.setButtonType(JFXButton.ButtonType.RAISED); + + gridPane.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0); + gridPane.add(serverNameField, 1, 0); + gridPane.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1); + gridPane.add(serverAddressField, 1, 1); + gridPane.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2); + gridPane.add(GUITools.VERSION_COMBO_BOX, 1, 2); + + + layout.setBody(gridPane); + JFXButton closeButton = new JFXButton(ButtonType.CLOSE.getText()); + closeButton.setOnAction((actionEvent -> dialog.hide())); + closeButton.setButtonType(JFXButton.ButtonType.RAISED); + layout.setActions(closeButton, submitButton); + + + serverAddressField.textProperty().addListener((observable, oldValue, newValue) -> submitButton.setDisable(newValue.trim().isEmpty())); + submitButton.setDisable(serverAddressField.getText().isBlank()); + dialog.setContent(layout); + + Platform.runLater(serverNameField::requestFocus); + + submitButton.setOnAction(actionEvent -> { + Server server1 = server; + BaseComponent serverName = new BaseComponent(serverNameField.getText()); + String serverAddress = DNSUtil.correctHostName(serverAddressField.getText()); + int desiredVersionId = GUITools.VERSION_COMBO_BOX.getSelectionModel().getSelectedItem().getVersionId(); + + if (server1 == null) { + server1 = new Server(Server.getNextServerId(), serverName, serverAddress, desiredVersionId); + Minosoft.serverList.add(server1); + ServerListCell.listView.getItems().add(server1); + } else { + server1.setName(serverName); + server1.setAddress(serverAddress); + server1.setDesiredVersionId(desiredVersionId); + if (server1.getCell() != null) { + server1.getCell().setName(server1.getName()); + //ToDo: version + } + } + server1.saveToConfig(); + Log.info(String.format("%s and saved server (serverName=%s, serverAddress=%s, version=%d)", ((server == null) ? "Added" : "Edited"), serverName.getLegacyText(), serverAddress, desiredVersionId)); + dialog.hide(); + }); + dialog.getDialogPane().setOnKeyReleased(keyEvent -> { + if (keyEvent.getCode() != KeyCode.ENTER) { + return; + } + if (serverAddressField.getText().trim().isEmpty()) { + return; + } + submitButton.fire(); + }); + dialog.showAndWait(); + } + @Override public void initialize(URL url, ResourceBundle resourceBundle) { serversPane.setCenter(ServerListCell.listView); @@ -125,54 +249,7 @@ public class MainWindow implements Initializable { @FXML public void addServer() { - Dialog dialog = new Dialog<>(); - dialog.setTitle(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_TITLE)); - dialog.setHeaderText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_HEADER)); - ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo); - - ButtonType addButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_ADD), ButtonBar.ButtonData.OK_DONE); - dialog.getDialogPane().getButtonTypes().addAll(addButtonType, ButtonType.CANCEL); - - GridPane grid = new GridPane(); - grid.setHgap(10); - grid.setVgap(10); - grid.setPadding(new Insets(20, 300, 10, 10)); - - TextField serverName = new TextField(); - serverName.setPromptText(LocaleManager.translate(Strings.SERVER_NAME)); - serverName.setText(LocaleManager.translate(Strings.ADD_SERVER_DIALOG_DEFAULT_SERVER_NAME)); - TextField serverAddress = new TextField(); - serverAddress.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS)); - - GUITools.versionList.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED); - - grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0); - grid.add(serverName, 1, 0); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1); - grid.add(serverAddress, 1, 1); - grid.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2); - grid.add(GUITools.versionList, 1, 2); - - Node addButton = dialog.getDialogPane().lookupButton(addButtonType); - - serverAddress.textProperty().addListener((observable, oldValue, newValue) -> addButton.setDisable(newValue.trim().isEmpty())); - addButton.setDisable(true); - - dialog.getDialogPane().setContent(grid); - - Platform.runLater(serverName::requestFocus); - - dialog.setResultConverter(dialogButton -> { - if (dialogButton == addButtonType) { - Server server = new Server(Server.getNextServerId(), serverName.getText(), DNSUtil.correctHostName(serverAddress.getText()), GUITools.versionList.getSelectionModel().getSelectedItem().getVersionId()); - Minosoft.serverList.add(server); - server.saveToConfig(); - ServerListCell.listView.getItems().add(server); - Log.info(String.format("Added and saved server (serverName=%s, serverAddress=%s, version=%d)", server.getName(), server.getAddress(), server.getDesiredVersionId())); - } - return null; - }); - dialog.showAndWait(); + addOrEditServer(null); } @FXML @@ -205,10 +282,9 @@ public class MainWindow implements Initializable { Parent parent = new FXMLLoader(MainWindow.class.getResource("/layout/settings.fxml")).load(); Stage stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); - stage.getIcons().add(GUITools.logo); stage.setTitle(LocaleManager.translate(Strings.SETTINGS_TITLE)); - stage.getIcons().add(GUITools.logo); stage.setScene(new Scene(parent)); + GUITools.initializeScene(stage.getScene()); stage.addEventHandler(KeyEvent.KEY_PRESSED, (KeyEvent event) -> { if (event.getCode() == KeyCode.ESCAPE) { stage.close(); diff --git a/src/main/java/de/bixilon/minosoft/gui/main/Server.java b/src/main/java/de/bixilon/minosoft/gui/main/Server.java index 20caac79f..78c00a0e6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/Server.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/Server.java @@ -15,6 +15,7 @@ package de.bixilon.minosoft.gui.main; import com.google.gson.JsonObject; import de.bixilon.minosoft.Minosoft; +import de.bixilon.minosoft.data.text.BaseComponent; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.protocol.ConnectionReasons; import de.bixilon.minosoft.protocol.protocol.LANServerListener; @@ -25,34 +26,37 @@ import java.util.ArrayList; import java.util.Base64; public class Server { - static int highestServerId; - final int id; - final ArrayList connections = new ArrayList<>(); - String name; - String address; - int desiredVersion; - byte[] favicon; - Connection lastPing; + private static int highestServerId; + private final int id; + private final ArrayList connections = new ArrayList<>(); + private BaseComponent name; + private BaseComponent addressName; + private String address; + private int desiredVersion; + private byte[] favicon; + private Connection lastPing; private boolean readOnly = false; + private ServerListCell cell; - public Server(int id, String name, String address, int desiredVersion, byte[] favicon) { + public Server(int id, BaseComponent name, String address, int desiredVersion, byte[] favicon) { this(id, name, address, desiredVersion); this.favicon = favicon; } - public Server(int id, String name, String address, int desiredVersion) { + public Server(int id, BaseComponent name, String address, int desiredVersion) { this.id = id; if (id > highestServerId) { highestServerId = id; } this.name = name; this.address = address; + this.addressName = new BaseComponent(address); this.desiredVersion = desiredVersion; } public Server(ServerAddress address) { this.id = getNextServerId(); - this.name = String.format("LAN Server #%d", LANServerListener.getServers().size()); + this.name = new BaseComponent(String.format("LAN Server #%d", LANServerListener.getServers().size())); this.address = address.toString(); this.desiredVersion = -1; // Automatic this.readOnly = true; @@ -63,7 +67,7 @@ public class Server { } public static Server deserialize(JsonObject json) { - Server server = new Server(json.get("id").getAsInt(), json.get("name").getAsString(), json.get("address").getAsString(), json.get("version").getAsInt()); + Server server = new Server(json.get("id").getAsInt(), new BaseComponent(json.get("name").getAsString()), json.get("address").getAsString(), json.get("version").getAsInt()); if (json.has("favicon")) { server.setFavicon(Base64.getDecoder().decode(json.get("favicon").getAsString())); } @@ -113,11 +117,15 @@ public class Server { return String.format("%s (%s)", getName(), getAddress()); } - public String getName() { + public BaseComponent getName() { + if (name.isEmpty()) { + return addressName; + } return name; } - public void setName(String name) { + + public void setName(BaseComponent name) { this.name = name; } @@ -127,6 +135,7 @@ public class Server { public void setAddress(String address) { this.address = address; + this.addressName = new BaseComponent(address); } public void ping() { @@ -164,7 +173,7 @@ public class Server { public JsonObject serialize() { JsonObject json = new JsonObject(); json.addProperty("id", id); - json.addProperty("name", name); + json.addProperty("name", name.getLegacyText()); json.addProperty("address", address); json.addProperty("version", desiredVersion); if (favicon != null) { @@ -184,4 +193,12 @@ public class Server { public boolean isReadOnly() { return readOnly; } + + public ServerListCell getCell() { + return cell; + } + + public void setCell(ServerListCell cell) { + this.cell = cell; + } } diff --git a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java index f49b2de7e..93280b9bb 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/ServerListCell.java @@ -13,12 +13,16 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.JFXAlert; +import com.jfoenix.controls.JFXButton; +import com.jfoenix.controls.JFXDialogLayout; import de.bixilon.minosoft.Minosoft; import de.bixilon.minosoft.data.Player; import de.bixilon.minosoft.data.locale.LocaleManager; import de.bixilon.minosoft.data.locale.Strings; import de.bixilon.minosoft.data.mappings.versions.Version; import de.bixilon.minosoft.data.mappings.versions.Versions; +import de.bixilon.minosoft.data.text.BaseComponent; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.modding.event.EventInvokerCallback; import de.bixilon.minosoft.modding.event.events.ConnectionStateChangeEvent; @@ -26,11 +30,9 @@ import de.bixilon.minosoft.modding.event.events.ServerListPingArriveEvent; import de.bixilon.minosoft.protocol.network.Connection; import de.bixilon.minosoft.protocol.ping.ForgeModInfo; import de.bixilon.minosoft.protocol.ping.ServerListPing; -import de.bixilon.minosoft.util.DNSUtil; import javafx.application.Platform; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; -import javafx.geometry.Insets; import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.Scene; @@ -38,7 +40,6 @@ import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import javafx.scene.paint.Color; import javafx.scene.text.Text; @@ -54,13 +55,14 @@ import java.util.ResourceBundle; public class ServerListCell extends ListCell implements Initializable { public static final ListView listView = new ListView<>(); - public ImageView icon; - public TextFlow motd; - public Label version; - public Label players; - public Label serverBrand; - public Label serverName; - public AnchorPane root; + public ImageView faviconField; + public TextFlow nameField; + public TextFlow motdField; + public Label versionField; + public Label playersField; + public Label brandField; + + public GridPane root; public MenuItem optionsConnect; public MenuItem optionsShowInfo; public MenuItem optionsEdit; @@ -97,10 +99,6 @@ public class ServerListCell extends ListCell implements Initializable { optionsDelete.setText(LocaleManager.translate(Strings.SERVER_ACTION_DELETE)); } - public AnchorPane getRoot() { - return root; - } - @Override protected void updateItem(Server server, boolean empty) { super.updateItem(server, empty); @@ -117,16 +115,17 @@ public class ServerListCell extends ListCell implements Initializable { if (server.equals(this.server)) { return; } + server.setCell(this); resetCell(); this.server = server; - serverName.setText(server.getName()); + setName(server.getName()); Image favicon = GUITools.getImage(server.getFavicon()); if (favicon == null) { - favicon = GUITools.logo; + favicon = GUITools.MINOSOFT_LOGO; } - icon.setImage(favicon); + faviconField.setImage(favicon); if (server.isConnected()) { setStyle("-fx-background-color: darkseagreen;"); optionsSessions.setDisable(false); @@ -149,37 +148,37 @@ public class ServerListCell extends ListCell implements Initializable { } if (ping == null) { // Offline - players.setText(""); - version.setText(LocaleManager.translate(Strings.OFFLINE)); - version.setStyle("-fx-text-fill: red;"); + playersField.setText(""); + versionField.setText(LocaleManager.translate(Strings.OFFLINE)); + versionField.setStyle("-fx-text-fill: red;"); setErrorMotd(String.format("%s", server.getLastPing().getLastConnectionException())); optionsConnect.setDisable(true); canConnect = false; return; } - players.setText(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.getPlayerOnline(), ping.getMaxPlayers())); + playersField.setText(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, ping.getPlayerOnline(), ping.getMaxPlayers())); Version serverVersion; if (server.getDesiredVersionId() == -1) { serverVersion = Versions.getVersionByProtocolId(ping.getProtocolId()); } else { serverVersion = Versions.getVersionById(server.getDesiredVersionId()); - version.setStyle("-fx-text-fill: green;"); + versionField.setStyle("-fx-text-fill: -secondary-light-light-color;"); } if (serverVersion == null) { - version.setText(ping.getServerBrand()); - version.setStyle("-fx-text-fill: red;"); + versionField.setText(ping.getServerBrand()); + versionField.setStyle("-fx-text-fill: red;"); optionsConnect.setDisable(true); canConnect = false; } else { - version.setText(serverVersion.getVersionName()); + versionField.setText(serverVersion.getVersionName()); optionsConnect.setDisable(false); canConnect = true; } - serverBrand.setText(ping.getServerModInfo().getBrand()); - serverBrand.setTooltip(new Tooltip(ping.getServerModInfo().getInfo())); - motd.getChildren().addAll(ping.getMotd().getJavaFXText()); + brandField.setText(ping.getServerModInfo().getBrand()); + brandField.setTooltip(new Tooltip(ping.getServerModInfo().getInfo())); + motdField.getChildren().setAll(ping.getMotd().getJavaFXText()); if (ping.getFavicon() != null) { - icon.setImage(GUITools.getImage(ping.getFavicon())); + faviconField.setImage(GUITools.getImage(ping.getFavicon())); if (!Arrays.equals(ping.getFavicon(), server.getFavicon())) { server.setFavicon(ping.getFavicon()); server.saveToConfig(); @@ -191,34 +190,40 @@ public class ServerListCell extends ListCell implements Initializable { } if (server.getLastPing().getLastConnectionException() != null) { // connection failed because of an error in minosoft, but ping was okay - version.setStyle("-fx-text-fill: red;"); + versionField.setStyle("-fx-text-fill: red;"); optionsConnect.setDisable(true); canConnect = false; - setErrorMotd(String.format("%s: %s", server.getLastPing().getLastConnectionException().getClass().getCanonicalName(), server.getLastPing().getLastConnectionException().getLocalizedMessage())); + setErrorMotd(String.format("%s: %s", server.getLastPing().getLastConnectionException().getClass().getCanonicalName(), server.getLastPing().getLastConnectionException().getMessage())); } }))); } + public void setName(BaseComponent name) { + nameField.getChildren().setAll(name.getJavaFXText()); + for (Node node : nameField.getChildren()) { + node.setStyle("-fx-font-size: 15pt ;"); + } + } + private void resetCell() { // clear all cells setStyle(null); - motd.getChildren().clear(); - serverBrand.setText(""); - serverBrand.setTooltip(null); - motd.setStyle(null); - version.setText(LocaleManager.translate(Strings.CONNECTING)); - version.setStyle(null); - players.setText(""); + motdField.getChildren().clear(); + brandField.setText(""); + brandField.setTooltip(null); + motdField.setStyle(null); + versionField.setText(LocaleManager.translate(Strings.CONNECTING)); + versionField.setStyle(null); + playersField.setText(""); optionsConnect.setDisable(true); optionsEdit.setDisable(false); optionsDelete.setDisable(false); } private void setErrorMotd(String message) { - motd.getChildren().clear(); Text text = new Text(message); text.setFill(Color.RED); - motd.getChildren().add(text); + motdField.getChildren().setAll(text); } public void delete() { @@ -227,12 +232,12 @@ public class ServerListCell extends ListCell implements Initializable { } server.getConnections().forEach(Connection::disconnect); server.delete(); - Log.info(String.format("Deleted server (name=\"%s\", address=\"%s\")", server.getName(), server.getAddress())); + Log.info(String.format("Deleted server (name=\"%s\", address=\"%s\")", server.getName().getLegacyText(), server.getAddress())); listView.getItems().remove(server); } public void refresh() { - Log.info(String.format("Refreshing server status (serverName=\"%s\", address=\"%s\")", server.getName(), server.getAddress())); + Log.info(String.format("Refreshing server status (serverName=\"%s\", address=\"%s\")", server.getName().getLegacyText(), server.getAddress())); if (server.getLastPing() == null) { // server was not pinged, don't even try, only costs memory and cpu return; @@ -250,7 +255,7 @@ public class ServerListCell extends ListCell implements Initializable { case SECONDARY -> optionsMenu.fire(); case MIDDLE -> { listView.getSelectionModel().select(server); - edit(); + editServer(); } } } @@ -273,68 +278,8 @@ public class ServerListCell extends ListCell implements Initializable { } - public void edit() { - if (server.isReadOnly()) { - return; - } - Dialog dialog = new Dialog<>(); - dialog.setTitle(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_TITLE, server.getName())); - dialog.setHeaderText(LocaleManager.translate(Strings.EDIT_SERVER_DIALOG_HEADER)); - ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo); - - ButtonType saveButtonType = new ButtonType(LocaleManager.translate(Strings.BUTTON_SAVE), ButtonBar.ButtonData.OK_DONE); - dialog.getDialogPane().getButtonTypes().addAll(saveButtonType, ButtonType.CANCEL); - - GridPane grid = new GridPane(); - grid.setHgap(10); - grid.setVgap(10); - grid.setPadding(new Insets(20, 300, 10, 10)); - - TextField serverName = new TextField(); - serverName.setPromptText(LocaleManager.translate(Strings.SERVER_NAME)); - serverName.setText(server.getName()); - TextField serverAddress = new TextField(); - serverAddress.setPromptText(LocaleManager.translate(Strings.SERVER_ADDRESS)); - serverAddress.setText(server.getAddress()); - - if (server.getDesiredVersionId() == -1) { - GUITools.versionList.getSelectionModel().select(Versions.LOWEST_VERSION_SUPPORTED); - } else { - GUITools.versionList.getSelectionModel().select(Versions.getVersionById(server.getDesiredVersionId())); - } - - grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, 0); - grid.add(serverName, 1, 0); - grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, 1); - grid.add(serverAddress, 1, 1); - grid.add(new Label(LocaleManager.translate(Strings.VERSION) + ":"), 0, 2); - grid.add(GUITools.versionList, 1, 2); - - Node saveButton = dialog.getDialogPane().lookupButton(saveButtonType); - - serverAddress.textProperty().addListener((observable, oldValue, newValue) -> saveButton.setDisable(newValue.trim().isEmpty())); - - dialog.getDialogPane().setContent(grid); - - Platform.runLater(serverName::requestFocus); - - dialog.setResultConverter(dialogButton -> { - if (dialogButton == saveButtonType) { - serverName.setText(serverName.getText()); - server.setName(serverName.getText()); - server.setDesiredVersionId(GUITools.versionList.getSelectionModel().getSelectedItem().getVersionId()); - if (server.getDesiredVersionId() != -1) { - version.setText(Versions.getVersionById(server.getDesiredVersionId()).getVersionName()); - version.setTextFill(Color.BLACK); - } - server.setAddress(DNSUtil.correctHostName(serverAddress.getText())); - server.saveToConfig(); - Log.info(String.format("Edited and saved server (serverName=%s, serverAddress=%s, version=%d)", server.getName(), server.getAddress(), server.getDesiredVersionId())); - } - return null; - }); - - dialog.showAndWait(); + public void editServer() { + MainWindow.addOrEditServer(server); } private void handleConnectionCallback(ConnectionStateChangeEvent event) { @@ -363,19 +308,24 @@ public class ServerListCell extends ListCell implements Initializable { } public void showInfo() { - Dialog dialog = new Dialog<>(); - dialog.setTitle("View server info: " + server.getName()); - ((Stage) dialog.getDialogPane().getScene().getWindow()).getIcons().add(GUITools.logo); + JFXAlert dialog = new JFXAlert<>(); + dialog.setTitle("View server info: " + server.getName().getMessage()); + GUITools.initializePane(dialog.getDialogPane()); - ButtonType loginButtonType = ButtonType.CLOSE; - dialog.getDialogPane().getButtonTypes().add(loginButtonType); + JFXDialogLayout layout = new JFXDialogLayout(); + + + JFXButton closeButton = new JFXButton(ButtonType.CLOSE.getText()); + closeButton.setOnAction((actionEvent -> dialog.hide())); + closeButton.setButtonType(JFXButton.ButtonType.RAISED); + layout.setActions(closeButton); GridPane grid = new GridPane(); grid.setHgap(10); grid.setVgap(10); - grid.setPadding(new Insets(20, 300, 10, 10)); - Label serverNameLabel = new Label(server.getName()); + TextFlow serverNameLabel = new TextFlow(); + serverNameLabel.getChildren().setAll(server.getName().getJavaFXText()); Label serverAddressLabel = new Label(server.getAddress()); Label forcedVersionLabel = new Label(); @@ -386,7 +336,9 @@ public class ServerListCell extends ListCell implements Initializable { } int column = -1; - grid.add(new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"), 0, ++column); + Label a = new Label(LocaleManager.translate(Strings.SERVER_NAME) + ":"); + a.setWrapText(false); + grid.add(a, 0, ++column); grid.add(serverNameLabel, 1, column); grid.add(new Label(LocaleManager.translate(Strings.SERVER_ADDRESS) + ":"), 0, ++column); grid.add(serverAddressLabel, 1, column); @@ -415,7 +367,7 @@ public class ServerListCell extends ListCell implements Initializable { Label serverBrandLabel = new Label(lastPing.getServerBrand()); Label playersOnlineMaxLabel = new Label(LocaleManager.translate(Strings.SERVER_INFO_SLOTS_PLAYERS_ONLINE, lastPing.getPlayerOnline(), lastPing.getMaxPlayers())); TextFlow motdLabel = new TextFlow(); - motdLabel.getChildren().addAll(lastPing.getMotd().getJavaFXText()); + motdLabel.getChildren().setAll(lastPing.getMotd().getJavaFXText()); Label moddedBrandLabel = new Label(lastPing.getServerModInfo().getBrand()); grid.add(new Label(LocaleManager.translate(Strings.SERVER_INFO_REAL_SERVER_ADDRESS) + ":"), 0, ++column); @@ -440,9 +392,9 @@ public class ServerListCell extends ListCell implements Initializable { } } } - - dialog.getDialogPane().setContent(grid); - + // ToDo: size probably + layout.setBody(grid); + dialog.setContent(layout); dialog.showAndWait(); } @@ -454,8 +406,8 @@ public class ServerListCell extends ListCell implements Initializable { Stage stage = new Stage(); stage.initModality(Modality.APPLICATION_MODAL); stage.setTitle(LocaleManager.translate(Strings.SESSIONS_DIALOG_TITLE, server.getName())); - stage.getIcons().add(GUITools.logo); stage.setScene(new Scene(parent)); + GUITools.initializeScene(stage.getScene()); stage.show(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java index 5eeb63353..a17a62663 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/SettingsWindow.java @@ -13,6 +13,7 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.JFXComboBox; import de.bixilon.minosoft.Minosoft; import de.bixilon.minosoft.config.ConfigurationPaths; import de.bixilon.minosoft.data.locale.LocaleManager; @@ -20,7 +21,6 @@ import de.bixilon.minosoft.data.locale.Strings; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.logging.LogLevels; import javafx.fxml.Initializable; -import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.Tab; import javafx.scene.layout.GridPane; @@ -30,14 +30,14 @@ import java.util.ResourceBundle; public class SettingsWindow implements Initializable { public GridPane tabGeneral; - public ComboBox generalLogLevel; + public JFXComboBox generalLogLevel; public Tab general; public Tab download; public Label generalLogLevelLabel; @Override public void initialize(URL url, ResourceBundle resourceBundle) { - generalLogLevel.setItems(GUITools.logLevels); + generalLogLevel.setItems(GUITools.LOG_LEVELS); generalLogLevel.getSelectionModel().select(Log.getLevel()); generalLogLevel.setOnAction((actionEvent -> { LogLevels newLevel = generalLogLevel.getValue(); diff --git a/src/main/java/de/bixilon/minosoft/gui/main/StartProgressWindow.java b/src/main/java/de/bixilon/minosoft/gui/main/StartProgressWindow.java index 1fcd420a7..393723cd6 100644 --- a/src/main/java/de/bixilon/minosoft/gui/main/StartProgressWindow.java +++ b/src/main/java/de/bixilon/minosoft/gui/main/StartProgressWindow.java @@ -13,25 +13,27 @@ package de.bixilon.minosoft.gui.main; +import com.jfoenix.controls.JFXAlert; +import com.jfoenix.controls.JFXDialogLayout; +import com.jfoenix.controls.JFXProgressBar; import de.bixilon.minosoft.data.locale.LocaleManager; import de.bixilon.minosoft.data.locale.Strings; import de.bixilon.minosoft.logging.Log; import de.bixilon.minosoft.util.CountUpAndDownLatch; import javafx.application.Application; import javafx.application.Platform; -import javafx.scene.control.Dialog; import javafx.scene.control.Label; -import javafx.scene.control.ProgressBar; import javafx.scene.layout.GridPane; import javafx.stage.Modality; import javafx.stage.Stage; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; public class StartProgressWindow extends Application { - public static CountDownLatch toolkitLatch = new CountDownLatch(2); // 2 if not started, 1 if started, 2 if loaded - public static Dialog progressDialog; + public final static CountDownLatch toolkitLatch = new CountDownLatch(2); // 2 if not started, 1 if started, 2 if loaded + public static JFXAlert progressDialog; + private static JFXProgressBar progressBar; + private static Label progressLabel; private static boolean exit = false; public static void show(CountUpAndDownLatch progress) throws InterruptedException { @@ -44,20 +46,30 @@ public class StartProgressWindow extends Application { latch.countDown(); return; } - AtomicReference progressBar = new AtomicReference<>(); - AtomicReference