diff --git a/pom.xml b/pom.xml index afb4acc..dfc4f36 100644 --- a/pom.xml +++ b/pom.xml @@ -9,11 +9,11 @@ ${java.version} ${java.version} UTF-8 - 21 - 5.8.2 + 22.0.1 + 5.10.2 10.17.1.0 - 1.18.30 - 6.4.2.Final + 1.18.32 + 6.5.2.Final @@ -21,7 +21,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 ${java.version} ${java.version} @@ -57,7 +57,7 @@ org.controlsfx controlsfx - 11.2.0 + 11.2.1 @@ -94,14 +94,14 @@ com.sun.xml.bind - jaxb-impl - 3.0.2 + jaxb-core + 4.0.5 org.apache.logging.log4j log4j-slf4j2-impl - 2.22.1 + 2.23.1 org.projectlombok @@ -112,13 +112,13 @@ org.mockito mockito-core - 4.3.1 + 5.12.0 test org.mockito mockito-junit-jupiter - 4.3.1 + 5.12.0 test diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/App.java b/src/main/java/com/JayPi4c/RobbiSimulator/App.java index f0122cc..721c7df 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/App.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/App.java @@ -1,16 +1,11 @@ package com.JayPi4c.RobbiSimulator; -import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; - -import java.util.ResourceBundle; - import com.JayPi4c.RobbiSimulator.controller.program.ProgramController; import com.JayPi4c.RobbiSimulator.controller.tutor.TutorController; import com.JayPi4c.RobbiSimulator.utils.AlertHelper; import com.JayPi4c.RobbiSimulator.utils.HibernateUtils; import com.JayPi4c.RobbiSimulator.utils.I18nUtils; import com.JayPi4c.RobbiSimulator.utils.PropertiesLoader; - import javafx.application.Application; import javafx.application.Platform; import javafx.scene.control.Alert.AlertType; @@ -18,100 +13,101 @@ import lombok.extern.slf4j.Slf4j; import javax.swing.*; +import java.util.ResourceBundle; + +import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; /** - * - * Hauptklasse des Robbi Simulators.
- * Javaversion: 17
- * - * @author Jonas Pohl + * Application entry point.
+ * Java version: 21 * + * @author Jonas Pohl */ @Slf4j public class App extends Application { - private static final String INIT_ERROR_MESSAGE = "Init.error.message"; - private static final String INIT_ERROR_TITLE = "Init.error.title"; - private static final String INIT_ERROR_HEADER = "Init.error.header"; - - /** - * Application entry point - * - * @param args the arguments from the command line - */ - public static void main(String[] args) { - try { - launch(args); - } catch (Exception e) { - e.printStackTrace(); - JOptionPane.showMessageDialog(null, """ - Failed to load application. - Further information can be obtained running the - application in the command line. - Please consider submitting your error. - """); - } - } - - @Override - public void init() { - logger.info("Initialize application"); - - logger.debug("Initializing properties..."); - if (PropertiesLoader.initialize()) { - logger.debug("Loaded properties successfully"); - } else - logger.debug("Failed to load properties."); - - I18nUtils.setBundle(ResourceBundle.getBundle("lang.messages", PropertiesLoader.getLocale())); - - logger.debug("Loading Program Controller"); - if (!ProgramController.initialize()) { - logger.error("Failed to load Program Controller"); - AlertHelper.showAlertAndWait(AlertType.ERROR, i18n(INIT_ERROR_MESSAGE), null, null, i18n(INIT_ERROR_TITLE), - i18n(INIT_ERROR_HEADER)); - Platform.exit(); - } - logger.debug("loading Program Controller successfully"); - - if (PropertiesLoader.isTutor()) { - logger.debug("Starting Tutor RMI server"); - if (TutorController.initialize()) - logger.debug("RMI server started"); - else - logger.debug("Failed to initialize RMI server."); - } - } - - @Override - public void start(Stage primaryStage) { - logger.info("Starting application"); - logger.debug("Creating scene"); - ProgramController.createAndShow(ProgramController.DEFAULT_ROBBI_FILE_NAME); - logger.debug("Scene creation done"); - } - - @Override - public void stop() { - - logger.debug("Shutting down database connection"); - HibernateUtils.shutdown(); - - if (PropertiesLoader.isTutor()) { - logger.debug("Stopping Tutor-Server."); - if (TutorController.shutdown()) - logger.debug("Tutor RMI server stopped successfully."); - else - logger.debug("Failed to shutdown Tutor RMI server"); - } - - logger.debug("saving properties..."); - if (PropertiesLoader.finish()) - logger.debug("Properties saved"); - else - logger.debug("Failed to save properties"); - - logger.info("Quitting application"); - } + private static final String INIT_ERROR_MESSAGE = "Init.error.message"; + private static final String INIT_ERROR_TITLE = "Init.error.title"; + private static final String INIT_ERROR_HEADER = "Init.error.header"; + + /** + * Application entry point + * + * @param args the arguments from the command line + */ + public static void main(String[] args) { + try { + launch(args); + } catch (Exception e) { + logger.error("Failed to load application", e); + JOptionPane.showMessageDialog(null, """ + Failed to load application. + Further information can be obtained running the + application in the command line. + Please consider submitting your error. + """); + } + } + + @Override + public void init() { + logger.info("Initialize application"); + + logger.debug("Initializing properties..."); + if (PropertiesLoader.initialize()) { + logger.debug("Loaded properties successfully"); + } else + logger.debug("Failed to load properties."); + + I18nUtils.setBundle(ResourceBundle.getBundle("lang.messages", PropertiesLoader.getLocale())); + + logger.debug("Loading Program Controller"); + if (!ProgramController.initialize()) { + logger.error("Failed to load Program Controller"); + AlertHelper.showAlertAndWait(AlertType.ERROR, i18n(INIT_ERROR_MESSAGE), null, null, i18n(INIT_ERROR_TITLE), + i18n(INIT_ERROR_HEADER)); + Platform.exit(); + } + logger.debug("loading Program Controller successfully"); + + if (PropertiesLoader.isTutor()) { + logger.debug("Starting Tutor RMI server"); + if (TutorController.initialize()) + logger.debug("RMI server started"); + else + logger.debug("Failed to initialize RMI server."); + } + } + + @Override + public void start(Stage primaryStage) { + logger.info("Starting application"); + logger.debug("Creating scene"); + ProgramController.createAndShow(ProgramController.DEFAULT_ROBBI_FILE_NAME); + logger.debug("Scene creation done"); + } + + @Override + public void stop() { + + logger.debug("Shutting down database connection"); + HibernateUtils.shutdown(); + + if (PropertiesLoader.isTutor()) { + logger.debug("Stopping Tutor-Server."); + if (TutorController.shutdown()) + logger.debug("Tutor RMI server stopped successfully."); + else + logger.debug("Failed to shutdown Tutor RMI server"); + } + + logger.debug("saving properties..."); + if (PropertiesLoader.finish()) + logger.debug("Properties saved"); + else + logger.debug("Failed to save properties"); + + logger.info("Quitting application"); + } } \ No newline at end of file diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/ButtonState.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/ButtonState.java index c3c079e..8590463 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/ButtonState.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/ButtonState.java @@ -6,69 +6,68 @@ /** * This class stores the state of the currently selected territory button state. * The state should be modified by the editor tool buttons. - * + *

* If the TerritoryEventHandler does register a click, the eventHandler gets the * current state from this class - * - * @author Jonas Pohl * + * @author Jonas Pohl */ +@Getter +@Setter public class ButtonState { - /** - * Constant for the ButtonState NONE. - */ - public static final int NONE = -1; - /** - * Constant for the ButtonState ROBBI. - */ - public static final int ROBBI = 0; + /** + * Constant for the ButtonState NONE. + */ + public static final int NONE = -1; + /** + * Constant for the ButtonState ROBBI. + */ + public static final int ROBBI = 0; - /** - * Constant for the ButtonState HOLLOW. - */ - public static final int HOLLOW = 1; - /** - * Constant for the ButtonState PILE_OF_SCRAP. - */ - public static final int PILE_OF_SCRAP = 2; - /** - * Constant for the ButtonState STOCKPILE. - */ - public static final int STOCKPILE = 3; - /** - * Constant for the ButtonState ACCU. - */ - public static final int ACCU = 4; - /** - * Constant for the ButtonState SCREW. - */ - public static final int SCREW = 5; - /** - * Constant for the ButtonState NUT. - */ - public static final int NUT = 6; - /** - * Constant for the ButtonState CLEAR. - */ - public static final int CLEAR = 7; + /** + * Constant for the ButtonState HOLLOW. + */ + public static final int HOLLOW = 1; + /** + * Constant for the ButtonState PILE_OF_SCRAP. + */ + public static final int PILE_OF_SCRAP = 2; + /** + * Constant for the ButtonState STOCKPILE. + */ + public static final int STOCKPILE = 3; + /** + * Constant for the ButtonState ACCU. + */ + public static final int ACCU = 4; + /** + * Constant for the ButtonState SCREW. + */ + public static final int SCREW = 5; + /** + * Constant for the ButtonState NUT. + */ + public static final int NUT = 6; + /** + * Constant for the ButtonState CLEAR. + */ + public static final int CLEAR = 7; - @Getter - @Setter - private int selected; + private int selected; - /** - * Creates a new ButtonState and sets the selected state to NONE - */ - public ButtonState() { - selected = NONE; - } + /** + * Creates a new ButtonState and sets the selected state to NONE + */ + public ButtonState() { + selected = NONE; + } - /** - * reset the currently selected state to NONE - */ - public void deselect() { - selected = NONE; - } + /** + * reset the currently selected state to NONE + */ + public void deselect() { + selected = NONE; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/ChangeTerritorySizeHandler.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/ChangeTerritorySizeHandler.java index 2e2043e..1ac8253 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/ChangeTerritorySizeHandler.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/ChangeTerritorySizeHandler.java @@ -1,108 +1,102 @@ package com.JayPi4c.RobbiSimulator.controller; -import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; - -import java.util.Optional; - import com.JayPi4c.RobbiSimulator.model.Dimension; import com.JayPi4c.RobbiSimulator.model.Territory; - import javafx.application.Platform; import javafx.event.ActionEvent; import javafx.event.EventHandler; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.DialogPane; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; +import javafx.scene.control.*; import javafx.scene.layout.GridPane; import javafx.stage.Modality; import javafx.stage.Window; +import java.util.Optional; + +import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; + /** * This EventHandler combines all the code needed to change the territory size - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class ChangeTerritorySizeHandler implements EventHandler { - private Territory territory; + private final Territory territory; - private Dialog dialog; - private Window parent; + private Dialog dialog; + private final Window parent; - // language keys - private static final String CHANGESIZE_DIALOG_TITLE = "ChangeSize.dialog.title"; - private static final String CHANGESIZE_DIALOG_HEADER = "ChangeSize.dialog.header"; - private static final String CHANGESIZE_DIALOG_COLS = "ChangeSize.dialog.cols"; - private static final String CHANGESIZE_DIALOG_ROWS = "ChangeSize.dialog.rows"; + // language keys + private static final String CHANGESIZE_DIALOG_TITLE = "ChangeSize.dialog.title"; + private static final String CHANGESIZE_DIALOG_HEADER = "ChangeSize.dialog.header"; + private static final String CHANGESIZE_DIALOG_COLS = "ChangeSize.dialog.cols"; + private static final String CHANGESIZE_DIALOG_ROWS = "ChangeSize.dialog.rows"; - /** - * Creates a new ChangeTerritorySizeHandler and sets up a new Dialog, which can - * be invoked in the handle method - * - * @param territory The territory, which size should be changed - * @param parent The parent window in order to set the dialog relative to the - * current window - */ - public ChangeTerritorySizeHandler(Window parent, Territory territory) { - this.territory = territory; - this.parent = parent; - } + /** + * Creates a new ChangeTerritorySizeHandler and sets up a new Dialog, which can + * be invoked in the handle method + * + * @param territory The territory, which size should be changed + * @param parent The parent window in order to set the dialog relative to the + * current window + */ + public ChangeTerritorySizeHandler(Window parent, Territory territory) { + this.territory = territory; + this.parent = parent; + } - /** - * Creates a new Dialog to handle the size change. The Dialog will be newly - * created every time in order to have the correct language at every moment. - */ - private void createDialog() { - dialog = new Dialog<>(); - dialog.setTitle(i18n(CHANGESIZE_DIALOG_TITLE)); - dialog.setHeaderText(i18n(CHANGESIZE_DIALOG_HEADER)); - DialogPane dialogPane = dialog.getDialogPane(); - dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); - TextField rowField = new TextField(); - rowField.textProperty().addListener((observeable, oldVal, newVal) -> dialog.getDialogPane() - .lookupButton(ButtonType.OK).setDisable(newVal.isEmpty() || !isValid(newVal))); - TextField colField = new TextField(); - colField.textProperty().addListener((observable, oldVal, newVal) -> dialog.getDialogPane() - .lookupButton(ButtonType.OK).setDisable(newVal.isEmpty() || !isValid(newVal))); + /** + * Creates a new Dialog to handle the size change. The Dialog will be newly + * created every time in order to have the correct language at every moment. + */ + private void createDialog() { + dialog = new Dialog<>(); + dialog.setTitle(i18n(CHANGESIZE_DIALOG_TITLE)); + dialog.setHeaderText(i18n(CHANGESIZE_DIALOG_HEADER)); + DialogPane dialogPane = dialog.getDialogPane(); + dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); + TextField rowField = new TextField(); + rowField.textProperty().addListener((observeable, oldVal, newVal) -> dialog.getDialogPane() + .lookupButton(ButtonType.OK).setDisable(newVal.isEmpty() || !isValid(newVal))); + TextField colField = new TextField(); + colField.textProperty().addListener((observable, oldVal, newVal) -> dialog.getDialogPane() + .lookupButton(ButtonType.OK).setDisable(newVal.isEmpty() || !isValid(newVal))); - GridPane grid = new GridPane(); - grid.addRow(0, new Label(i18n(CHANGESIZE_DIALOG_COLS)), colField); - grid.addRow(1, new Label(i18n(CHANGESIZE_DIALOG_ROWS)), rowField); - grid.setHgap(20); - dialogPane.setContent(grid); - rowField.setText(Integer.toString(territory.getNumRows())); - colField.setText(Integer.toString(territory.getNumCols())); - Platform.runLater(colField::requestFocus); - dialog.setResultConverter(button -> button == ButtonType.OK - ? new Dimension(Integer.parseInt(colField.getText()), Integer.parseInt(rowField.getText())) - : null); - dialog.initModality(Modality.WINDOW_MODAL); - dialog.initOwner(parent); - } + GridPane grid = new GridPane(); + grid.addRow(0, new Label(i18n(CHANGESIZE_DIALOG_COLS)), colField); + grid.addRow(1, new Label(i18n(CHANGESIZE_DIALOG_ROWS)), rowField); + grid.setHgap(20); + dialogPane.setContent(grid); + rowField.setText(Integer.toString(territory.getNumRows())); + colField.setText(Integer.toString(territory.getNumCols())); + Platform.runLater(colField::requestFocus); + dialog.setResultConverter(button -> button == ButtonType.OK + ? new Dimension(Integer.parseInt(colField.getText()), Integer.parseInt(rowField.getText())) + : null); + dialog.initModality(Modality.WINDOW_MODAL); + dialog.initOwner(parent); + } - /** - * Checks if the given String is between 1 and 100. - * - * @param s the String which represents the user-input - * @return true if the s is > 0 and <= 100, false otherwise - */ - private boolean isValid(String s) { - try { - int val = Integer.parseInt(s); - return val > 0 && val <= 100; - } catch (NumberFormatException e) { - return false; - } - } + /** + * Checks if the given String is between 1 and 100. + * + * @param s the String which represents the user-input + * @return true if the s is > 0 and <= 100, false otherwise + */ + private boolean isValid(String s) { + try { + int val = Integer.parseInt(s); + return val > 0 && val <= 100; + } catch (NumberFormatException e) { + return false; + } + } - @Override - public void handle(ActionEvent event) { - createDialog(); - Optional optionalDimension = dialog.showAndWait(); - optionalDimension.ifPresent(result -> territory.changeSize(result.cols(), result.rows())); - } + @Override + public void handle(ActionEvent event) { + createDialog(); + Optional optionalDimension = dialog.showAndWait(); + optionalDimension.ifPresent(result -> territory.changeSize(result.cols(), result.rows())); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/LanguageController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/LanguageController.java index 0a1a7dd..086e76e 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/LanguageController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/LanguageController.java @@ -105,7 +105,7 @@ public class LanguageController { private static final String MENU_TUTOR_RECEIVEANSWER = "Menu.tutor.receiveAnswer"; private static final String MENU_TUTOR = "Menu.tutor"; private static final String MAIN_TITLE = "Main.title"; - private MainStage stage; + private final MainStage stage; /** * Constructor to create a new LanguageController. Sets the actions to the diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/MainStageController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/MainStageController.java index 340474b..4556a9d 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/MainStageController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/MainStageController.java @@ -48,14 +48,14 @@ @Slf4j public class MainStageController implements Observer { - private ButtonState buttonState; + private final ButtonState buttonState; - private MainStage mainStage; + private final MainStage mainStage; @Setter private boolean changeCursor = false; @Getter - private boolean soundsEnabled = false; + private final boolean soundsEnabled = false; private RadioMenuItem selectedRadioMenuItem = null; @@ -353,10 +353,7 @@ private File getFile(String description, String extension) { * has unsaved changes */ private String getTitle(Program program) { - StringBuilder builder = new StringBuilder(); - builder.append(i18n("Main.title")).append(": ").append(program.getName()) - .append((program.isEdited() ? "*" : "")); - return builder.toString(); + return i18n("Main.title") + ": " + program.getName() + (program.isEdited() ? "*" : ""); } /** diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/MethodHandler.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/MethodHandler.java index 458bbb9..7158944 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/MethodHandler.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/MethodHandler.java @@ -9,6 +9,7 @@ import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.control.Alert.AlertType; +import lombok.extern.slf4j.Slf4j; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; @@ -22,11 +23,12 @@ * * @author Jonas Pohl */ +@Slf4j public class MethodHandler implements EventHandler { - private Method method; - private Territory territory; - private MainStage parent; + private final Method method; + private final Territory territory; + private final MainStage parent; /** * Creates a new MethodHandler with the method and the territory the message is @@ -64,10 +66,10 @@ public void handle(ActionEvent event) { if (result != null) { AlertHelper.showAlertAndWait(AlertType.INFORMATION, - I18nUtils.i18n("Execution.information.result") + result.toString(), parent); + I18nUtils.i18n("Execution.information.result") + result, parent); } } catch (IllegalArgumentException | IllegalAccessException e) { - e.printStackTrace(); + logger.error("Failed to invoke method", e); } catch (InvocationTargetException e) { if (e.getCause() instanceof RobbiException) { parent.getNotificationController().showMessage(3000, e.getCause().getLocalizedMessage()); diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritoryEventHandler.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritoryEventHandler.java index 62fbc2a..fc26435 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritoryEventHandler.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritoryEventHandler.java @@ -4,121 +4,119 @@ import com.JayPi4c.RobbiSimulator.view.MainStage; import com.JayPi4c.RobbiSimulator.view.RobbiContextMenu; import com.JayPi4c.RobbiSimulator.view.TerritoryPanel; - import javafx.event.EventHandler; import javafx.scene.input.MouseEvent; /** * This class combines all functions needed to control the user interaction with * the territory - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class TerritoryEventHandler implements EventHandler { - private Territory territory; + private final Territory territory; - private boolean robbiDragged = false; + private boolean robbiDragged = false; - private ButtonState buttonState; + private final ButtonState buttonState; - private RobbiContextMenu robbiContextMenu; + private RobbiContextMenu robbiContextMenu; - /** - * Creates a new TerritoryEventHandler and sets the contextMenuRequest to show a - * RobbiContextMenu if the user right-clicks on Robbi - * - * @param territory the Territory this handler is for - * @param territoryPanel the TerritoryPanel, this handler is handling - * @param buttonState the ButtonState for this eventHandler - * @param parent the parent window to show alerts relative to it - */ - public TerritoryEventHandler(Territory territory, TerritoryPanel territoryPanel, ButtonState buttonState, - MainStage parent) { - this.territory = territory; - this.buttonState = buttonState; - territoryPanel.setOnContextMenuRequested(event -> { - if (territory.robbiOnTile(getCol(event.getX()), getRow(event.getY()))) { - robbiContextMenu = new RobbiContextMenu(territory, parent); - robbiContextMenu.show(territoryPanel.getScene().getWindow(), event.getScreenX(), event.getScreenY()); - } - }); + /** + * Creates a new TerritoryEventHandler and sets the contextMenuRequest to show a + * RobbiContextMenu if the user right-clicks on Robbi + * + * @param territory the Territory this handler is for + * @param territoryPanel the TerritoryPanel, this handler is handling + * @param buttonState the ButtonState for this eventHandler + * @param parent the parent window to show alerts relative to it + */ + public TerritoryEventHandler(Territory territory, TerritoryPanel territoryPanel, ButtonState buttonState, + MainStage parent) { + this.territory = territory; + this.buttonState = buttonState; + territoryPanel.setOnContextMenuRequested(event -> { + if (territory.robbiOnTile(getCol(event.getX()), getRow(event.getY()))) { + robbiContextMenu = new RobbiContextMenu(territory, parent); + robbiContextMenu.show(territoryPanel.getScene().getWindow(), event.getScreenX(), event.getScreenY()); + } + }); - } + } - /** - * {@inheritDoc}
- * Places an Item or Object in the territory or drags and drops the robbi - */ - @Override - public void handle(MouseEvent event) { - int col = getCol(event.getX()); - int row = getRow(event.getY()); - if (event.getEventType() == MouseEvent.MOUSE_PRESSED) { - robbiDragged = territory.robbiOnTile(col, row); - } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) { - if (robbiDragged) - territory.placeRobbi(col, row); - } else if (event.getEventType() == MouseEvent.MOUSE_RELEASED) { - if (!robbiDragged) { - switch (buttonState.getSelected()) { - case ButtonState.ROBBI: - territory.placeRobbi(col, row); - break; - case ButtonState.HOLLOW: - territory.placeHollow(col, row); - break; - case ButtonState.PILE_OF_SCRAP: - territory.placePileOfScrap(col, row); - break; - case ButtonState.STOCKPILE: - territory.placeStockpile(col, row); - break; - case ButtonState.ACCU: - territory.placeAccu(col, row); - break; - case ButtonState.SCREW: - territory.placeScrew(col, row); - break; - case ButtonState.NUT: - territory.placeNut(col, row); - break; - case ButtonState.CLEAR: - territory.clearTile(col, row); - break; - case ButtonState.NONE: - // fall through - default: - // Do nothing - } - } - robbiDragged = false; - } + /** + * {@inheritDoc}
+ * Places an Item or Object in the territory or drags and drops the robbi + */ + @Override + public void handle(MouseEvent event) { + int col = getCol(event.getX()); + int row = getRow(event.getY()); + if (event.getEventType() == MouseEvent.MOUSE_PRESSED) { + robbiDragged = territory.robbiOnTile(col, row); + } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) { + if (robbiDragged) + territory.placeRobbi(col, row); + } else if (event.getEventType() == MouseEvent.MOUSE_RELEASED) { + if (!robbiDragged) { + switch (buttonState.getSelected()) { + case ButtonState.ROBBI: + territory.placeRobbi(col, row); + break; + case ButtonState.HOLLOW: + territory.placeHollow(col, row); + break; + case ButtonState.PILE_OF_SCRAP: + territory.placePileOfScrap(col, row); + break; + case ButtonState.STOCKPILE: + territory.placeStockpile(col, row); + break; + case ButtonState.ACCU: + territory.placeAccu(col, row); + break; + case ButtonState.SCREW: + territory.placeScrew(col, row); + break; + case ButtonState.NUT: + territory.placeNut(col, row); + break; + case ButtonState.CLEAR: + territory.clearTile(col, row); + break; + case ButtonState.NONE: + // fall through + default: + // Do nothing + } + } + robbiDragged = false; + } - } + } - /** - * Calculates the column to a given horizontal mouse-position - * - * @param x Horizontal position of the event relative to the origin of the - * MouseEvent's source. - * @return column corresponding to the given x - */ - private int getCol(double x) { - return (int) (x / (TerritoryPanel.getCellsize() + TerritoryPanel.getCellspacer())); - } + /** + * Calculates the column to a given horizontal mouse-position + * + * @param x Horizontal position of the event relative to the origin of the + * MouseEvent's source. + * @return column corresponding to the given x + */ + private int getCol(double x) { + return (int) (x / (TerritoryPanel.getCellsize() + TerritoryPanel.getCellspacer())); + } - /** - * Calculates the row to a given vertical mouse-position - * - * @param y Vertical position of the event relative to the origin of the - * MouseEvent's source. - * @return row corresponding to the given y - */ - private int getRow(double y) { - return (int) (y / (TerritoryPanel.getCellsize() + TerritoryPanel.getCellspacer())); + /** + * Calculates the row to a given vertical mouse-position + * + * @param y Vertical position of the event relative to the origin of the + * MouseEvent's source. + * @return row corresponding to the given y + */ + private int getRow(double y) { + return (int) (y / (TerritoryPanel.getCellsize() + TerritoryPanel.getCellspacer())); - } + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritorySaveController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritorySaveController.java index 4a07c0d..c901caa 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritorySaveController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/TerritorySaveController.java @@ -1,36 +1,9 @@ package com.JayPi4c.RobbiSimulator.controller; -import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.Writer; -import java.util.Optional; - import com.JayPi4c.RobbiSimulator.controller.program.ProgramController; -import com.JayPi4c.RobbiSimulator.model.Accu; -import com.JayPi4c.RobbiSimulator.model.DIRECTION; -import com.JayPi4c.RobbiSimulator.model.Hollow; -import com.JayPi4c.RobbiSimulator.model.InvalidTerritoryException; -import com.JayPi4c.RobbiSimulator.model.Item; -import com.JayPi4c.RobbiSimulator.model.Nut; -import com.JayPi4c.RobbiSimulator.model.PileOfScrap; -import com.JayPi4c.RobbiSimulator.model.Screw; -import com.JayPi4c.RobbiSimulator.model.Stockpile; -import com.JayPi4c.RobbiSimulator.model.Territory; -import com.JayPi4c.RobbiSimulator.model.TerritoryState; +import com.JayPi4c.RobbiSimulator.model.*; import com.JayPi4c.RobbiSimulator.utils.AlertHelper; import com.JayPi4c.RobbiSimulator.view.MainStage; - import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.Marshaller; @@ -39,242 +12,242 @@ import javafx.stage.FileChooser; import lombok.extern.slf4j.Slf4j; +import java.io.*; +import java.util.Optional; + +import static com.JayPi4c.RobbiSimulator.utils.I18nUtils.i18n; + /** * Controller to handle all territory save action. It handles load and save * actions for all supported formats. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j public class TerritorySaveController { - private static final String DEFAULT_SERIALISATION_FILE_EXTENSION = ".ter"; - private static final String DEFAULT_XML_FILE_EXTENSION = ".rsxml"; - private static final String DEFAULT_JAXB_FILE_EXTENSION = ".rsjaxb"; - - private MainStage mainStage; - - /** - * Constructor to create a new TerritorySaveController for the given mainStage. - * - * @param mainStage the mainStage this controller is for - */ - public TerritorySaveController(MainStage mainStage) { - this.mainStage = mainStage; - this.mainStage.getMenubar().getSaveSerialTerritoryMenuItem().setOnAction(e -> serialize()); - this.mainStage.getMenubar().getLoadSerialTerritoryMenuItem().setOnAction(e -> deserialize()); - - this.mainStage.getMenubar().getSaveXMLTerritoryMenuItem().setOnAction(e -> saveXMLtoFile()); - this.mainStage.getMenubar().getLoadXMLTerritoryMenuItem().setOnAction(e -> loadXMLfromFile()); - - this.mainStage.getMenubar().getSaveJAXBTerritoryMenuItem().setOnAction(e -> saveJAXB()); - this.mainStage.getMenubar().getLoadJAXBTerritoryMenuItem().setOnAction(e -> loadJAXB()); - } - - /** - * Helper to serialize the territory of the mainStage into a file. - */ - private void serialize() { - Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), - i18n("Territory.save.dialog.filter.serial"), DEFAULT_SERIALISATION_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file was selected to serialze in."); - return; - } - - File file = fileOpt.get(); - if (!file.getName().endsWith(DEFAULT_SERIALISATION_FILE_EXTENSION)) { - file = new File(file.getAbsolutePath() + DEFAULT_SERIALISATION_FILE_EXTENSION); - } - - logger.debug("serialize in file {}", file); - try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) { - synchronized (mainStage.getTerritory()) { - oos.writeObject(mainStage.getTerritory()); - oos.writeObject(mainStage.getTerritory().getRobbiItem()); - oos.writeInt(mainStage.getTerritory().getRobbiX()); - oos.writeInt(mainStage.getTerritory().getRobbiY()); - oos.writeObject(mainStage.getTerritory().getRobbiDirection()); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - logger.info("finished serialization"); - } - - } - - /** - * Helper to deserialize a territory from a file and update the old territory to - * the new values. - */ - private void deserialize() { - Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), - i18n("Territory.load.dialog.filter.deserial"), DEFAULT_SERIALISATION_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file was selected to deserialize from."); - return; - } - File file = fileOpt.get(); - - try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { - logger.debug("deserialize from file {}", file); - Territory t = (Territory) ois.readObject(); - Item item = (Item) ois.readObject(); - int x = ois.readInt(); - int y = ois.readInt(); - DIRECTION facing = (DIRECTION) ois.readObject(); - mainStage.getTerritory().update(t, item, x, y, facing); - } catch (InvalidTerritoryException e) { - AlertHelper.showAlertAndWait(AlertType.WARNING, i18n("Territory.load.failure"), mainStage); - } catch (IOException | ClassNotFoundException e) { - e.printStackTrace(); - } finally { - logger.info("finished deserialization"); - } - } - - /** - * Asks for a file to save the xml to and then writes the territory into this - * file. - */ - private void saveXMLtoFile() { - Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), - i18n("Territory.save.dialog.filter.xml"), DEFAULT_XML_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file selected to save territory in."); - return; - } - File file = fileOpt.get(); - - if (!file.getName().endsWith(DEFAULT_XML_FILE_EXTENSION)) { - file = new File(file.getAbsolutePath() + DEFAULT_XML_FILE_EXTENSION); - } - - logger.debug("save as XML in file {}", file); - try (ByteArrayOutputStream baos = mainStage.getTerritory().toXML(); - OutputStream outputStream = new FileOutputStream(file.getAbsolutePath())) { - baos.writeTo(outputStream); - } catch (IOException e) { - logger.debug("failed"); - } - - } - - /** - * Asks for an XML-File and loads the contents into the territory. - */ - private void loadXMLfromFile() { - Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), - i18n("Territory.load.dialog.filter.xml"), DEFAULT_XML_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file selected to load XML from."); - return; - } - - File file = fileOpt.get(); - logger.debug("load territory from xml-file {}", file); - try { - if (mainStage.getTerritory().fromXML(new FileInputStream(file))) - logger.info("finished loading from xml-file"); - else - logger.info("Failed loading from xml-file"); - } catch (FileNotFoundException e) { - logger.debug("Could not find file {}", file.getAbsolutePath()); - } - - } - - /** - * Loads a territory by a filename using JAXB - * - * @return true if the territory was loaded successfully, false otherwise - */ - private void loadJAXB() { - Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), - i18n("Territory.load.dialog.filter.jaxb"), DEFAULT_JAXB_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file selected"); - return; - } - File file = fileOpt.get(); - logger.debug("load territory from jaxb-file {}", file); - try { - JAXBContext context = JAXBContext.newInstance(TerritoryState.class, Nut.class, Screw.class, Accu.class, - Stockpile.class, PileOfScrap.class, Hollow.class); - Unmarshaller um = context.createUnmarshaller(); - TerritoryState ter = (TerritoryState) um.unmarshal(new FileReader(file)); - mainStage.getTerritory().restore(ter); - } catch (IOException | JAXBException e) { - e.printStackTrace(); - logger.debug("failed to load JAXB"); - } - } - - /** - * Saves the territory using JAXB. - */ - private void saveJAXB() { - Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), - i18n("Territory.save.dialog.filter.jaxb"), DEFAULT_JAXB_FILE_EXTENSION); - - if (fileOpt.isEmpty()) { - logger.debug("No file selected to save territory in."); - return; - } - File file = fileOpt.get(); - if (!file.getName().endsWith(DEFAULT_JAXB_FILE_EXTENSION)) { - file = new File(file.getAbsolutePath() + DEFAULT_JAXB_FILE_EXTENSION); - } - logger.debug("save territory from jaxb-file {}", file); - try (Writer w = new FileWriter(file)) { - JAXBContext context = JAXBContext.newInstance(TerritoryState.class, Nut.class, Screw.class, Accu.class, - Stockpile.class, PileOfScrap.class, Hollow.class); - Marshaller m = context.createMarshaller(); - m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - m.marshal(mainStage.getTerritory().save(), w); - } catch (IOException | JAXBException e) { - e.printStackTrace(); - logger.debug("failed to save jaxb"); - } - } - - /** - * Opens a dialog to ask for a file to save the territory in. - * - * @param title the title of the dialog - * @param description file description for the allowed files - * @param fileExtension allowed file-extension - * @return a file to save the territory in - */ - private Optional getSaveFile(String title, String description, String fileExtension) { - FileChooser chooser = new FileChooser(); - chooser.setTitle(title); - chooser.setInitialDirectory(new File(ProgramController.PATH_TO_PROGRAMS)); - chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(description, "*" + fileExtension)); - return Optional.ofNullable(chooser.showSaveDialog(mainStage)); - } - - /** - * Opens a dialog to ask for a file to load a territory from. - * - * @param title the title of the dialog - * @param description file description for allowed files - * @param fileExtension allowed file-extension - * @return a file to load a territory from - */ - public Optional getLoadFile(String title, String description, String fileExtension) { - FileChooser fileChooser = new FileChooser(); - fileChooser.setTitle(title); - fileChooser.setInitialDirectory(new File(ProgramController.PATH_TO_PROGRAMS)); - fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(description, "*" + fileExtension)); - return Optional.ofNullable(fileChooser.showOpenDialog(mainStage)); - } + private static final String DEFAULT_SERIALISATION_FILE_EXTENSION = ".ter"; + private static final String DEFAULT_XML_FILE_EXTENSION = ".rsxml"; + private static final String DEFAULT_JAXB_FILE_EXTENSION = ".rsjaxb"; + + private final MainStage mainStage; + + /** + * Constructor to create a new TerritorySaveController for the given mainStage. + * + * @param mainStage the mainStage this controller is for + */ + public TerritorySaveController(MainStage mainStage) { + this.mainStage = mainStage; + this.mainStage.getMenubar().getSaveSerialTerritoryMenuItem().setOnAction(e -> serialize()); + this.mainStage.getMenubar().getLoadSerialTerritoryMenuItem().setOnAction(e -> deserialize()); + + this.mainStage.getMenubar().getSaveXMLTerritoryMenuItem().setOnAction(e -> saveXMLtoFile()); + this.mainStage.getMenubar().getLoadXMLTerritoryMenuItem().setOnAction(e -> loadXMLfromFile()); + + this.mainStage.getMenubar().getSaveJAXBTerritoryMenuItem().setOnAction(e -> saveJAXB()); + this.mainStage.getMenubar().getLoadJAXBTerritoryMenuItem().setOnAction(e -> loadJAXB()); + } + + /** + * Helper to serialize the territory of the mainStage into a file. + */ + private void serialize() { + Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), + i18n("Territory.save.dialog.filter.serial"), DEFAULT_SERIALISATION_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file was selected to serialze in."); + return; + } + + File file = fileOpt.get(); + if (!file.getName().endsWith(DEFAULT_SERIALISATION_FILE_EXTENSION)) { + file = new File(file.getAbsolutePath() + DEFAULT_SERIALISATION_FILE_EXTENSION); + } + + logger.debug("serialize in file {}", file); + try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file))) { + synchronized (mainStage.getTerritory()) { + oos.writeObject(mainStage.getTerritory()); + oos.writeObject(mainStage.getTerritory().getRobbiItem()); + oos.writeInt(mainStage.getTerritory().getRobbiX()); + oos.writeInt(mainStage.getTerritory().getRobbiY()); + oos.writeObject(mainStage.getTerritory().getRobbiDirection()); + } + } catch (IOException e) { + logger.error("Failed to serialize territory", e); + } finally { + logger.info("finished serialization"); + } + + } + + /** + * Helper to deserialize a territory from a file and update the old territory to + * the new values. + */ + private void deserialize() { + Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), + i18n("Territory.load.dialog.filter.deserial"), DEFAULT_SERIALISATION_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file was selected to deserialize from."); + return; + } + File file = fileOpt.get(); + + try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) { + logger.debug("deserialize from file {}", file); + Territory t = (Territory) ois.readObject(); + Item item = (Item) ois.readObject(); + int x = ois.readInt(); + int y = ois.readInt(); + DIRECTION facing = (DIRECTION) ois.readObject(); + mainStage.getTerritory().update(t, item, x, y, facing); + } catch (InvalidTerritoryException e) { + AlertHelper.showAlertAndWait(AlertType.WARNING, i18n("Territory.load.failure"), mainStage); + } catch (IOException | ClassNotFoundException e) { + logger.error("Failed to deserialize territory", e); + } finally { + logger.info("finished deserialization"); + } + } + + /** + * Asks for a file to save the xml to and then writes the territory into this + * file. + */ + private void saveXMLtoFile() { + Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), + i18n("Territory.save.dialog.filter.xml"), DEFAULT_XML_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file selected to save territory in."); + return; + } + File file = fileOpt.get(); + + if (!file.getName().endsWith(DEFAULT_XML_FILE_EXTENSION)) { + file = new File(file.getAbsolutePath() + DEFAULT_XML_FILE_EXTENSION); + } + + logger.debug("save as XML in file {}", file); + try (ByteArrayOutputStream baos = mainStage.getTerritory().toXML(); + OutputStream outputStream = new FileOutputStream(file.getAbsolutePath())) { + baos.writeTo(outputStream); + } catch (IOException e) { + logger.debug("failed"); + } + + } + + /** + * Asks for an XML-File and loads the contents into the territory. + */ + private void loadXMLfromFile() { + Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), + i18n("Territory.load.dialog.filter.xml"), DEFAULT_XML_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file selected to load XML from."); + return; + } + + File file = fileOpt.get(); + logger.debug("load territory from xml-file {}", file); + try { + if (mainStage.getTerritory().fromXML(new FileInputStream(file))) + logger.info("finished loading from xml-file"); + else + logger.info("Failed loading from xml-file"); + } catch (FileNotFoundException e) { + logger.debug("Could not find file {}", file.getAbsolutePath()); + } + + } + + /** + * Loads a territory by a filename using JAXB + */ + private void loadJAXB() { + Optional fileOpt = getLoadFile(i18n("Territory.load.dialog.title"), + i18n("Territory.load.dialog.filter.jaxb"), DEFAULT_JAXB_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file selected"); + return; + } + File file = fileOpt.get(); + logger.debug("load territory from jaxb-file {}", file); + try { + JAXBContext context = JAXBContext.newInstance(TerritoryState.class, Nut.class, Screw.class, Accu.class, + Stockpile.class, PileOfScrap.class, Hollow.class); + Unmarshaller um = context.createUnmarshaller(); + TerritoryState ter = (TerritoryState) um.unmarshal(new FileReader(file)); + mainStage.getTerritory().restore(ter); + } catch (IOException | JAXBException e) { + logger.error("failed to load JAXB.", e); + } + } + + /** + * Saves the territory using JAXB. + */ + private void saveJAXB() { + Optional fileOpt = getSaveFile(i18n("Territory.save.dialog.title"), + i18n("Territory.save.dialog.filter.jaxb"), DEFAULT_JAXB_FILE_EXTENSION); + + if (fileOpt.isEmpty()) { + logger.debug("No file selected to save territory in."); + return; + } + File file = fileOpt.get(); + if (!file.getName().endsWith(DEFAULT_JAXB_FILE_EXTENSION)) { + file = new File(file.getAbsolutePath() + DEFAULT_JAXB_FILE_EXTENSION); + } + logger.debug("save territory from jaxb-file {}", file); + try (Writer w = new FileWriter(file)) { + JAXBContext context = JAXBContext.newInstance(TerritoryState.class, Nut.class, Screw.class, Accu.class, + Stockpile.class, PileOfScrap.class, Hollow.class); + Marshaller m = context.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + m.marshal(mainStage.getTerritory().save(), w); + } catch (IOException | JAXBException e) { + logger.debug("failed to save jaxb.", e); + } + } + + /** + * Opens a dialog to ask for a file to save the territory in. + * + * @param title the title of the dialog + * @param description file description for the allowed files + * @param fileExtension allowed file-extension + * @return a file to save the territory in + */ + private Optional getSaveFile(String title, String description, String fileExtension) { + FileChooser chooser = new FileChooser(); + chooser.setTitle(title); + chooser.setInitialDirectory(new File(ProgramController.PATH_TO_PROGRAMS)); + chooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(description, "*" + fileExtension)); + return Optional.ofNullable(chooser.showSaveDialog(mainStage)); + } + + /** + * Opens a dialog to ask for a file to load a territory from. + * + * @param title the title of the dialog + * @param description file description for allowed files + * @param fileExtension allowed file-extension + * @return a file to load a territory from + */ + public Optional getLoadFile(String title, String description, String fileExtension) { + FileChooser fileChooser = new FileChooser(); + fileChooser.setTitle(title); + fileChooser.setInitialDirectory(new File(ProgramController.PATH_TO_PROGRAMS)); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(description, "*" + fileExtension)); + return Optional.ofNullable(fileChooser.showOpenDialog(mainStage)); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/Example.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/Example.java index f53cd69..e49cd4b 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/Example.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/Example.java @@ -1,56 +1,46 @@ package com.JayPi4c.RobbiSimulator.controller.examples; -import java.util.List; - import com.JayPi4c.RobbiSimulator.controller.program.ProgramController; - -import jakarta.persistence.CollectionTable; -import jakarta.persistence.Column; -import jakarta.persistence.ElementCollection; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Lob; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Data; +import java.util.List; + /** * This class holds all information needed for an example to be loaded. It * provides a method to load a new MainStage with the given Information. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Data @Entity @Table(name = "EXAMPLES") public class Example { - @Id - @Column(unique = true, nullable = false) - @GeneratedValue(strategy = GenerationType.AUTO) - private int id; + @Id + @Column(unique = true, nullable = false) + @GeneratedValue(strategy = GenerationType.AUTO) + private int id; - private String programName; + private String programName; - @Lob - @Column(columnDefinition = "clob") - private String code; + @Lob + @Column(columnDefinition = "clob") + private String code; - @Lob - @Column(columnDefinition = "clob") - private String territory; + @Lob + @Column(columnDefinition = "clob") + private String territory; - @ElementCollection - @CollectionTable(name = "TAGS") - private List tags; + @ElementCollection + @CollectionTable(name = "TAGS") + private List tags; - /** - * Loads a new MainStage with the given information. - */ - public void load() { - ProgramController.createAndShow(programName, code, territory); - } + /** + * Loads a new MainStage with the given information. + */ + public void load() { + ProgramController.createAndShow(programName, code, territory); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/ExampleService.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/ExampleService.java index 53cbdd8..51b9a3b 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/ExampleService.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/examples/ExampleService.java @@ -1,21 +1,19 @@ package com.JayPi4c.RobbiSimulator.controller.examples; -import java.util.List; -import java.util.Optional; - -import org.hibernate.Session; - import com.JayPi4c.RobbiSimulator.utils.HibernateUtils; - import javafx.util.Pair; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hibernate.Session; + +import java.util.List; +import java.util.Optional; /** * Service to easily access examples from the database using the HibernateUtils * class. - * + * * @author Jonas Pohl * @since 1.0.0 */ @@ -23,79 +21,79 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class ExampleService { - /** - * Method to store an example with its tags in the database. - * - * @param programName the name of the program - * @param editorContent the code in the editor - * @param territoryXML the territory encoded in XML - * @param tags the tags related to this example - * @return true if the example was stored successfully, false otherwise - */ - public static boolean store(String programName, String editorContent, String territoryXML, List tags) { - Example example = new Example(); - example.setProgramName(programName); - example.setCode(editorContent); - example.setTerritory(territoryXML); - example.setTags(tags); + /** + * Method to store an example with its tags in the database. + * + * @param programName the name of the program + * @param editorContent the code in the editor + * @param territoryXML the territory encoded in XML + * @param tags the tags related to this example + * @return true if the example was stored successfully, false otherwise + */ + public static boolean store(String programName, String editorContent, String territoryXML, List tags) { + Example example = new Example(); + example.setProgramName(programName); + example.setCode(editorContent); + example.setTerritory(territoryXML); + example.setTags(tags); - try (Session session = HibernateUtils.getSessionFactory().openSession()) { - session.beginTransaction(); - session.merge(example); - session.getTransaction().commit(); - return true; - } catch (Exception e) { - logger.error("Could not store example", e); - return false; - } - } + try (Session session = HibernateUtils.getSessionFactory().openSession()) { + session.beginTransaction(); + session.merge(example); + session.getTransaction().commit(); + return true; + } catch (Exception e) { + logger.error("Could not store example", e); + return false; + } + } - /** - * Method to get all examples identified by id and programName by their tag. - * - * @param tag the tag to search the examples for - * @return List of examples as pairs of id and programName - */ - public static Optional>> query(String tag) { - try (Session session = HibernateUtils.getSessionFactory().openSession()) { - List allExamples = session.createQuery("from Example", Example.class).list(); + /** + * Method to get all examples identified by id and programName by their tag. + * + * @param tag the tag to search the examples for + * @return List of examples as pairs of id and programName + */ + public static Optional>> query(String tag) { + try (Session session = HibernateUtils.getSessionFactory().openSession()) { + List allExamples = session.createQuery("from Example", Example.class).list(); - List taggedExamples = allExamples.stream().filter(ex -> ex.getTags().contains(tag)).toList(); + List taggedExamples = allExamples.stream().filter(ex -> ex.getTags().contains(tag)).toList(); - return Optional.of(taggedExamples.stream().map(ex -> new Pair<>(ex.getId(), ex.getProgramName())).toList()); - } - } + return Optional.of(taggedExamples.stream().map(ex -> new Pair<>(ex.getId(), ex.getProgramName())).toList()); + } + } - /** - * Loads an example from the database by the given id. - * - * @param id the ID of the example to load - * @return Optional containing the example or an empty Optional if no example - * could be found - */ - public static Optional loadExample(int id) { - Example example; - try (Session session = HibernateUtils.getSessionFactory().openSession()) { - session.beginTransaction(); - example = session.get(Example.class, id); - session.getTransaction().commit(); - } - return Optional.ofNullable(example); - } + /** + * Loads an example from the database by the given id. + * + * @param id the ID of the example to load + * @return Optional containing the example or an empty Optional if no example + * could be found + */ + public static Optional loadExample(int id) { + Example example; + try (Session session = HibernateUtils.getSessionFactory().openSession()) { + session.beginTransaction(); + example = session.get(Example.class, id); + session.getTransaction().commit(); + } + return Optional.ofNullable(example); + } - /** - * Method to load all distinct tags from the database. - * - * @return List of all distinct tags stored in the database - */ - public static Optional> getAllTags() { - List tags; - try (Session session = HibernateUtils.getSessionFactory().openSession()) { - List allExamples = session.createQuery("from Example", Example.class).list(); - logger.debug("Found {} examples", allExamples.size()); - tags = allExamples.stream().flatMap(ex -> ex.getTags().stream()).distinct().toList(); - } - return Optional.of(tags); - } + /** + * Method to load all distinct tags from the database. + * + * @return List of all distinct tags stored in the database + */ + public static Optional> getAllTags() { + List tags; + try (Session session = HibernateUtils.getSessionFactory().openSession()) { + List allExamples = session.createQuery("from Example", Example.class).list(); + logger.debug("Found {} examples", allExamples.size()); + tags = allExamples.stream().flatMap(ex -> ex.getTags().stream()).distinct().toList(); + } + return Optional.of(tags); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Diagnostics.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Diagnostics.java index a7dd7c4..a58bf3a 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Diagnostics.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Diagnostics.java @@ -4,52 +4,49 @@ import java.util.List; /** - * * This class contains a list of Diagnostics, which are created during the * post-compile annotation check. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class Diagnostics { - private List diags; - - /** - * Constructor for the Diagnostics-class. It creates the list to hold the - * diagnostics. - */ - public Diagnostics() { - diags = new ArrayList<>(); - } - - /** - * Adds the given diagnostic to the list of diagnostics - * - * @param d The Diagnostic to be added to the list of diagnostics - */ - public void add(Diagnostic d) { - diags.add(d); - } - - /** - * Returns a list of all collected Diagnostics. - * - * @return the list of all diagnostics - */ - public List getDiagnosis() { - return diags; - } - - /** - * Container to hold a single Diagnostic, which consists of a type and the - * faulty value provided for this type. - * - * @author Jonas Pohl - * - */ - public record Diagnostic(String type, String value) { - - } + private final List diags; + + /** + * Constructor for the Diagnostics-class. It creates the list to hold the + * diagnostics. + */ + public Diagnostics() { + diags = new ArrayList<>(); + } + + /** + * Adds the given diagnostic to the list of diagnostics + * + * @param d The Diagnostic to be added to the list of diagnostics + */ + public void add(Diagnostic d) { + diags.add(d); + } + + /** + * Returns a list of all collected Diagnostics. + * + * @return the list of all diagnostics + */ + public List getDiagnosis() { + return diags; + } + + /** + * Container to hold a single Diagnostic, which consists of a type and the + * faulty value provided for this type. + * + * @author Jonas Pohl + */ + public record Diagnostic(String type, String value) { + + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Program.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Program.java index 7685dad..b926aa8 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Program.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/Program.java @@ -1,108 +1,103 @@ package com.JayPi4c.RobbiSimulator.controller.program; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; - import com.JayPi4c.RobbiSimulator.utils.Observable; - import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import java.io.*; /** * This class contains the contents, the name of program and whether it is * edited or not - * - * @author Jonas Pohl * + * @author Jonas Pohl */ +@Slf4j @Getter public class Program extends Observable { - /** - * The name of the program - */ - @Setter - private String name; + /** + * The name of the program + */ + @Setter + private String name; - private String editorContent; - private File file; + private String editorContent; + private final File file; - /** - * Whether the program is edited or not - */ - @Setter - private boolean edited = false; + /** + * Whether the program is edited or not + */ + @Setter + private boolean edited = false; - /** - * Creates and loads a program from a given file and the program name - * - * @param f the file on the fileSystem storing the program - * @param name the name of the program - */ - public Program(File f, String name) { - this.file = f; - this.name = name; - try (BufferedReader reader = new BufferedReader(new FileReader(f))) { - StringBuilder bobTheBuilder = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - bobTheBuilder.append(line); - bobTheBuilder.append(System.lineSeparator()); - } + /** + * Creates and loads a program from a given file and the program name + * + * @param f the file on the fileSystem storing the program + * @param name the name of the program + */ + public Program(File f, String name) { + this.file = f; + this.name = name; + try (BufferedReader reader = new BufferedReader(new FileReader(f))) { + StringBuilder bobTheBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + bobTheBuilder.append(line); + bobTheBuilder.append(System.lineSeparator()); + } - String content = bobTheBuilder.toString(); + String content = bobTheBuilder.toString(); - editorContent = content.replace(ProgramController.createPrefix(name), ""); - int endIndex = editorContent.lastIndexOf('}'); - bobTheBuilder.setLength(0); - editorContent = bobTheBuilder.append(editorContent).deleteCharAt(endIndex).toString().trim(); - } catch (IOException e) { - e.printStackTrace(); - } - } + editorContent = content.replace(ProgramController.createPrefix(name), ""); + int endIndex = editorContent.lastIndexOf('}'); + bobTheBuilder.setLength(0); + editorContent = bobTheBuilder.append(editorContent).deleteCharAt(endIndex).toString().trim(); + } catch (IOException e) { + logger.error("Could not load program", e); + } + } - /** - * Sets the editorContent and notifies all Observers, namely the - * MainStageController to update the textEditors content. - * - * @param content the new content - */ - public void setEditorContent(String content) { - this.editorContent = content; - this.edited = true; - this.setChanged(); - this.notifyAllObservers(); - } + /** + * Sets the editorContent and notifies all Observers, namely the + * MainStageController to update the textEditors content. + * + * @param content the new content + */ + public void setEditorContent(String content) { + this.editorContent = content; + this.edited = true; + this.setChanged(); + this.notifyAllObservers(); + } - /** - * saves the text of the editor-content into the corresponding file It does only - * save the given text, if the changes were made - * - * @param text the text to save in the file - */ - public void save(String text) { - if (!edited) - return; + /** + * saves the text of the editor-content into the corresponding file It does only + * save the given text, if the changes were made + * + * @param text the text to save in the file + */ + public void save(String text) { + if (!edited) + return; - editorContent = text; - save(); - } + editorContent = text; + save(); + } - /** - * Forces the program to be saved even if it might not be edited. - */ - public void save() { - String content = ProgramController.createTemplate(name, editorContent); - try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - writer.write(content); - } catch (IOException e) { - e.printStackTrace(); - } - edited = false; - } + /** + * Forces the program to be saved even if it might not be edited. + */ + public void save() { + String content = ProgramController.createTemplate(name, editorContent); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { + writer.write(content); + } catch (IOException e) { + logger.error("Could not save program", e); + } + edited = false; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/ProgramController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/ProgramController.java index a902cc6..b26cc9e 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/ProgramController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/program/ProgramController.java @@ -45,7 +45,7 @@ public class ProgramController { /** - * Constant String with the Path name for the programs directory. + * Constant String with the Path name for the programs' directory. */ public static final String PATH_TO_PROGRAMS = "programs"; /** @@ -118,14 +118,14 @@ public static boolean initialize() { if (!defaultProgram.createNewFile()) return false; } catch (IOException e) { - e.printStackTrace(); + logger.error("Could not create file", e); return false; } try (BufferedWriter writer = new BufferedWriter(new FileWriter(defaultProgram))) { writer.write(createTemplate(DEFAULT_ROBBI_FILE_NAME, DEFAULT_CONTENT)); } catch (IOException e) { - e.printStackTrace(); + logger.error("Could not write to file", e); return false; } } @@ -142,6 +142,8 @@ private static Collection getFilenamesInDirectory() { // get a list of all files in programs directory that end with .java File[] files = new File(PATH_TO_PROGRAMS) .listFiles(file -> (file.isFile() && file.getName().endsWith(DEFAULT_FILE_EXTENSION))); + if (files == null) + return Collections.emptySet(); // get a String collection with all filenames in the programs directory Collection filenamesInDirectory = Arrays.stream(files) .map(file -> file.getName().replace(DEFAULT_FILE_EXTENSION, "")) @@ -154,7 +156,7 @@ private static Collection getFilenamesInDirectory() { /** * Creates a Dialog and asks the user to for the name of the new program. - * Afterwards, it initiates the creation of a new stage for the program. + * Afterward, it initiates the creation of a new stage for the program. * * @param parent the parent window to show alerts relative to the parent window * @see ProgramController#createAndShow(String) @@ -216,12 +218,12 @@ public static void createAndShow(String programName) { if (!f.createNewFile()) logger.debug("Could not create file '{}'", f.getAbsolutePath()); } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to create file", e); } try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) { writer.write(content); } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to write to file", e); } } @@ -299,12 +301,12 @@ public static void createAndShow(String programName, String programCode, String if (!f.createNewFile()) logger.debug("Could not create file '{}'", f.getAbsolutePath()); } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to create file", e); } try (BufferedWriter writer = new BufferedWriter(new FileWriter(f))) { writer.write(content); } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to write to file", e); } } @@ -427,17 +429,15 @@ public static void compile(Program program, boolean showAlerts, Window parent) { try (StandardJavaFileManager manager = javac.getStandardFileManager(diagnostics, null, null)) { Iterable units = manager - .getJavaFileObjectsFromFiles(Arrays.asList(program.getFile())); + .getJavaFileObjectsFromFiles(Collections.singletonList(program.getFile())); // https://stackoverflow.com/questions/60016127/can-toolprovider-getsystemjavacompiler-access-runtime-generated-in-memory-sour CompilationTask task = javac.getTask(null, manager, diagnostics, List.of("-p", System.getProperty("jdk.module.path")), null, units); task.addModules(List.of("RobbiSimulator")); //https://docs.oracle.com/javase%2F9%2Fdocs%2Fapi%2F%2F/javax/tools/JavaCompiler.CompilationTask.html if (Boolean.FALSE.equals(task.call())) { boolean showedAlert = false; // flag to indicate that only one alert is shown - diagnostics.toString(); logger.error("Compilation failed"); for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { - diagnostic.toString(); logger.error("Kind: {}", diagnostic.getKind()); logger.error("Quelle: {}", diagnostic.getSource()); @@ -448,13 +448,11 @@ public static void compile(Program program, boolean showAlerts, Window parent) { diagnostic.getEndPosition()); // TODO change String.format to use i18n directly if (showAlerts && !showedAlert) { - StringBuilder bobTheBuilder = new StringBuilder(); - bobTheBuilder.append(String.format(i18n(COMPILATION_DIAGNOSTIC_KIND), diagnostic.getKind())); - bobTheBuilder.append(String.format(i18n(COMPILATION_DIAGNOSTIC_CODEANDMESSAGE), - diagnostic.getCode(), diagnostic.getMessage(null))); - bobTheBuilder.append( - String.format(i18n(COMPILATION_DIAGNOSTIC_ROW), diagnostic.getLineNumber() - 1)); - AlertHelper.showAlertAndWait(AlertType.ERROR, bobTheBuilder.toString(), parent, + String bobTheBuilder = String.format(i18n(COMPILATION_DIAGNOSTIC_KIND), diagnostic.getKind()) + + String.format(i18n(COMPILATION_DIAGNOSTIC_CODEANDMESSAGE), + diagnostic.getCode(), diagnostic.getMessage(null)) + + String.format(i18n(COMPILATION_DIAGNOSTIC_ROW), diagnostic.getLineNumber() - 1); + AlertHelper.showAlertAndWait(AlertType.ERROR, bobTheBuilder, parent, Modality.WINDOW_MODAL, i18n(COMPILATION_DIAGNOSTIC_TITLE), diagnostic.getKind().toString()); showedAlert = true; @@ -505,7 +503,7 @@ Modality.WINDOW_MODAL, i18n(COMPILATION_DIAGNOSTIC_TITLE), } } catch (IOException e) { - e.printStackTrace(); + logger.error("Failed to compile program", e); } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/Simulation.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/Simulation.java index c8a8c11..05d48a2 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/Simulation.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/Simulation.java @@ -1,15 +1,11 @@ package com.JayPi4c.RobbiSimulator.controller.simulation; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - import com.JayPi4c.RobbiSimulator.model.RobbiException; import com.JayPi4c.RobbiSimulator.model.Territory; import com.JayPi4c.RobbiSimulator.utils.AlertHelper; import com.JayPi4c.RobbiSimulator.utils.Observable; import com.JayPi4c.RobbiSimulator.utils.Observer; import com.JayPi4c.RobbiSimulator.utils.SoundManager; - import javafx.application.Platform; import javafx.scene.control.Alert.AlertType; import javafx.stage.Window; @@ -17,109 +13,111 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + /** - * This Simulation class is a separate thread that runs the code of robbis + * This Simulation class is a separate thread that runs the code of robbi's * main-Method. It can be paused, resumed and stopped by the user at any time. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j public class Simulation extends Thread implements Observer { - private Territory territory; - private SimulationController simController; - private Window parent; + private final Territory territory; + private final SimulationController simController; + private final Window parent; - @Getter - @Setter - private volatile boolean stopped; - @Getter - @Setter - private volatile boolean paused; - @Getter - private final Object lock = new Object(); + @Getter + @Setter + private volatile boolean stopped; + @Getter + @Setter + private volatile boolean paused; + @Getter + private final Object lock = new Object(); - /** - * Constructor to create a new Simulation, which can execute robbis main-Method. - * - * @param territory The territory in which the simulation is happening - * @param simController The SimulationController, which started this simulation - * @param parent The parent window to show alerts relative to the it - */ - public Simulation(Territory territory, SimulationController simController, Window parent) { - this.territory = territory; - this.simController = simController; - this.parent = parent; - stopped = false; - paused = false; - } + /** + * Constructor to create a new Simulation, which can execute robbi's main-Method. + * + * @param territory The territory in which the simulation is happening + * @param simController The SimulationController, which started this simulation + * @param parent The parent window to show alerts relative to it + */ + public Simulation(Territory territory, SimulationController simController, Window parent) { + this.territory = territory; + this.simController = simController; + this.parent = parent; + stopped = false; + paused = false; + } - /** - * Starts the simulation and triggers the robbis main-Method. It informs the - * user if the execution finished in an unexpected way. In the end it does some - * finalization. - */ - @Override - public void run() { - logger.info("Simulation started"); - territory.addObserver(this); - try { - Method main = territory.getRobbi().getClass().getDeclaredMethod("main"); - main.setAccessible(true); - main.invoke(territory.getRobbi()); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException - | SecurityException e) { - if (e.getCause() instanceof StopException) { - logger.debug("Simulation stopped"); - } else if (e.getCause() instanceof RobbiException re) { - logger.debug("Simulation stopped with exception: {}", re.getMessage()); - SoundManager.playWarnSound(); - // TODO: change to Snackbar? - Platform.runLater( - () -> AlertHelper.showAlertAndWait(AlertType.ERROR, re.getLocalizedMessage(), parent)); - } else - e.printStackTrace(); - } finally { - stopped = true; - territory.removeObserver(this); - simController.finish(); - logger.info("Simulation done."); - } + /** + * Starts the simulation and triggers the robbi's main-Method. It informs the + * user if the execution finished in an unexpected way. In the end it does some + * finalization. + */ + @Override + public void run() { + logger.info("Simulation started"); + territory.addObserver(this); + try { + Method main = territory.getRobbi().getClass().getDeclaredMethod("main"); + main.setAccessible(true); + main.invoke(territory.getRobbi()); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException + | SecurityException e) { + if (e.getCause() instanceof StopException) { + logger.debug("Simulation stopped"); + } else if (e.getCause() instanceof RobbiException re) { + logger.debug("Simulation stopped with exception: {}", re.getMessage()); + SoundManager.playWarnSound(); + // TODO: change to Snackbar? + Platform.runLater( + () -> AlertHelper.showAlertAndWait(AlertType.ERROR, re.getLocalizedMessage(), parent)); + } else + logger.error("Simulation stopped with unwanted exception", e); + } finally { + stopped = true; + territory.removeObserver(this); + simController.finish(); + logger.info("Simulation done."); + } - } + } - /** - * If the territory has been updated by a non-FXApplicationThread, this thread - * is sleeping for the time provided by the SimulationController. Furthermore, - * it waits while the simulation is stopped and throws an StopException if the - * Simulation has been terminated by the user. - * - * @param observable The observable, which caused the update to trigger - */ - @Override - public void update(Observable observable) { - if (Platform.isFxApplicationThread()) // if observable is called by gui, ignore it - return; - try { - sleep(simController.getSpeed()); - } catch (InterruptedException e) { - logger.debug("Stopping simulation during sleep"); - Thread.currentThread().interrupt(); - } - if (this.stopped) - throw new StopException(); - while (this.paused) - synchronized (lock) { - try { - lock.wait(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - if (stopped) - throw new StopException(); + /** + * If the territory has been updated by a non-FXApplicationThread, this thread + * is sleeping for the time provided by the SimulationController. Furthermore, + * it waits while the simulation is stopped and throws an StopException if the + * Simulation has been terminated by the user. + * + * @param observable The observable, which caused the update to trigger + */ + @Override + public void update(Observable observable) { + if (Platform.isFxApplicationThread()) // if observable is called by gui, ignore it + return; + try { + sleep(simController.getSpeed()); + } catch (InterruptedException e) { + logger.debug("Stopping simulation during sleep"); + Thread.currentThread().interrupt(); + } + if (this.stopped) + throw new StopException(); + while (this.paused) + synchronized (lock) { + try { + lock.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if (stopped) + throw new StopException(); - } + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/SimulationController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/SimulationController.java index 0e32940..6cb1546 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/SimulationController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/SimulationController.java @@ -1,14 +1,11 @@ package com.JayPi4c.RobbiSimulator.controller.simulation; -import java.util.Optional; - import com.JayPi4c.RobbiSimulator.controller.program.ProgramController; import com.JayPi4c.RobbiSimulator.model.Robbi; import com.JayPi4c.RobbiSimulator.model.Territory; import com.JayPi4c.RobbiSimulator.model.TerritoryState; import com.JayPi4c.RobbiSimulator.view.MainStage; import com.JayPi4c.RobbiSimulator.view.Toolbar; - import javafx.application.Platform; import javafx.scene.control.Button; import javafx.scene.control.MenuItem; @@ -16,223 +13,224 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import java.util.Optional; + /** * Controller to handle all actions belonging to the simulation. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j public class SimulationController { - private static final int MIN_SPEED = 100; - private static final int MAX_SPEED = 2500; - - private Simulation simulation; - - private MainStage stage; - private Territory territory; - - @Getter - private volatile int speed; - - private MenuItem resetMenuItem; - private Button resetToolbar; - - private MenuItem pauseMenuItem; - private ToggleButton pauseToolbar; - private MenuItem startMenuItem; - private ToggleButton startToolbar; - private MenuItem stopMenuItem; - private ToggleButton stopToolbar; - - private TerritoryState territoryState; - - /** - * Constructor to create a new SimulationController, which adds all actions to - * the corresponding gui elements. - * - * @param stage The stage, this controller is for - * @param territory the territory in which the simulation takes place - */ - public SimulationController(MainStage stage, Territory territory) { - this.stage = stage; - this.territory = territory; - Toolbar toolbar = stage.getToolbar(); - speed = (int) toolbar.getSpeedSliderToolbar().getValue(); - - resetToolbar = toolbar.getResetButtonToolbar(); - resetToolbar.setOnAction(e -> reset()); - resetMenuItem = this.stage.getMenubar().getResetMenuItem(); - resetMenuItem.onActionProperty().bind(resetToolbar.onActionProperty()); - - startToolbar = toolbar.getStartToggleButtonToolbar(); - startToolbar.setOnAction(e -> { - if (!isSimulationRunning()) - start(); - else - resume(); - }); - startMenuItem = stage.getMenubar().getStartMenuItem(); - startMenuItem.onActionProperty().bind(startToolbar.onActionProperty()); - startMenuItem.disableProperty().bind(startToolbar.disableProperty()); - - pauseToolbar = toolbar.getPauseToggleButtonToolbar(); - pauseToolbar.setOnAction(e -> pause()); - pauseMenuItem = this.stage.getMenubar().getPauseMenuItem(); - pauseMenuItem.onActionProperty().bind(pauseToolbar.onActionProperty()); - pauseMenuItem.disableProperty().bind(pauseToolbar.disableProperty()); - - stopToolbar = toolbar.getStopToggleButtonToolbar(); - stopToolbar.setOnAction(e -> stop()); - stopMenuItem = this.stage.getMenubar().getStopMenuItem(); - stopMenuItem.onActionProperty().bind(stopToolbar.onActionProperty()); - stopMenuItem.disableProperty().bind(stopToolbar.disableProperty()); - - toolbar.getSpeedSliderToolbar().valueProperty().addListener((ov, oldVal, newVal) -> setSpeed((Double) newVal)); - setSpeed(toolbar.getSpeedSliderToolbar().getValue()); - disableButtonStates(false, true, true); - - } - - /** - * Helper to start e new simulation. - */ - private void start() { - logger.debug("Starting new simulation"); - Optional r = ProgramController.getNewRobbi(stage.getProgram().getName()); - if (r.isPresent()) - territory.setRobbi(r.get()); - else - logger.debug("Could not initialize Robbi"); - territoryState = territory.save(); - simulation = new Simulation(territory, this, stage); - simulation.setDaemon(true); // program should exit even if simulation is running - simulation.start(); - disableButtonStates(true, false, false); - } - - /** - * Helper to pause the current simulation. - */ - private void pause() { - logger.debug("Pausing simulation"); - simulation.setPaused(true); - disableButtonStates(false, true, false); - } - - /** - * Helper to resume the current simulation. - */ - private void resume() { - logger.debug("Resuming simulation"); - simulation.setPaused(false); - synchronized (simulation.getLock()) { - simulation.getLock().notifyAll(); - } - disableButtonStates(true, false, false); - } - - /** - * Helper to stop the current simulation. - */ - private void stop() { - logger.debug("Stopping simulation"); - simulation.setStopped(true); - simulation.setPaused(false); - simulation.interrupt(); - synchronized (simulation.getLock()) { - simulation.getLock().notifyAll(); - } - } - - /** - * Helper to reset the territory to the state at the beginning of the - * simulation. - */ - private void reset() { - logger.debug("Resetting the simulation"); - if (isSimulationRunning()) - stop(); - - if (territoryState != null) - territory.restore(territoryState); - } - - /** - * Helper to check if the simulation is currently running - * - * @return true if the simulation is not null or not stopped - */ - private boolean isSimulationRunning() { - return !(simulation == null || simulation.isStopped()); - } - - /** - * Stops the simulation if one exists. - */ - public void stopSimulation() { - if (simulation != null) { - stop(); - } - } - - /** - * Helper to finish up a simulation if it is finished or has been stopped by the - * user. - */ - public void finish() { - Platform.runLater(() -> { - disableButtonStates(false, true, true); - startToolbar.setSelected(false); - }); - } - - /** - * Helper to set the buttonstates according the the given parameters. - * - * @param start true, to disable start simulation button - * @param pause true, to disable pause simulation button - * @param stop true, to disable stop simulation button - */ - private void disableButtonStates(boolean start, boolean pause, boolean stop) { - if (!Platform.isFxApplicationThread()) { - Platform.runLater(() -> { - startToolbar.setDisable(start); - pauseToolbar.setDisable(pause); - stopToolbar.setDisable(stop); - }); - } else { - startToolbar.setDisable(start); - pauseToolbar.setDisable(pause); - stopToolbar.setDisable(stop); - } - } - - /** - * Updates the speed attribute to the given parameter. - * - * @param speed the new speed value - */ - public void setSpeed(double speed) { - this.speed = (int) map(speed, Toolbar.MIN_SPEED_VALUE, Toolbar.MAX_SPEED_VALUE, MAX_SPEED, MIN_SPEED); - } - - /** - * Maps the given value, which ranges between istart and istop on a value which - * ranges between ostart and ostop. - * - * @see Stackoverflow - * @param value value to map - * @param istart input start - * @param istop input stop - * @param ostart output start - * @param ostop output stop - * @return the mapped value - */ - private final double map(double value, double istart, double istop, double ostart, double ostop) { - return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); - } + private static final int MIN_SPEED = 100; + private static final int MAX_SPEED = 2500; + + private Simulation simulation; + + private final MainStage stage; + private final Territory territory; + + @Getter + private volatile int speed; + + private final MenuItem resetMenuItem; + private final Button resetToolbar; + + private final MenuItem pauseMenuItem; + private final ToggleButton pauseToolbar; + private final MenuItem startMenuItem; + private final ToggleButton startToolbar; + private final MenuItem stopMenuItem; + private final ToggleButton stopToolbar; + + private TerritoryState territoryState; + + /** + * Constructor to create a new SimulationController, which adds all actions to + * the corresponding gui elements. + * + * @param stage The stage, this controller is for + * @param territory the territory in which the simulation takes place + */ + public SimulationController(MainStage stage, Territory territory) { + this.stage = stage; + this.territory = territory; + Toolbar toolbar = stage.getToolbar(); + speed = (int) toolbar.getSpeedSliderToolbar().getValue(); + + resetToolbar = toolbar.getResetButtonToolbar(); + resetToolbar.setOnAction(e -> reset()); + resetMenuItem = this.stage.getMenubar().getResetMenuItem(); + resetMenuItem.onActionProperty().bind(resetToolbar.onActionProperty()); + + startToolbar = toolbar.getStartToggleButtonToolbar(); + startToolbar.setOnAction(e -> { + if (!isSimulationRunning()) + start(); + else + resume(); + }); + startMenuItem = stage.getMenubar().getStartMenuItem(); + startMenuItem.onActionProperty().bind(startToolbar.onActionProperty()); + startMenuItem.disableProperty().bind(startToolbar.disableProperty()); + + pauseToolbar = toolbar.getPauseToggleButtonToolbar(); + pauseToolbar.setOnAction(e -> pause()); + pauseMenuItem = this.stage.getMenubar().getPauseMenuItem(); + pauseMenuItem.onActionProperty().bind(pauseToolbar.onActionProperty()); + pauseMenuItem.disableProperty().bind(pauseToolbar.disableProperty()); + + stopToolbar = toolbar.getStopToggleButtonToolbar(); + stopToolbar.setOnAction(e -> stop()); + stopMenuItem = this.stage.getMenubar().getStopMenuItem(); + stopMenuItem.onActionProperty().bind(stopToolbar.onActionProperty()); + stopMenuItem.disableProperty().bind(stopToolbar.disableProperty()); + + toolbar.getSpeedSliderToolbar().valueProperty().addListener((ov, oldVal, newVal) -> setSpeed((Double) newVal)); + setSpeed(toolbar.getSpeedSliderToolbar().getValue()); + disableButtonStates(false, true, true); + + } + + /** + * Helper to start e new simulation. + */ + private void start() { + logger.debug("Starting new simulation"); + Optional r = ProgramController.getNewRobbi(stage.getProgram().getName()); + if (r.isPresent()) + territory.setRobbi(r.get()); + else + logger.debug("Could not initialize Robbi"); + territoryState = territory.save(); + simulation = new Simulation(territory, this, stage); + simulation.setDaemon(true); // program should exit even if simulation is running + simulation.start(); + disableButtonStates(true, false, false); + } + + /** + * Helper to pause the current simulation. + */ + private void pause() { + logger.debug("Pausing simulation"); + simulation.setPaused(true); + disableButtonStates(false, true, false); + } + + /** + * Helper to resume the current simulation. + */ + private void resume() { + logger.debug("Resuming simulation"); + simulation.setPaused(false); + synchronized (simulation.getLock()) { + simulation.getLock().notifyAll(); + } + disableButtonStates(true, false, false); + } + + /** + * Helper to stop the current simulation. + */ + private void stop() { + logger.debug("Stopping simulation"); + simulation.setStopped(true); + simulation.setPaused(false); + simulation.interrupt(); + synchronized (simulation.getLock()) { + simulation.getLock().notifyAll(); + } + } + + /** + * Helper to reset the territory to the state at the beginning of the + * simulation. + */ + private void reset() { + logger.debug("Resetting the simulation"); + if (isSimulationRunning()) + stop(); + + if (territoryState != null) + territory.restore(territoryState); + } + + /** + * Helper to check if the simulation is currently running + * + * @return true if the simulation is not null or not stopped + */ + private boolean isSimulationRunning() { + return !(simulation == null || simulation.isStopped()); + } + + /** + * Stops the simulation if one exists. + */ + public void stopSimulation() { + if (simulation != null) { + stop(); + } + } + + /** + * Helper to finish up a simulation if it is finished or has been stopped by the + * user. + */ + public void finish() { + Platform.runLater(() -> { + disableButtonStates(false, true, true); + startToolbar.setSelected(false); + }); + } + + /** + * Helper to set the buttonstates according the the given parameters. + * + * @param start true, to disable start simulation button + * @param pause true, to disable pause simulation button + * @param stop true, to disable stop simulation button + */ + private void disableButtonStates(boolean start, boolean pause, boolean stop) { + if (!Platform.isFxApplicationThread()) { + Platform.runLater(() -> { + startToolbar.setDisable(start); + pauseToolbar.setDisable(pause); + stopToolbar.setDisable(stop); + }); + } else { + startToolbar.setDisable(start); + pauseToolbar.setDisable(pause); + stopToolbar.setDisable(stop); + } + } + + /** + * Updates the speed attribute to the given parameter. + * + * @param speed the new speed value + */ + public void setSpeed(double speed) { + this.speed = (int) map(speed, Toolbar.MIN_SPEED_VALUE, Toolbar.MAX_SPEED_VALUE, MAX_SPEED, MIN_SPEED); + } + + /** + * Maps the given value, which ranges between inStart and inStop, on a value which + * ranges between outStart and outStop. + * + * @param value value to map + * @param inStart input start + * @param inStop input stop + * @param outStart output start + * @param outStop output stop + * @return the mapped value + * @see Stackoverflow + */ + private double map(double value, double inStart, double inStop, double outStart, double outStop) { + return outStart + (outStop - outStart) * ((value - inStart) / (inStop - inStart)); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/StopException.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/StopException.java index 4526466..af53ce6 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/StopException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/simulation/StopException.java @@ -4,12 +4,9 @@ * This Exception indicates, that the simulation has been interrupted. It will * be thrown, if the user hits the stop button while the main Method of robbi is * still running. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class StopException extends RuntimeException { - private static final long serialVersionUID = 1L; - } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Answer.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Answer.java index 92e0f8f..ddadb63 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Answer.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Answer.java @@ -1,14 +1,18 @@ package com.JayPi4c.RobbiSimulator.controller.tutor; +import java.io.Serial; import java.io.Serializable; /** * Wrapper to hold an answer instance. - * - * @author Jonas Pohl + * * @param code the code which is stored in the editor * @param territory the territory encoded as XML string + * @author Jonas Pohl */ public record Answer(String code, String territory) implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/ITutor.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/ITutor.java index 398e77c..0e705a5 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/ITutor.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/ITutor.java @@ -5,31 +5,30 @@ /** * Interface for RMI communication - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public interface ITutor extends Remote { - /** - * Sends a request of code and territory to the tutor and returns the id of the - * request at the tutors instance. - * - * @param code the requests code - * @param territory the requests territory - * @return the requests id - * @throws RemoteException thrown on connection errors - */ - public int sendRequest(String code, String territory) throws RemoteException; + /** + * Sends a request of code and territory to the tutor and returns the id of the + * request at the tutors instance. + * + * @param code the requests code + * @param territory the requests territory + * @return the requests id + * @throws RemoteException thrown on connection errors + */ + int sendRequest(String code, String territory) throws RemoteException; - /** - * Fetches the answer for the given id. The answer will be null, if no answer is - * set. - * - * @param id the id for the fetched answer - * @return the answer for the id or null, if no answer is set - * @throws RemoteException thrown on connection errors - */ - public Answer getAnswer(int id) throws RemoteException; + /** + * Fetches the answer for the given id. The answer will be null, if no answer is + * set. + * + * @param id the id for the fetched answer + * @return the answer for the id or null, if no answer is set + * @throws RemoteException thrown on connection errors + */ + Answer getAnswer(int id) throws RemoteException; } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Request.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Request.java index a013a5c..2db54cb 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Request.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Request.java @@ -2,9 +2,8 @@ /** * Wrapper to hold a request instance. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public record Request(int id, String code, String territory) { diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/StudentController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/StudentController.java index 797172f..6823343 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/StudentController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/StudentController.java @@ -29,7 +29,7 @@ public class StudentController { private static final String MENU_TUTOR_SEND_REQUEST_INFORMATION = "Menu.tutor.sendRequest.information"; private static final String MENU_TUTOR_SENDREQUEST_ERROR = "Menu.tutor.sendRequest.error"; private int requestID; - private MainStage stage; + private final MainStage stage; /** * Constructor to create a new StudentController diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Tutor.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Tutor.java index 7b78137..6bd9c26 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Tutor.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/Tutor.java @@ -1,83 +1,80 @@ package com.JayPi4c.RobbiSimulator.controller.tutor; -import java.rmi.RemoteException; -import java.rmi.server.UnicastRemoteObject; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Optional; -import java.util.Queue; - import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; +import java.io.Serial; +import java.rmi.RemoteException; +import java.rmi.server.UnicastRemoteObject; +import java.util.*; + /** * ITutor implementation to handle the RMI invocations. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j @EqualsAndHashCode(callSuper = true) public class Tutor extends UnicastRemoteObject implements ITutor { - private static final long serialVersionUID = 4722167139215525516L; + @Serial + private static final long serialVersionUID = 4722167139215525516L; - private transient Queue requests; - /** - * ID of the latest request. Will increment after a request arrived. - */ - private int currentID = 0; - /** - * Map to hold answers accessible by their id - */ - private Map answers; + private transient final Queue requests; + /** + * ID of the latest request. Will increment after a request arrived. + */ + private int currentID = 0; + /** + * Map to hold answers accessible by their id + */ + private final Map answers; - /** - * Create a new tutor-instance - * - * @throws RemoteException thrown on connection errors - */ - public Tutor() throws RemoteException { - super(); - requests = new LinkedList<>(); - answers = new HashMap<>(); - } + /** + * Create a new tutor-instance + * + * @throws RemoteException thrown on connection errors + */ + public Tutor() throws RemoteException { + super(); + requests = new LinkedList<>(); + answers = new HashMap<>(); + } - @Override - public synchronized int sendRequest(String code, String territory) throws RemoteException { - requests.add(new Request(currentID, code, territory)); - logger.debug("Added new request with id {}.", currentID); - return currentID++; - } + @Override + public synchronized int sendRequest(String code, String territory) throws RemoteException { + requests.add(new Request(currentID, code, territory)); + logger.debug("Added new request with id {}.", currentID); + return currentID++; + } - @Override - public synchronized Answer getAnswer(int id) throws RemoteException { - if (answers.containsKey(id)) { - logger.debug("Returning answer with id {}.", id); - return answers.remove(id); - } - logger.debug("Could not find answer with id {}.", id); - return null; - } + @Override + public synchronized Answer getAnswer(int id) throws RemoteException { + if (answers.containsKey(id)) { + logger.debug("Returning answer with id {}.", id); + return answers.remove(id); + } + logger.debug("Could not find answer with id {}.", id); + return null; + } - /** - * Returns an optional with a new request if one is available. - * - * @return Optional of the oldest request or an empty Optional. - */ - public synchronized Optional getNewRequest() { - return Optional.ofNullable(requests.poll()); - } + /** + * Returns an optional with a new request if one is available. + * + * @return Optional of the oldest request or an empty Optional. + */ + public synchronized Optional getNewRequest() { + return Optional.ofNullable(requests.poll()); + } - /** - * Adds an answer with the corresponding id in the list of done answers. - * - * @param id the id for the answer - * @param answer the actual answer - */ - public synchronized void setAnswer(int id, Answer answer) { - answers.put(id, answer); - } + /** + * Adds an answer with the corresponding id in the list of done answers. + * + * @param id the id for the answer + * @param answer the actual answer + */ + public synchronized void setAnswer(int id, Answer answer) { + answers.put(id, answer); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/TutorController.java b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/TutorController.java index b53c500..789f0de 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/TutorController.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/controller/tutor/TutorController.java @@ -32,7 +32,7 @@ public class TutorController { private static final String MENU_TUTOR_SAVEANSWER_INFORMATION = "Menu.tutor.saveAnswer.information"; private static Tutor tutor; private static Registry registry; - private MainStage stage; + private final MainStage stage; private int currentID = NO_ID; /** @@ -67,7 +67,7 @@ public static boolean initialize() { } /** - * Unbinds all previously binded instances. + * Unbinds all previously bound instances. * * @return true if the unbinding was successful, false otherwise */ diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Accu.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Accu.java index 31448bc..b1e6d48 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Accu.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Accu.java @@ -2,15 +2,17 @@ import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; + /** * Class representing the accu-item. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class Accu implements Item { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsEmptyException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsEmptyException.java index 2166e32..482bac1 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsEmptyException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsEmptyException.java @@ -1,21 +1,23 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if an item is placed down while there is no item in * the bag. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class BagIsEmptyException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new BagIsEmptyException with a localized message. - */ - public BagIsEmptyException() { - super("Exception.BagIsEmpty"); - } + /** + * Constructor for a new BagIsEmptyException with a localized message. + */ + public BagIsEmptyException() { + super("Exception.BagIsEmpty"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsFullException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsFullException.java index bd7d16b..96e1a4c 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsFullException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/BagIsFullException.java @@ -1,20 +1,22 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if an item is picked up while the bag is already full. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class BagIsFullException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new BagIsFullException with a localized message. - */ - public BagIsFullException() { - super("Exception.BagIsFull"); - } + /** + * Constructor for a new BagIsFullException with a localized message. + */ + public BagIsFullException() { + super("Exception.BagIsFull"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/DIRECTION.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/DIRECTION.java index de3451c..26bd2c9 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/DIRECTION.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/DIRECTION.java @@ -1,48 +1,45 @@ package com.JayPi4c.RobbiSimulator.model; /** - * Enumeration to hold all cardinal-points to store robbis current facing. - * - * @author Jonas Pohl + * Enumeration to hold all cardinal-points to store robbi's current facing. * + * @author Jonas Pohl */ public enum DIRECTION { - /** - * Direction if robbi is looking up. - */ - NORTH, - /** - * Direction if robbi is looking left. - */ - WEST, - /** - * Direction if robbi is looking down. - */ - SOUTH, - /** - * Direction if robbi is looking right. - */ - EAST; - - private static DIRECTION[] vals = values(); + /** + * Direction if robbi is looking up. + */ + NORTH, + /** + * Direction if robbi is looking left. + */ + WEST, + /** + * Direction if robbi is looking down. + */ + SOUTH, + /** + * Direction if robbi is looking right. + */ + EAST; - /** - * moves through the direction counter-clockwise - * - * @return the next direction after a counter-clockwise 90 degrees turn. - */ - public DIRECTION next() { - return vals[(this.ordinal() + 1) % vals.length]; - } + /** + * moves through the direction counter-clockwise + * + * @return the next direction after a counter-clockwise 90 degrees turn. + */ + public DIRECTION next() { + return values()[(this.ordinal() + 1) % values().length]; + } - /** - * Moves through the direction clockwise. - * - * @return the next direction after a clockwise 90 degrees turn. - */ - public DIRECTION previous() { - return vals[(this.ordinal() + vals.length - 1) % vals.length]; - } + /** + * Moves through the direction clockwise. + * + * @return the next direction after a clockwise 90 degrees turn. + */ + public DIRECTION previous() { + return values()[(this.ordinal() + values().length - 1) % values().length]; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Dimension.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Dimension.java index 6b22cb8..4a320eb 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Dimension.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Dimension.java @@ -2,9 +2,8 @@ /** * Record to hold information about the new dimension of the simulation gird. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public record Dimension(int cols, int rows) { diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Hollow.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Hollow.java index 8234253..e638e89 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Hollow.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Hollow.java @@ -2,38 +2,40 @@ import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; + /** * Class representing a Hollow tile. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class Hollow extends Tile { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Getter for the item placed on the tile. - * - * @return the item placed on this tile. No item can be placed here, therefore - * the item returned is null - */ - @Override - public Item getItem() { - return null; - } + /** + * Getter for the item placed on the tile. + * + * @return the item placed on this tile. No item can be placed here, therefore + * the item returned is null + */ + @Override + public Item getItem() { + return null; + } - /** - * Setter to place an item in the hollow. Since the gamelogic forbids this - * action, the item given to the hollow will not be saved and dropped instead. - * - * @param item item to be placed in the hollow. - */ - @Override - public void setItem(Item item) { - // Robbi can't reach a hollow tile. Items will be dropped if it is placed into a - // hollow - } + /** + * Setter to place an item in the hollow. Since the game logic forbids this + * action, the item given to the hollow will not be saved and dropped instead. + * + * @param item item to be placed in the hollow. + */ + @Override + public void setItem(Item item) { + // Robbi can't reach a hollow tile. Items will be dropped if it is placed into a + // hollow + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/HollowAheadException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/HollowAheadException.java index 0b37fb4..c9e3276 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/HollowAheadException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/HollowAheadException.java @@ -1,19 +1,21 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** - * Exception to be thrown if robbi tries to move into a hollow- - * - * @author Jonas Pohl + * Exception to be thrown if robbi tries to move into a hollow. * + * @author Jonas Pohl */ public class HollowAheadException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new HollowAheadException with a localized message. - */ - public HollowAheadException() { - super("Exception.HollowAhead"); - } + /** + * Constructor for a new HollowAheadException with a localized message. + */ + public HollowAheadException() { + super("Exception.HollowAhead"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/InvalidTerritoryException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/InvalidTerritoryException.java index 1a3814e..b921764 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/InvalidTerritoryException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/InvalidTerritoryException.java @@ -1,20 +1,22 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if the user tries to load an invalid territory. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class InvalidTerritoryException extends Exception { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new InvalidTerritoryException with a message. - */ - public InvalidTerritoryException() { - super("The loaded territory is invalid."); - } + /** + * Constructor for a new InvalidTerritoryException with a message. + */ + public InvalidTerritoryException() { + super("The loaded territory is invalid."); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Item.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Item.java index e564244..91167e0 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Item.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Item.java @@ -4,9 +4,8 @@ /** * Interface for all item classes. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public interface Item extends Serializable { diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/NoItemException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/NoItemException.java index 2770ef5..cfcb742 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/NoItemException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/NoItemException.java @@ -1,21 +1,23 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if robbi tries to pick up an item from a tile, which - * has no item provied. - * - * @author Jonas Pohl + * has no item provided. * + * @author Jonas Pohl */ public class NoItemException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new NoItemException with a localized message. - */ - public NoItemException() { - super("Exception.NoItem"); - } + /** + * Constructor for a new NoItemException with a localized message. + */ + public NoItemException() { + super("Exception.NoItem"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/NoPileOfScrapAheadException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/NoPileOfScrapAheadException.java index e62ca3f..3a805cc 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/NoPileOfScrapAheadException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/NoPileOfScrapAheadException.java @@ -1,21 +1,23 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if robbi attempts to push a pile of scrap while there * is no pile of scrap ahead of robbi. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class NoPileOfScrapAheadException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new NoPileOfScrapAheadException with localized message. - */ - public NoPileOfScrapAheadException() { - super("Exception.NoPileOfScrapAhead"); - } + /** + * Constructor for a new NoPileOfScrapAheadException with localized message. + */ + public NoPileOfScrapAheadException() { + super("Exception.NoPileOfScrapAhead"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Nut.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Nut.java index 13b1afe..1dfb0db 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Nut.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Nut.java @@ -2,15 +2,17 @@ import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; + /** * Class representing the nut-item. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class Nut implements Item { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/PileOfScrap.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/PileOfScrap.java index 3022a4f..266d294 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/PileOfScrap.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/PileOfScrap.java @@ -2,37 +2,39 @@ import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; + /** * Class representing a PileOfScrap Tile. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class PileOfScrap extends Tile { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Setter to place an item on a PileOfScrap. Since the item placed on a pile of - * scrap, the item just vanishes. - * - * @param item the item to vanish - */ - @Override - public void setItem(Item item) { - // Item vanishes - } + /** + * Setter to place an item on a PileOfScrap. Since the item placed on a pile of + * scrap, the item just vanishes. + * + * @param item the item to vanish + */ + @Override + public void setItem(Item item) { + // Item vanishes + } - /** - * Getter for the item placed on the tile. - * - * @return the item placed on this tile. All items placed on a pile of scrap - * vanish, therefore the item returned will be null. - */ - @Override - public Item getItem() { - return null; - } + /** + * Getter for the item placed on the tile. + * + * @return the item placed on this tile. All items placed on a pile of scrap + * vanish, therefore the item returned will be null. + */ + @Override + public Item getItem() { + return null; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Robbi.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Robbi.java index d7b13c8..eaa8666 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Robbi.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Robbi.java @@ -1,324 +1,319 @@ package com.JayPi4c.RobbiSimulator.model; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.Synchronized; +import lombok.*; import lombok.extern.slf4j.Slf4j; /** - * * This is the actor class of the simulator. All public functions in this class - * will be available in the simulators editor. - * + * will be available in the simulator's editor. + * * @author Jonas Pohl */ @Slf4j @NoArgsConstructor public class Robbi { - /** - * Attribute to store the territory in which robbi is living - */ - @Setter(value = AccessLevel.PACKAGE) - private Territory territory; - /** - * Attribute to store robbis x position in the territory - */ - @Getter(value = AccessLevel.PACKAGE) - private volatile int x; - /** - * Attribute to store robbis y position in the territory - */ - @Getter(value = AccessLevel.PACKAGE) - private volatile int y; - /** - * Attribute to store robbis item - */ - @Getter(value = AccessLevel.PACKAGE, onMethod_ = { @Synchronized("territory") }) - @Setter(value = AccessLevel.PACKAGE, onMethod_ = { @Synchronized("territory") }) - private Item item = null; + /** + * Attribute to store the territory in which robbi is living + */ + @Setter(value = AccessLevel.PACKAGE) + private Territory territory; + /** + * Attribute to store robbi's x position in the territory + */ + @Getter(value = AccessLevel.PACKAGE) + private volatile int x; + /** + * Attribute to store robbi's y position in the territory + */ + @Getter(value = AccessLevel.PACKAGE) + private volatile int y; + /** + * Attribute to store robbi's item + */ + @Getter(value = AccessLevel.PACKAGE, onMethod_ = {@Synchronized("territory")}) + @Setter(value = AccessLevel.PACKAGE, onMethod_ = {@Synchronized("territory")}) + private Item item = null; - /** - * Attribute to store robbis facing - */ - @Getter(value = AccessLevel.PACKAGE) - private volatile DIRECTION facing; + /** + * Attribute to store robbi's facing + */ + @Getter(value = AccessLevel.PACKAGE) + private volatile DIRECTION facing; - /** - * The main-Method which will be overwritten by every custom Robbi - * implementation. When starting a simulation, this method will be called. - */ - void main() { - // will be overritten - logger.error("Please overrite the main-method"); - } + /** + * The main-Method which will be overwritten by every custom Robbi + * implementation. When starting a simulation, this method will be called. + */ + void main() { + // will be overwritten + logger.error("Please overwrite the main-method"); + } - /** - * Constructor to create a new robbi with the given territory. - * - * @param t the territory in which robbi is placed. - */ - Robbi(Territory t) { - this.territory = t; - this.x = 0; - this.y = 0; - this.facing = DIRECTION.EAST; - } + /** + * Constructor to create a new robbi with the given territory. + * + * @param t the territory in which robbi is placed. + */ + Robbi(Territory t) { + this.territory = t; + this.x = 0; + this.y = 0; + this.facing = DIRECTION.EAST; + } - // ============= HELPER ================ + // ============= HELPER ================ - /** - * Sets the position of robbi. - * - * @param x new x position - * @param y new y position - */ - void setPosition(int x, int y) { - synchronized (territory) { - if (x < 0 || y < 0 || x >= territory.getNumCols() || y >= territory.getNumRows()) - throw new IllegalArgumentException("Robbi kann nicht außerhalb des Territoriums platziert werden."); - if (territory.getTile(x, y) instanceof Hollow) - throw new TileBlockedException(); - this.x = x; - this.y = y; - } - } + /** + * Sets the position of robbi. + * + * @param x new x position + * @param y new y position + */ + void setPosition(int x, int y) { + synchronized (territory) { + if (x < 0 || y < 0 || x >= territory.getNumCols() || y >= territory.getNumRows()) + throw new IllegalArgumentException("Robbi kann nicht außerhalb des Territoriums platziert werden."); + if (territory.getTile(x, y) instanceof Hollow) + throw new TileBlockedException(); + this.x = x; + this.y = y; + } + } - /** - * Updates the facing of robbi to the given facing. - * - * @param facing robbis new facing - */ - void setFacing(DIRECTION facing) { - synchronized (territory) { - this.facing = facing; - } - } + /** + * Updates the facing of robbi to the given facing. + * + * @param facing robbi's new facing + */ + void setFacing(DIRECTION facing) { + synchronized (territory) { + this.facing = facing; + } + } - // ==================== PUBLIC FUNCTIONS ========== + // ==================== PUBLIC FUNCTIONS ========== - /** - * If possible move Robbi one tile towards the direction it is facing. - */ - public final void vor() { - synchronized (territory) { - Tile t; - switch (facing) { - case NORTH: - t = territory.getTile(x, y - 1); - if (t instanceof Hollow) - throw new HollowAheadException(); - else { - y = y - 1; - y += territory.getNumRows(); - y %= territory.getNumRows(); - } - break; - case SOUTH: - t = territory.getTile(x, y + 1); - if (t instanceof Hollow) - throw new HollowAheadException(); - else { - y = y + 1; - y += territory.getNumRows(); - y %= territory.getNumRows(); - } - break; - case EAST: - t = territory.getTile(x + 1, y); - if (t instanceof Hollow) - throw new HollowAheadException(); - else { - x = x + 1; - x += territory.getNumCols(); - x %= territory.getNumCols(); - } - break; - case WEST: - t = territory.getTile(x - 1, y); - if (t instanceof Hollow) - throw new HollowAheadException(); - else { - x = x - 1; - x += territory.getNumCols(); - x %= territory.getNumCols(); - } - break; - default: - break; - } - } - territory.setChanged(); - territory.notifyAllObservers(); - } + /** + * If possible move Robbi one tile towards the direction it is facing. + */ + public final void vor() { + synchronized (territory) { + Tile t; + switch (facing) { + case NORTH: + t = territory.getTile(x, y - 1); + if (t instanceof Hollow) + throw new HollowAheadException(); + else { + y = y - 1; + y += territory.getNumRows(); + y %= territory.getNumRows(); + } + break; + case SOUTH: + t = territory.getTile(x, y + 1); + if (t instanceof Hollow) + throw new HollowAheadException(); + else { + y = y + 1; + y += territory.getNumRows(); + y %= territory.getNumRows(); + } + break; + case EAST: + t = territory.getTile(x + 1, y); + if (t instanceof Hollow) + throw new HollowAheadException(); + else { + x = x + 1; + x += territory.getNumCols(); + x %= territory.getNumCols(); + } + break; + case WEST: + t = territory.getTile(x - 1, y); + if (t instanceof Hollow) + throw new HollowAheadException(); + else { + x = x - 1; + x += territory.getNumCols(); + x %= territory.getNumCols(); + } + break; + default: + break; + } + } + territory.setChanged(); + territory.notifyAllObservers(); + } - /** - * Turn Robbi counterclockwise. - */ - public final void linksUm() { - synchronized (territory) { - facing = facing.next(); - } - territory.setChanged(); - territory.notifyAllObservers(); - } + /** + * Turn Robbi counterclockwise. + */ + public final void linksUm() { + synchronized (territory) { + facing = facing.next(); + } + territory.setChanged(); + territory.notifyAllObservers(); + } - /** - * If possible drop the item that is stored in the bag. - */ - public final void legeAb() { - synchronized (territory) { - if (item == null) - throw new BagIsEmptyException(); - if (territory.placeItem(item, x, y)) - item = null; - else - throw new TileIsFullException(); - } - territory.setChanged(); - territory.notifyAllObservers(); - } + /** + * If possible drop the item that is stored in the bag. + */ + public final void legeAb() { + synchronized (territory) { + if (item == null) + throw new BagIsEmptyException(); + if (territory.placeItem(item, x, y)) + item = null; + else + throw new TileIsFullException(); + } + territory.setChanged(); + territory.notifyAllObservers(); + } - /** - * if possible take the item that occupies the tile Robbi is on. - */ - public final void nehmeAuf() { - synchronized (territory) { - Item i = territory.getItem(x, y); - if (i == null) - throw new NoItemException(); - if (this.item != null) { - throw new BagIsFullException(); - } - this.item = territory.removeItem(x, y); - } - territory.setChanged(); - territory.notifyAllObservers(); - } + /** + * if possible take the item that occupies the tile Robbi is on. + */ + public final void nehmeAuf() { + synchronized (territory) { + Item i = territory.getItem(x, y); + if (i == null) + throw new NoItemException(); + if (this.item != null) { + throw new BagIsFullException(); + } + this.item = territory.removeItem(x, y); + } + territory.setChanged(); + territory.notifyAllObservers(); + } - /** - * If a pile of scrap is ahead of Robbi and afterwards a nonblocking tile, Robbi - * pushes the pile of scrap one tile the direction he is facing. - */ - public final void schiebeSchrotthaufen() { - synchronized (territory) { - territory.deactivateNotification(); - if (!vornSchrotthaufen()) { - territory.activateNotification(); - throw new NoPileOfScrapAheadException(); - } - int dx = switch (facing) { - case EAST -> x + 2; - case WEST -> x - 2; - default -> x; - }; - int dy = switch (facing) { - case NORTH -> y - 2; - case SOUTH -> y + 2; - default -> y; - }; + /** + * If a pile of scrap is ahead of Robbi and afterward a nonblocking tile, Robbi + * pushes the pile of scrap one tile the direction he is facing. + */ + public final void schiebeSchrotthaufen() { + synchronized (territory) { + territory.deactivateNotification(); + if (!vornSchrotthaufen()) { + territory.activateNotification(); + throw new NoPileOfScrapAheadException(); + } + int dx = switch (facing) { + case EAST -> x + 2; + case WEST -> x - 2; + default -> x; + }; + int dy = switch (facing) { + case NORTH -> y - 2; + case SOUTH -> y + 2; + default -> y; + }; - Tile t = territory.getTile(dx, dy); - if (t instanceof Stockpile || t instanceof PileOfScrap) { - territory.activateNotification(); - throw new TileBlockedException(); - } else { - if (territory.getTile(dx, dy) instanceof Hollow) - territory.clearTile(dx, dy); - else - territory.placePileOfScrap(dx, dy); - int px = switch (facing) { - case EAST -> x + 1; - case WEST -> x - 1; - default -> x; - }; - int py = switch (facing) { - case NORTH -> y - 1; - case SOUTH -> y + 1; - default -> y; - }; - territory.clearTile(px, py); - } - vor(); - } - territory.activateNotification(); - } + Tile t = territory.getTile(dx, dy); + if (t instanceof Stockpile || t instanceof PileOfScrap) { + territory.activateNotification(); + throw new TileBlockedException(); + } else { + if (territory.getTile(dx, dy) instanceof Hollow) + territory.clearTile(dx, dy); + else + territory.placePileOfScrap(dx, dy); + int px = switch (facing) { + case EAST -> x + 1; + case WEST -> x - 1; + default -> x; + }; + int py = switch (facing) { + case NORTH -> y - 1; + case SOUTH -> y + 1; + default -> y; + }; + territory.clearTile(px, py); + } + vor(); + } + territory.activateNotification(); + } - /** - * checks if an Item is on the tile Robbi is on. - * - * @return true if an item is on robbis tile, false otherwise - */ - public final boolean gegenstandDa() { - synchronized (territory) { - return territory.getItem(x, y) != null; - } - } + /** + * checks if an Item is on the tile Robbi is on. + * + * @return true if an item is on robbi's tile, false otherwise + */ + public final boolean gegenstandDa() { + synchronized (territory) { + return territory.getItem(x, y) != null; + } + } - /** - * Checks if the tile on which Robbi stands is a stockpile - * - * @return true if the current tile is an instanceof Stockpile, false otherwise - */ - public final boolean istLagerplatz() { - synchronized (territory) { - return territory.getTile(x, y) instanceof Stockpile; - } - } + /** + * Checks if the tile on which Robbi stands is a stockpile + * + * @return true if the current tile is an instanceof Stockpile, false otherwise + */ + public final boolean istLagerplatz() { + synchronized (territory) { + return territory.getTile(x, y) instanceof Stockpile; + } + } - /** - * checks if a hollow is ahead of Robbi. - * - * @return true if an hollow is ahead, false otherwise - */ - public final boolean vornKuhle() { - synchronized (territory) { - int dx = switch (facing) { - case EAST -> x + 1; - case WEST -> x - 1; - default -> x; - }; - int dy = switch (facing) { - case NORTH -> y - 1; - case SOUTH -> y + 1; - default -> y; - }; - return territory.getTile(dx, dy) instanceof Hollow; - } - } + /** + * checks if a hollow is ahead of Robbi. + * + * @return true if a hollow is ahead, false otherwise + */ + public final boolean vornKuhle() { + synchronized (territory) { + int dx = switch (facing) { + case EAST -> x + 1; + case WEST -> x - 1; + default -> x; + }; + int dy = switch (facing) { + case NORTH -> y - 1; + case SOUTH -> y + 1; + default -> y; + }; + return territory.getTile(dx, dy) instanceof Hollow; + } + } - /** - * checks if a pile of scrap is ahead of Robbi. - * - * @return true if a pile of scrap is ahead of robbi, false otherwise - */ - public final boolean vornSchrotthaufen() { - synchronized (territory) { - int dx = switch (facing) { - case EAST -> x + 1; - case WEST -> x - 1; - default -> x; - }; - int dy = switch (facing) { - case NORTH -> y - 1; - case SOUTH -> y + 1; - default -> y; - }; - return territory.getTile(dx, dy) instanceof PileOfScrap; - } - } + /** + * checks if a pile of scrap is ahead of Robbi. + * + * @return true if a pile of scrap is ahead of robbi, false otherwise + */ + public final boolean vornSchrotthaufen() { + synchronized (territory) { + int dx = switch (facing) { + case EAST -> x + 1; + case WEST -> x - 1; + default -> x; + }; + int dy = switch (facing) { + case NORTH -> y - 1; + case SOUTH -> y + 1; + default -> y; + }; + return territory.getTile(dx, dy) instanceof PileOfScrap; + } + } - /** - * checks if an item is in Robbis bag. - * - * @return true if an item is in the bag, false otherwise - */ - public final boolean istTascheVoll() { - synchronized (territory) { - return item != null; - } - } + /** + * checks if an item is in Robbi's bag. + * + * @return true if an item is in the bag, false otherwise + */ + public final boolean istTascheVoll() { + synchronized (territory) { + return item != null; + } + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiException.java index 7cf5bac..5a81d04 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiException.java @@ -2,29 +2,31 @@ import com.JayPi4c.RobbiSimulator.utils.I18nUtils; +import java.io.Serial; + /** * Abstract Exception class for almost all exceptions thrown in this * application. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public abstract class RobbiException extends RuntimeException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new RobbiException with the given message key. - * - * @param key a key for a message to provide further details of the exception - */ - protected RobbiException(String key) { - super(key); - } + /** + * Constructor for a new RobbiException with the given message key. + * + * @param key a key for a message to provide further details of the exception + */ + protected RobbiException(String key) { + super(key); + } - @Override - public String getLocalizedMessage() { - return I18nUtils.i18n(getMessage()); - } + @Override + public String getLocalizedMessage() { + return I18nUtils.i18n(getMessage()); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiState.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiState.java index 5685ebf..cfa7c77 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiState.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/RobbiState.java @@ -11,9 +11,8 @@ /** * Robbi State to store all state relevant attributes in order to apply the * Memento-Pattern. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement @Getter @@ -21,16 +20,16 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class RobbiState { - @XmlElement - private int x; + @XmlElement + private int x; - @XmlElement - private int y; + @XmlElement + private int y; - @XmlElement - private DIRECTION facing; + @XmlElement + private DIRECTION facing; - @XmlAnyElement - private Item item; + @XmlAnyElement + private Item item; } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Screw.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Screw.java index 77f3e92..31cb71c 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Screw.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Screw.java @@ -2,15 +2,17 @@ import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; + /** * Class representing the screw-item. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class Screw implements Item { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Stockpile.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Stockpile.java index d35a58c..3b525d5 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Stockpile.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Stockpile.java @@ -1,79 +1,80 @@ package com.JayPi4c.RobbiSimulator.model; -import java.util.ArrayList; -import java.util.List; - import jakarta.xml.bind.annotation.XmlAnyElement; import jakarta.xml.bind.annotation.XmlElementWrapper; import jakarta.xml.bind.annotation.XmlRootElement; +import java.io.Serial; +import java.util.ArrayList; +import java.util.List; + /** * Class representing a Stockpile tile. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement public class Stockpile extends Tile { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Attribute to store all items placed on the tile - */ - @XmlElementWrapper - @XmlAnyElement(lax = true) - private ArrayList items; - // TODO Queue more efficient? - // check if queue would be better, allowing an easier iteration over the - // elements. + /** + * Attribute to store all items placed on the tile + */ + @XmlElementWrapper + @XmlAnyElement(lax = true) + private final List items; + // TODO Queue more efficient? + // check if queue would be better, allowing an easier iteration over the + // elements. - /** - * Constructor to create a new Stockpile and initialize the list of items on the - * stockpile. - */ - public Stockpile() { - items = new ArrayList<>(); - } + /** + * Constructor to create a new Stockpile and initialize the list of items on the + * stockpile. + */ + public Stockpile() { + items = new ArrayList<>(); + } - /** - * Adds the given item to the list of items on the stockpile. - * - * @param item the item to add to the stockpile - */ - @Override - public void setItem(Item item) { - items.add(item); - } + /** + * Adds the given item to the list of items on the stockpile. + * + * @param item the item to add to the stockpile + */ + @Override + public void setItem(Item item) { + items.add(item); + } - /** - * Iterates through the list of items in the stockpile and returns one. - * - * @return the last item added to the stockpile, null if no item is placed on - * the stockpile - */ - @Override - public Item getItem() { - return (items.isEmpty()) ? null : items.get(items.size() - 1); - } + /** + * Iterates through the list of items in the stockpile and returns one. + * + * @return the last item added to the stockpile, null if no item is placed on + * the stockpile + */ + @Override + public Item getItem() { + return (items.isEmpty()) ? null : items.getLast(); + } - /** - * Removes and returns the last item from the stockpile. - * - * @return the last item added to the stockpile, null if no item was added yet - */ - @Override - public Item pickItem() { - return items.remove(items.size() - 1); - } + /** + * Removes and returns the last item from the stockpile. + * + * @return the last item added to the stockpile, null if no item was added yet + */ + @Override + public Item pickItem() { + return items.removeLast(); + } - /** - * Returns the full list of items placed on the stockpile. - * - * @return the arrayList containing all items on this stockpile - */ - public List getAllItems() { - return items; - } + /** + * Returns the full list of items placed on the stockpile. + * + * @return the arrayList containing all items on this stockpile + */ + public List getAllItems() { + return items; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Territory.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Territory.java index 01b9494..58625ff 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Territory.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Territory.java @@ -1,26 +1,13 @@ package com.JayPi4c.RobbiSimulator.model; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Serializable; -import java.util.Optional; - -import javax.xml.XMLConstants; -import javax.xml.stream.FactoryConfigurationError; -import javax.xml.stream.XMLInputFactory; -import javax.xml.stream.XMLOutputFactory; -import javax.xml.stream.XMLStreamConstants; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamReader; -import javax.xml.stream.XMLStreamWriter; - import com.JayPi4c.RobbiSimulator.utils.Observable; - import lombok.extern.slf4j.Slf4j; +import javax.xml.XMLConstants; +import javax.xml.stream.*; +import java.io.*; +import java.util.Optional; + /** * This class contains all datastructures and utility functions to control the * territory. @@ -30,6 +17,7 @@ @Slf4j public class Territory extends Observable implements Serializable { + @Serial private static final long serialVersionUID = 1L; private transient Robbi robbi; @@ -175,16 +163,16 @@ public synchronized Robbi getRobbi() { } /** - * Getter for robbis current direction. + * Getter for robbi's current direction. * - * @return robbis current direction + * @return robbi's current direction */ public synchronized DIRECTION getRobbiDirection() { return robbi.getFacing(); } /** - * Getter for robbis current item. + * Getter for robbi's current item. * * @return the item robbi is currently holding. null, if robbi does not have * one. @@ -200,7 +188,7 @@ public synchronized Item getRobbiItem() { * @param bound the bound to limit i to * @return the normalized value of i */ - private int normalizeCoord(int i, int bound) { + private int normalizeCoordinate(int i, int bound) { i %= bound; i += bound; i %= bound; @@ -229,7 +217,7 @@ public synchronized boolean robbiOnTile(int col, int row) { */ public boolean placeItem(Item item, int x, int y) { synchronized (this) { - Tile t = tiles[normalizeCoord(x, numberOfColumns)][normalizeCoord(y, numberOfRows)]; + Tile t = tiles[normalizeCoordinate(x, numberOfColumns)][normalizeCoordinate(y, numberOfRows)]; if (t.getItem() != null && !(t instanceof Stockpile)) return false; t.setItem(item); @@ -247,7 +235,7 @@ public boolean placeItem(Item item, int x, int y) { * @return the item, which is placed at the given position */ public synchronized Item getItem(int x, int y) { - Tile t = tiles[normalizeCoord(x, numberOfColumns)][normalizeCoord(y, numberOfRows)]; + Tile t = tiles[normalizeCoordinate(x, numberOfColumns)][normalizeCoordinate(y, numberOfRows)]; return t.getItem(); } @@ -259,9 +247,9 @@ public synchronized Item getItem(int x, int y) { * @return the item that has been removed from the tile */ public Item removeItem(int x, int y) { - Item i = null; + Item i; synchronized (this) { - Tile t = tiles[normalizeCoord(x, numberOfColumns)][normalizeCoord(y, numberOfRows)]; + Tile t = tiles[normalizeCoordinate(x, numberOfColumns)][normalizeCoordinate(y, numberOfRows)]; i = t.pickItem(); } setChanged(); @@ -277,9 +265,9 @@ public Item removeItem(int x, int y) { * * @param territory the new territory * @param item the item robbi has in his bag - * @param x robbis x position - * @param y robbis y positions - * @param facing robbis facing + * @param x robbi's x position + * @param y robbi's y positions + * @param facing robbi's facing * @throws InvalidTerritoryException if it is impossible to create the territory * with the given information */ @@ -355,8 +343,8 @@ public void changeSize(int newCols, int newRows) { /** * move robbi to the given position. * - * @param x robbis new x-position - * @param y robbis new y-position + * @param x robbi's new x-position + * @param y robbi's new y-position */ public void placeRobbi(int x, int y) { synchronized (this) { @@ -372,12 +360,12 @@ public void placeRobbi(int x, int y) { * Place a new Hollow at the given position if it is in bounds and robbi is not * on the tile. * - * @param x Hollows x-Position - * @param y Hollows y-Position + * @param x Hollow's x-Position + * @param y Hollow's y-Position */ public void placeHollow(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { if ((x < numberOfColumns && y < numberOfRows) && !(x == robbi.getX() && y == robbi.getY())) tiles[x][y] = new Hollow(); @@ -395,8 +383,8 @@ public void placeHollow(int x, int y) { * @param y PileOfScrap y-Position */ public void placePileOfScrap(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y] = new PileOfScrap(); } @@ -412,8 +400,8 @@ public void placePileOfScrap(int x, int y) { * @param y Stockpile y-Position */ public void placeStockpile(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y] = new Stockpile(); } @@ -428,8 +416,8 @@ public void placeStockpile(int x, int y) { * @param y Accu y-Position */ public void placeAccu(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y].setItem(new Accu()); } @@ -445,8 +433,8 @@ public void placeAccu(int x, int y) { * @param y Screw y-Position */ public void placeScrew(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y].setItem(new Screw()); } @@ -461,8 +449,8 @@ public void placeScrew(int x, int y) { * @param y Nut y-Position */ public void placeNut(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y].setItem(new Nut()); } @@ -477,8 +465,8 @@ public void placeNut(int x, int y) { * @param y Tile y-Position */ public void clearTile(int x, int y) { - x = normalizeCoord(x, numberOfColumns); - y = normalizeCoord(y, numberOfRows); + x = normalizeCoordinate(x, numberOfColumns); + y = normalizeCoordinate(y, numberOfRows); synchronized (this) { tiles[x][y] = new Tile(); } @@ -549,8 +537,7 @@ public boolean fromXML(InputStream stream) { } break; case "facing": - DIRECTION facing = DIRECTION.valueOf(parser.getAttributeValue(null, "facing")); - robbiDirection = facing; + robbiDirection = DIRECTION.valueOf(parser.getAttributeValue(null, "facing")); break; case "robbi": robbiX = Integer.parseInt(parser.getAttributeValue(null, "col")); @@ -579,7 +566,7 @@ public boolean fromXML(InputStream stream) { try { stream.close(); } catch (IOException e) { - e.printStackTrace(); + logger.error("Could not close stream", e); } } } @@ -594,14 +581,12 @@ public boolean fromXML(InputStream stream) { */ private Item getItemFromParser(XMLStreamReader parser) { String type = parser.getAttributeValue(null, "type"); - if (type.equals("Nut")) { - return new Nut(); - } else if (type.equals("Accu")) { - return new Accu(); - } else if (type.equals("Screw")) { - return new Screw(); - } - return null; + return switch (type) { + case "Nut" -> new Nut(); + case "Accu" -> new Accu(); + case "Screw" -> new Screw(); + default -> null; + }; } /** @@ -689,14 +674,13 @@ public ByteArrayOutputStream toXML() { return baos; } catch (FactoryConfigurationError | XMLStreamException e) { - e.printStackTrace(); - logger.error("failed to save as XML."); + logger.error("failed to save as XML.", e); return null; } } /** - * Helper to store an item in an xml-file. + * Helper to store an item in a xml-file. * * @param writer the writer, the item needs to be written to * @param item the item to write @@ -717,7 +701,7 @@ private void writeItem(XMLStreamWriter writer, Item item) throws XMLStreamExcept */ private Optional getDTD() { Optional module = ModuleLayer.boot().findModule("RobbiSimulator"); - if(module.isEmpty()) { + if (module.isEmpty()) { logger.warn("Could not load dtd"); return Optional.empty(); } @@ -736,18 +720,18 @@ private Optional getDTD() { } /** - * Getter for Robbis x Position. + * Getter for Robbi's x Position. * - * @return robbis x Position + * @return robbi's x Position */ public synchronized int getRobbiX() { return robbi.getX(); } /** - * Getter for Robbis y Position. + * Getter for Robbi's y Position. * - * @return robbis y Position + * @return robbi's y Position */ public synchronized int getRobbiY() { return robbi.getY(); diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/TerritoryState.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/TerritoryState.java index 592104f..556a239 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/TerritoryState.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/TerritoryState.java @@ -9,59 +9,58 @@ /** * Territory State to store all state relevant attributes in order to apply the * Memento-Pattern. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @XmlRootElement @Getter @NoArgsConstructor(access = AccessLevel.PRIVATE) public class TerritoryState { - @XmlElement - private int numberOfColumns; - @XmlElement - private int numberOfRows; - - @XmlElement - private Tile[][] tiles; - @XmlElement - private RobbiState robbiState; + @XmlElement + private int numberOfColumns; + @XmlElement + private int numberOfRows; - /** - * Constructor to create a Territory state. Creates an independet copy of the - * tiles array and the robbi. - * - * @param numberOfColumns number of columns in the territory - * @param numberOfRows number of rows in the territory - * @param tiles the tiles array representing the territory - * @param robbi the robbi in the territory - */ - public TerritoryState(int numberOfColumns, int numberOfRows, Tile[][] tiles, Robbi robbi) { - this.numberOfColumns = numberOfColumns; - this.numberOfRows = numberOfRows; - this.tiles = new Tile[tiles.length][tiles[0].length]; - for (int i = 0; i < tiles.length; i++) { - for (int j = 0; j < tiles[i].length; j++) { - Tile t = tiles[i][j]; - Tile newTile; - if (t instanceof Hollow) { - newTile = new Hollow(); - } else if (t instanceof PileOfScrap) { - newTile = new PileOfScrap(); - } else if (t instanceof Stockpile stockpile) { - newTile = new Stockpile(); - for (Item item : stockpile.getAllItems()) - newTile.setItem(item); - } else { - newTile = new Tile(); - newTile.setItem(t.getItem()); - } - this.tiles[i][j] = newTile; + @XmlElement + private Tile[][] tiles; + @XmlElement + private RobbiState robbiState; - } - } - this.robbiState = new RobbiState(robbi.getX(), robbi.getY(), robbi.getFacing(), robbi.getItem()); - } + /** + * Constructor to create a Territory state. Creates an independent copy of the + * tiles array and the robbi. + * + * @param numberOfColumns number of columns in the territory + * @param numberOfRows number of rows in the territory + * @param tiles the tiles array representing the territory + * @param robbi the robbi in the territory + */ + public TerritoryState(int numberOfColumns, int numberOfRows, Tile[][] tiles, Robbi robbi) { + this.numberOfColumns = numberOfColumns; + this.numberOfRows = numberOfRows; + this.tiles = new Tile[tiles.length][tiles[0].length]; + for (int i = 0; i < tiles.length; i++) { + for (int j = 0; j < tiles[i].length; j++) { + Tile newTile = switch (tiles[i][j]) { + case Hollow ignored: + yield new Hollow(); + case PileOfScrap ignored: + yield new PileOfScrap(); + case Stockpile stockpile: + Stockpile s = new Stockpile(); + for (Item item : stockpile.getAllItems()) + s.setItem(item); + yield s; + case Tile t: + Tile t2 = new Tile(); + t2.setItem(t.getItem()); + yield t2; + }; + this.tiles[i][j] = newTile; + } + } + this.robbiState = new RobbiState(robbi.getX(), robbi.getY(), robbi.getFacing(), robbi.getItem()); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/Tile.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/Tile.java index e8f79e6..7f3caba 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/Tile.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/Tile.java @@ -1,7 +1,5 @@ package com.JayPi4c.RobbiSimulator.model; -import java.io.Serializable; - import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAnyElement; @@ -9,35 +7,38 @@ import lombok.Getter; import lombok.Setter; +import java.io.Serial; +import java.io.Serializable; + /** * The default Tile for the territory. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ +@Getter +@Setter @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Tile implements Serializable { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Attribute to store the item whoch is placed on the tile. - */ - @Getter - @Setter - @XmlAnyElement(lax = true) - private Item item = null; + /** + * Attribute to store the item which is placed on the tile. + */ + @XmlAnyElement(lax = true) + private Item item = null; - /** - * Removes the item from the tile and returns it. - * - * @return the item stored on the tile - */ - public Item pickItem() { - Item it = item; - item = null; - return it; - } + /** + * Removes the item from the tile and returns it. + * + * @return the item stored on the tile + */ + public Item pickItem() { + Item it = item; + item = null; + return it; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/TileBlockedException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/TileBlockedException.java index e8e4fe9..50a4728 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/TileBlockedException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/TileBlockedException.java @@ -1,21 +1,23 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if robbi attempts to move a pile of Scrap while the * tile ahead is not suitable to push a pile to. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class TileBlockedException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new TileBlockedException with localized message. - */ - public TileBlockedException() { - super("Exception.TileBlocked"); - } + /** + * Constructor for a new TileBlockedException with localized message. + */ + public TileBlockedException() { + super("Exception.TileBlocked"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/model/TileIsFullException.java b/src/main/java/com/JayPi4c/RobbiSimulator/model/TileIsFullException.java index 8aeb97b..c3c6efa 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/model/TileIsFullException.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/model/TileIsFullException.java @@ -1,21 +1,23 @@ package com.JayPi4c.RobbiSimulator.model; +import java.io.Serial; + /** * Exception to be thrown if robbi attempts to place an item on a tile, that has * already an item stored. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class TileIsFullException extends RobbiException { - private static final long serialVersionUID = 1L; + @Serial + private static final long serialVersionUID = 1L; - /** - * Constructor for a new TileIsFullException with localized message. - */ - public TileIsFullException() { - super("Exception.TileIsFull"); - } + /** + * Constructor for a new TileIsFullException with localized message. + */ + public TileIsFullException() { + super("Exception.TileIsFull"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/AlertHelper.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/AlertHelper.java index f020d40..272d006 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/AlertHelper.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/AlertHelper.java @@ -9,104 +9,103 @@ /** * Static class to create Alerts with the necessary information. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class AlertHelper { - /** - * Creates and shows an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - */ - public static void showAlertAndWait(AlertType type, String message, Window owner) { - Alert alert = createAlert(type, message, owner); - alert.showAndWait(); - } + /** + * Creates and shows an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + */ + public static void showAlertAndWait(AlertType type, String message, Window owner) { + Alert alert = createAlert(type, message, owner); + alert.showAndWait(); + } - /** - * Creates and shows an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - * @param modality the modality of the alert - */ - public static void showAlertAndWait(AlertType type, String message, Window owner, Modality modality) { - Alert alert = createAlert(type, message, owner, modality); - alert.showAndWait(); - } + /** + * Creates and shows an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + * @param modality the modality of the alert + */ + public static void showAlertAndWait(AlertType type, String message, Window owner, Modality modality) { + Alert alert = createAlert(type, message, owner, modality); + alert.showAndWait(); + } - /** - * Creates and shows an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - * @param modality the modality of the alert - * @param title the title for the alert - * @param header the header for the alert - */ - public static void showAlertAndWait(AlertType type, String message, Window owner, Modality modality, String title, - String header) { - Alert alert = createAlert(type, message, owner, modality, title, header); - alert.showAndWait(); - } + /** + * Creates and shows an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + * @param modality the modality of the alert + * @param title the title for the alert + * @param header the header for the alert + */ + public static void showAlertAndWait(AlertType type, String message, Window owner, Modality modality, String title, + String header) { + Alert alert = createAlert(type, message, owner, modality, title, header); + alert.showAndWait(); + } - /** - * Creates an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - * @param modality the modality of the alert - * @param title the title for the alert - * @param header the header for the alert - * @return the alert with the given information - */ - public static Alert createAlert(AlertType type, String message, Window owner, Modality modality, String title, - String header) { - Alert alert = new Alert(type); - alert.setContentText(message); - if (title != null) - alert.setTitle(title); - if (header != null) - alert.setHeaderText(header); - alert.initModality(modality); - alert.initOwner(owner); - return alert; - } + /** + * Creates an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + * @param modality the modality of the alert + * @param title the title for the alert + * @param header the header for the alert + * @return the alert with the given information + */ + public static Alert createAlert(AlertType type, String message, Window owner, Modality modality, String title, + String header) { + Alert alert = new Alert(type); + alert.setContentText(message); + if (title != null) + alert.setTitle(title); + if (header != null) + alert.setHeaderText(header); + alert.initModality(modality); + alert.initOwner(owner); + return alert; + } - /** - * Creates an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - * @param modality the modality of the alert - * @return the alert with the given information - */ - public static Alert createAlert(AlertType type, String message, Window owner, Modality modality) { - return createAlert(type, message, owner, modality, null, null); - } + /** + * Creates an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + * @param modality the modality of the alert + * @return the alert with the given information + */ + public static Alert createAlert(AlertType type, String message, Window owner, Modality modality) { + return createAlert(type, message, owner, modality, null, null); + } - /** - * Creates an alert with the given information. - * - * @param type the AlertType of the alert - * @param message the contentText for the alert - * @param owner the alerts owner to place it relative to the parent - * @return the alert with the given information - */ - public static Alert createAlert(AlertType type, String message, Window owner) { - Alert alert = new Alert(type); - alert.setContentText(message); - alert.initOwner(owner); - return alert; - } + /** + * Creates an alert with the given information. + * + * @param type the AlertType of the alert + * @param message the contentText for the alert + * @param owner the alerts owner to place it relative to the parent + * @return the alert with the given information + */ + public static Alert createAlert(AlertType type, String message, Window owner) { + Alert alert = new Alert(type); + alert.setContentText(message); + alert.initOwner(owner); + return alert; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/HibernateUtils.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/HibernateUtils.java index c6f7174..0289b37 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/HibernateUtils.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/HibernateUtils.java @@ -1,15 +1,14 @@ package com.JayPi4c.RobbiSimulator.utils; -import org.hibernate.SessionFactory; -import org.hibernate.cfg.Configuration; - import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Configuration; /** * Utility class to manage the Hibernate SessionFactory. - * + * * @author Jonas Pohl * @since 1.0.0 */ @@ -17,37 +16,36 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class HibernateUtils { - /** - * The session factory to interact with the database via hibernate. - */ - private static SessionFactory sessionFactory; + /** + * The session factory to interact with the database via hibernate. + */ + private static SessionFactory sessionFactory; - /** - * Getter for the SessionFactory. If the SessionFactory is null, it will be - * created. - * - * @return The SessionFactory. - * - */ - public static SessionFactory getSessionFactory() { - if (sessionFactory == null) { - System.setProperty("derby.stream.error.file", "logs/derby.log"); // make sure log-file is in logs folder - try { - sessionFactory = new Configuration().configure().buildSessionFactory(); - } catch (Exception ex) { - logger.error("Initial SessionFactory creation failed: {}", ex); - throw new ExceptionInInitializerError(ex); - } - } - return sessionFactory; - } + /** + * Getter for the SessionFactory. If the SessionFactory is null, it will be + * created. + * + * @return The SessionFactory. + */ + public static SessionFactory getSessionFactory() { + if (sessionFactory == null) { + System.setProperty("derby.stream.error.file", "logs/derby.log"); // make sure log-file is in logs folder + try { + sessionFactory = new Configuration().configure().buildSessionFactory(); + } catch (Exception ex) { + logger.error("Initial SessionFactory creation failed.", ex); + throw new ExceptionInInitializerError(ex); + } + } + return sessionFactory; + } - /** - * Utility function to shutdown the database connection. - */ - public static void shutdown() { - if (sessionFactory != null) - sessionFactory.close(); - } + /** + * Utility function to shut down the database connection. + */ + public static void shutdown() { + if (sessionFactory != null) + sessionFactory.close(); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/I18nUtils.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/I18nUtils.java index 89c460c..3897137 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/I18nUtils.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/I18nUtils.java @@ -1,9 +1,5 @@ package com.JayPi4c.RobbiSimulator.utils; -import java.text.MessageFormat; -import java.util.Locale; -import java.util.ResourceBundle; - import javafx.beans.binding.Bindings; import javafx.beans.binding.StringBinding; import javafx.beans.property.ObjectProperty; @@ -13,9 +9,13 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.text.MessageFormat; +import java.util.Locale; +import java.util.ResourceBundle; + /** * Utility-Class to support internationalization. - * + * *
* Some research pointed out the eclipse solution for i18n. For further * information have a look in the this * Stack Overflow article. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class I18nUtils { - /** - * The resource bundle on which elements can bind in order to be updated on - * language change. - */ - private static final ObjectProperty bundle = new SimpleObjectProperty<>(); + /** + * The resource bundle on which elements can bind in order to be updated on + * language change. + */ + private static final ObjectProperty bundle = new SimpleObjectProperty<>(); - /** - * The current locale. Will be initially set to {@link Locale#UK} in JavaFX init - * Method. - * - */ - @Getter - private static Locale locale; + /** + * The current locale. Will be initially set to {@link Locale#UK} in JavaFX init + * Method. + */ + @Getter + private static Locale locale; - static { - setLocale(PropertiesLoader.getLocale()); - } + static { + setLocale(PropertiesLoader.getLocale()); + } - /** - * ObjectProperty to allow bindings - * - * @return The ObjectProperty - */ - public static ObjectProperty bundleProperty() { - return bundle; - } + /** + * ObjectProperty to allow bindings + * + * @return The ObjectProperty + */ + public static ObjectProperty bundleProperty() { + return bundle; + } - /** - * Getter for the current locale. - * - * @return the current locale - */ - public static ResourceBundle getBundle() { - return bundle.get(); - } + /** + * Getter for the current locale. + * + * @return the current locale + */ + public static ResourceBundle getBundle() { + return bundle.get(); + } - /** - * Setter for the current resourceBundle. - * - * @param bundle the new bundle - */ - public static void setBundle(ResourceBundle bundle) { - bundleProperty().set(bundle); - } + /** + * Setter for the current resourceBundle. + * + * @param bundle the new bundle + */ + public static void setBundle(ResourceBundle bundle) { + bundleProperty().set(bundle); + } - /** - * Returns the String mapped to the provided key in the current locale. - * - * @param key the key to be mapped - * @param args the arguments to be inserted into the String - * @return the localized String for the key - */ - public static String i18n(String key, final Object... args) { - return MessageFormat.format(getBundle().getString(key), args); - } + /** + * Returns the String mapped to the provided key in the current locale. + * + * @param key the key to be mapped + * @param args the arguments to be inserted into the String + * @return the localized String for the key + */ + public static String i18n(String key, final Object... args) { + return MessageFormat.format(getBundle().getString(key), args); + } - /** - * Helper to create a new String Binding for the provided key. - * - * @param key the key to be mapped on the resources - * @param args the arguments to be inserted into the String - * @return a binding for the provided key - */ - public static StringBinding createBinding(String key, final Object... args) { - return Bindings.createStringBinding(() -> i18n(key, args), bundleProperty()); - } + /** + * Helper to create a new String Binding for the provided key. + * + * @param key the key to be mapped on the resources + * @param args the arguments to be inserted into the String + * @return a binding for the provided key + */ + public static StringBinding createBinding(String key, final Object... args) { + return Bindings.createStringBinding(() -> i18n(key, args), bundleProperty()); + } - /** - * Method to create a tooltip for the given key and object parameters - * - * @param key the key for the language file - * @param args the arguments for the language file - * @return a i18n tooltip - */ - public static Tooltip createTooltip(String key, final Object... args) { - Tooltip tt = new Tooltip(); - tt.textProperty().bind(I18nUtils.createBinding(key, args)); - return tt; - } + /** + * Method to create a tooltip for the given key and object parameters + * + * @param key the key for the language file + * @param args the arguments for the language file + * @return a i18n tooltip + */ + public static Tooltip createTooltip(String key, final Object... args) { + Tooltip tt = new Tooltip(); + tt.textProperty().bind(I18nUtils.createBinding(key, args)); + return tt; + } - /** - * Sets the bundle to the given locale. - * - * @param locale the new locale for the resourceBundle - */ - public static void setLocale(Locale locale) { - I18nUtils.locale = locale; - Locale.setDefault(locale); - setBundle(ResourceBundle.getBundle("lang.messages", locale)); - } + /** + * Sets the bundle to the given locale. + * + * @param locale the new locale for the resourceBundle + */ + public static void setLocale(Locale locale) { + I18nUtils.locale = locale; + Locale.setDefault(locale); + setBundle(ResourceBundle.getBundle("lang.messages", locale)); + } - /** - * Setter for the current locale by the String representation of the locale. - * - * @param locale the locale as String - */ - public static void setLocale(String locale) { - try { - String[] parts = locale.split("_"); - setLocale(new Locale(parts[0], parts[1])); - } catch (IndexOutOfBoundsException | NullPointerException e) { - setLocale(Locale.UK); - } - } + /** + * Setter for the current locale by the String representation of the locale. + * + * @param languageTag the locale defined by a language tag + */ + public static void setLocale(String languageTag) { + try { + setLocale(Locale.forLanguageTag(languageTag)); + } catch (IndexOutOfBoundsException | NullPointerException e) { + setLocale(Locale.UK); + } + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observable.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observable.java index 23f16d2..2b85e5e 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observable.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observable.java @@ -5,83 +5,82 @@ /** * Abstract class to allow the Observer-Pattern. Classes implementing the * Observer Interface can register to classes extending this Observable class. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public abstract class Observable { - private CopyOnWriteArrayList observers; // faster than vector for read access and thread save + private final CopyOnWriteArrayList observers; // faster than vector for read access and thread save - private boolean changed; + private boolean changed; - private boolean notify = true; + private boolean notify = true; - /** - * Constructor for the Observable class which initializes the observer array. - */ - protected Observable() { - observers = new CopyOnWriteArrayList<>(); - changed = false; - } + /** + * Constructor for the Observable class which initializes the observer array. + */ + protected Observable() { + observers = new CopyOnWriteArrayList<>(); + changed = false; + } - /** - * Sets the changed flag to true, in order to allow the notifyAllObservers - * method to inform all observers. - */ - public void setChanged() { - changed = true; - } + /** + * Sets the changed flag to true, in order to allow the notifyAllObservers + * method to inform all observers. + */ + public void setChanged() { + changed = true; + } - /** - * Notifies all observers that the Observable Object has been updated. - */ - public void notifyAllObservers() { - if (notify) { - if (changed) { - for (Observer s : observers) - s.update(this); - } - changed = false; - } - } + /** + * Notifies all observers that the Observable Object has been updated. + */ + public void notifyAllObservers() { + if (notify) { + if (changed) { + for (Observer s : observers) + s.update(this); + } + changed = false; + } + } - /** - * Register a new Observer to the list of Observers. - * - * @param obs the new Observer to add to the list of observers. - */ - public void addObserver(Observer obs) { - observers.add(obs); - } + /** + * Register a new Observer to the list of Observers. + * + * @param obs the new Observer to add to the list of observers. + */ + public void addObserver(Observer obs) { + observers.add(obs); + } - /** - * Removes the given Observer from the list of observers. The Observer will no - * longer be notified about any updates. - * - * @param obs the observer to remove from the list of observers - * @return true if the observer could be removed, false otherwise - */ - public boolean removeObserver(Observer obs) { - return observers.remove(obs); - } + /** + * Removes the given Observer from the list of observers. The Observer will no + * longer be notified about any updates. + * + * @param obs the observer to remove from the list of observers + * @return true if the observer could be removed, false otherwise + */ + public boolean removeObserver(Observer obs) { + return observers.remove(obs); + } - /** - * Allows to send Notifications to all observers and notifies all Observers if - * changes have been made while the notifications had been deactivated. - */ - public void activateNotification() { - this.notify = true; - notifyAllObservers(); - } + /** + * Allows to send Notifications to all observers and notifies all Observers if + * changes have been made while the notifications had been deactivated. + */ + public void activateNotification() { + this.notify = true; + notifyAllObservers(); + } - /** - * Prevents the Observable class from notifying any observers even if - * notifyAllObservers is called. To activate notifications again, call - * activateNotification. - */ - public void deactivateNotification() { - this.notify = false; - } + /** + * Prevents the Observable class from notifying any observers even if + * notifyAllObservers is called. To activate notifications again, call + * activateNotification. + */ + public void deactivateNotification() { + this.notify = false; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observer.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observer.java index 9b78eac..4529ed6 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observer.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/Observer.java @@ -3,18 +3,17 @@ /** * Interface to allow to register to Observable classes. The update function * will be called whenever the observable class decides to notify all Observers. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public interface Observer { - /** - * Notifies the observer whenever the Observable class is notifying all - * observers about changes. - * - * @param observable the Observable to call the update function. - */ - public void update(Observable observable); + /** + * Notifies the observer whenever the Observable class is notifying all + * observers about changes. + * + * @param observable the Observable to call the update function. + */ + void update(Observable observable); } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/PropertiesLoader.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/PropertiesLoader.java index cadcb8f..15bfc8b 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/PropertiesLoader.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/PropertiesLoader.java @@ -1,5 +1,9 @@ package com.JayPi4c.RobbiSimulator.utils; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -7,160 +11,154 @@ import java.util.Locale; import java.util.Properties; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; - /** * Utility-class for Properties. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class PropertiesLoader { - private static Properties properties; - - private static final String DIR = System.getProperty("user.dir"); - private static final String FILE = "/simulator.properties"; - private static final String COMMENTS = "role=student OR tutor"; - - private static final String DARKMODE_PROPERTY = "darkmode"; - private static final String SOUNDS_PROPERTY = "sounds"; - private static final String TUTORPORT_PROPERTY = "tutorport"; - private static final String ROLE_PROPERTY = "role"; - private static final String LANGUAGE_PROPERTY = "lang"; - private static final String TUTORHOST_PROPERTY = "tutorhost"; - - private static final String TUTORHOST_DEFAULT_VALUE = "localhost"; - private static final String TUTORPORT_DEFAULT_VALUE = "3579"; - - /** - * Loads the properties and stores them in an Object. - * - * If the simulator.properties file can't be found, default values will be - * loaded. - * - * @return true if the initialization was successful, false otherwise - */ - public static boolean initialize() { - properties = new Properties(); - try (InputStream in = new FileInputStream(DIR + FILE)) { - properties.load(in); - return true; - } catch (IOException e) { - loadDefaultProperties(); - return false; - } - } - - /** - * Getter for the role - * - * @return true if the role is set to tutor, false otherwise - */ - public static boolean isTutor() { - try { - return properties.getProperty(ROLE_PROPERTY).equalsIgnoreCase("tutor"); - } catch (NullPointerException e) { - properties.put(ROLE_PROPERTY, "student"); - return false; - } - } - - /** - * Getter for the sounds property. - * - * @return true if the sounds property is set to true - */ - public static boolean getSounds() { - return Boolean.parseBoolean(properties.getProperty(SOUNDS_PROPERTY)); - } - - /** - * Getter for the sounds property. - * - * @return true if the sounds property is set to true - */ - public static boolean getDarkmode() { - return Boolean.parseBoolean(properties.getProperty(DARKMODE_PROPERTY)); - } - - /** - * Getter for the tutorhost. - * - * @return the tutorhost stored in the properties file, localhost if no - * propterty is found - */ - public static String getTutorhost() { - String host = properties.getProperty(TUTORHOST_PROPERTY); - if (host == null) { - host = TUTORHOST_DEFAULT_VALUE; - properties.put(TUTORHOST_PROPERTY, host); - } - return host; - } - - /** - * Getter for the tutorport. - * - * @return the tutorport stored in the properties file - */ - public static int getTutorport() { - try { - return Integer.parseInt(properties.getProperty(TUTORPORT_PROPERTY)); - } catch (NumberFormatException | NullPointerException e) { - properties.put(TUTORPORT_PROPERTY, TUTORPORT_DEFAULT_VALUE); - return Integer.parseInt(TUTORPORT_DEFAULT_VALUE); - } - } - - /** - * Getter for the locale. - * - * @return the locale stored in the properties file - */ - public static Locale getLocale() { - try { - String[] parts = properties.getProperty(LANGUAGE_PROPERTY).split("_"); - return new Locale(parts[0], parts[1]); - } catch (IndexOutOfBoundsException | NullPointerException e) { - logger.debug("Failed to load locale from properties"); - properties.put(LANGUAGE_PROPERTY, Locale.GERMANY.toString()); - return Locale.GERMANY; - } - } - - /** - * Stores all properties back in the properties file. - * - * @return true, if the saving was successful, false otherwise - */ - public static boolean finish() { - properties.put(LANGUAGE_PROPERTY, I18nUtils.getLocale().toString()); - properties.put(SOUNDS_PROPERTY, Boolean.toString(SoundManager.getSound())); - properties.put(DARKMODE_PROPERTY, Boolean.toString(SceneManager.getDarkmode())); - try (FileOutputStream fos = new FileOutputStream(DIR + FILE)) { - properties.store(fos, COMMENTS); - return true; - } catch (IOException e) { - return false; - } - } - - /** - * Loads initial values in the properties object. This is needed if the - * application failed to load properties from the file. - */ - private static void loadDefaultProperties() { - properties.put(LANGUAGE_PROPERTY, Locale.GERMANY.toString()); - properties.put(ROLE_PROPERTY, "student"); - properties.put(TUTORPORT_PROPERTY, TUTORPORT_DEFAULT_VALUE); - properties.put(TUTORHOST_PROPERTY, TUTORHOST_DEFAULT_VALUE); - properties.put(SOUNDS_PROPERTY, Boolean.toString(false)); - properties.put(DARKMODE_PROPERTY, Boolean.toString(false)); - } + private static Properties properties; + + private static final String DIR = System.getProperty("user.dir"); + private static final String FILE = "/simulator.properties"; + private static final String COMMENTS = "role=student OR tutor"; + + private static final String DARKMODE_PROPERTY = "darkmode"; + private static final String SOUNDS_PROPERTY = "sounds"; + private static final String TUTORPORT_PROPERTY = "tutorport"; + private static final String ROLE_PROPERTY = "role"; + private static final String LANGUAGE_PROPERTY = "lang"; + private static final String TUTORHOST_PROPERTY = "tutorhost"; + + private static final String TUTORHOST_DEFAULT_VALUE = "localhost"; + private static final String TUTORPORT_DEFAULT_VALUE = "3579"; + + /** + * Loads the properties and stores them in an Object. + *

+ * If the simulator.properties file can't be found, default values will be + * loaded. + * + * @return true if the initialization was successful, false otherwise + */ + public static boolean initialize() { + properties = new Properties(); + try (InputStream in = new FileInputStream(DIR + FILE)) { + properties.load(in); + return true; + } catch (IOException e) { + loadDefaultProperties(); + return false; + } + } + + /** + * Getter for the role + * + * @return true if the role is set to tutor, false otherwise + */ + public static boolean isTutor() { + try { + return properties.getProperty(ROLE_PROPERTY).equalsIgnoreCase("tutor"); + } catch (NullPointerException e) { + properties.put(ROLE_PROPERTY, "student"); + return false; + } + } + + /** + * Getter for the sounds-property. + * + * @return true if the sounds property is set to true + */ + public static boolean getSounds() { + return Boolean.parseBoolean(properties.getProperty(SOUNDS_PROPERTY)); + } + + /** + * Getter for the darkmode-property. + * + * @return true if the darkmode property is set to true + */ + public static boolean getDarkmode() { + return Boolean.parseBoolean(properties.getProperty(DARKMODE_PROPERTY)); + } + + /** + * Getter for the tutorhost. + * + * @return the tutorhost stored in the properties file, localhost if no + * propterty is found + */ + public static String getTutorhost() { + String host = properties.getProperty(TUTORHOST_PROPERTY); + if (host == null) { + host = TUTORHOST_DEFAULT_VALUE; + properties.put(TUTORHOST_PROPERTY, host); + } + return host; + } + + /** + * Getter for the tutor-port. + * + * @return the tutor-port stored in the properties file + */ + public static int getTutorport() { + try { + return Integer.parseInt(properties.getProperty(TUTORPORT_PROPERTY)); + } catch (NumberFormatException | NullPointerException e) { + properties.put(TUTORPORT_PROPERTY, TUTORPORT_DEFAULT_VALUE); + return Integer.parseInt(TUTORPORT_DEFAULT_VALUE); + } + } + + /** + * Getter for the locale. + * + * @return the locale stored in the properties file + */ + public static Locale getLocale() { + try { + return Locale.forLanguageTag(properties.getProperty(LANGUAGE_PROPERTY)); + } catch (IndexOutOfBoundsException | NullPointerException e) { + logger.debug("Failed to load locale from properties"); + properties.put(LANGUAGE_PROPERTY, Locale.GERMANY.toLanguageTag()); + return Locale.GERMANY; + } + } + + /** + * Stores all properties back in the properties file. + * + * @return true, if the saving was successful, false otherwise + */ + public static boolean finish() { + properties.put(LANGUAGE_PROPERTY, I18nUtils.getLocale().toLanguageTag()); + properties.put(SOUNDS_PROPERTY, Boolean.toString(SoundManager.getSound())); + properties.put(DARKMODE_PROPERTY, Boolean.toString(SceneManager.getDarkmode())); + try (FileOutputStream fos = new FileOutputStream(DIR + FILE)) { + properties.store(fos, COMMENTS); + return true; + } catch (IOException e) { + return false; + } + } + + /** + * Loads initial values in the properties object. This is needed if the + * application failed to load properties from the file. + */ + private static void loadDefaultProperties() { + properties.put(LANGUAGE_PROPERTY, Locale.GERMANY.toLanguageTag()); + properties.put(ROLE_PROPERTY, "student"); + properties.put(TUTORPORT_PROPERTY, TUTORPORT_DEFAULT_VALUE); + properties.put(TUTORHOST_PROPERTY, TUTORHOST_DEFAULT_VALUE); + properties.put(SOUNDS_PROPERTY, Boolean.toString(false)); + properties.put(DARKMODE_PROPERTY, Boolean.toString(false)); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/SceneManager.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/SceneManager.java index 49b1928..daf24a8 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/SceneManager.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/SceneManager.java @@ -9,55 +9,54 @@ /** * Class to manage the loaded scene. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class SceneManager { - - private static final String DARK_MODE_CSS = Objects.requireNonNull(SceneManager.class.getResource("/css/dark-theme.css")).toExternalForm(); - - /** - * The boolean on which elements can bind in order to be updated on dark-mode - * change. - */ - private static final ObjectProperty darkmode = new SimpleObjectProperty<>(PropertiesLoader.getDarkmode()); - - /** - * ObjectProperty to allow bindings - * - * @return The ObjectProperty - */ - public static ObjectProperty darkmodeProperty() { - return darkmode; - } - - /** - * Getter for the current dark-mode flag. - * - * @return the current dark-mode setting - */ - public static boolean getDarkmode() { - return darkmode.get(); - } - - /** - * Setter for the current dark-mode flag. - * - * @param flag the new value - */ - public static void setDarkmode(boolean flag) { - darkmodeProperty().set(flag); - } - - /** - * Getter for the dark-mode css source. - * - * @return the source for the dark-mode css - */ - public static String getDarkmodeCss() { - return DARK_MODE_CSS; - } + + private static final String DARK_MODE_CSS = Objects.requireNonNull(SceneManager.class.getResource("/css/dark-theme.css")).toExternalForm(); + + /** + * The boolean on which elements can bind in order to be updated on dark-mode + * change. + */ + private static final ObjectProperty darkmode = new SimpleObjectProperty<>(PropertiesLoader.getDarkmode()); + + /** + * ObjectProperty to allow bindings + * + * @return The ObjectProperty + */ + public static ObjectProperty darkmodeProperty() { + return darkmode; + } + + /** + * Getter for the current dark-mode flag. + * + * @return the current dark-mode setting + */ + public static boolean getDarkmode() { + return darkmode.get(); + } + + /** + * Setter for the current dark-mode flag. + * + * @param flag the new value + */ + public static void setDarkmode(boolean flag) { + darkmodeProperty().set(flag); + } + + /** + * Getter for the dark-mode css source. + * + * @return the source for the dark-mode css + */ + public static String getDarkmodeCss() { + return DARK_MODE_CSS; + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/SoundManager.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/SoundManager.java index fc123ca..b778472 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/SoundManager.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/SoundManager.java @@ -1,75 +1,76 @@ package com.JayPi4c.RobbiSimulator.utils; -import java.net.URISyntaxException; - import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.scene.media.Media; import javafx.scene.media.MediaPlayer; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.net.URISyntaxException; /** * Manager to load and play sounds. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ +@Slf4j @NoArgsConstructor(access = AccessLevel.PRIVATE) public class SoundManager { - /** - * The boolean on which elements can bind in order to be updated if sound is - * deactivated /activated - */ - private static final ObjectProperty sound = new SimpleObjectProperty<>(PropertiesLoader.getSounds()); + /** + * The boolean on which elements can bind in order to be updated if sound is + * deactivated /activated + */ + private static final ObjectProperty sound = new SimpleObjectProperty<>(PropertiesLoader.getSounds()); - private static Media warningSound = null; + private static Media warningSound = null; - /** - * Plays a warning sounds. If the sound is not loaded yet, the sound will be - * loaded and stored for further plays. - */ - public static void playWarnSound() { - if (Boolean.FALSE.equals(sound.get())) - return; - if (warningSound == null) { - try { - warningSound = new Media( - SoundManager.class.getResource("/sounds/warning-sound.mp3").toURI().toString()); - } catch (URISyntaxException e) { - e.printStackTrace(); - } - } - MediaPlayer mediaPlayer = new MediaPlayer(warningSound); - mediaPlayer.play(); - } + /** + * Plays a warning sounds. If the sound is not loaded yet, the sound will be + * loaded and stored for further plays. + */ + public static void playWarnSound() { + if (Boolean.FALSE.equals(sound.get())) + return; + if (warningSound == null) { + try { + warningSound = new Media( + SoundManager.class.getResource("/sounds/warning-sound.mp3").toURI().toString()); + } catch (URISyntaxException e) { + logger.error("Could not load sound file.", e); + } + } + MediaPlayer mediaPlayer = new MediaPlayer(warningSound); + mediaPlayer.play(); + } - /** - * ObjectProperty to allow bindings - * - * @return The ObjectProperty - */ - public static ObjectProperty soundProperty() { - return sound; - } + /** + * ObjectProperty to allow bindings + * + * @return The ObjectProperty + */ + public static ObjectProperty soundProperty() { + return sound; + } - /** - * Getter for the current sound flag. - * - * @return the current sound setting - */ - public static boolean getSound() { - return sound.get(); - } + /** + * Getter for the current sound flag. + * + * @return the current sound setting + */ + public static boolean getSound() { + return sound.get(); + } - /** - * Setter for the current sound flag. - * - * @param flag the new value - */ - public static void setSound(boolean flag) { - soundProperty().set(flag); - } + /** + * Setter for the current sound flag. + * + * @param flag the new value + */ + public static void setSound(boolean flag) { + soundProperty().set(flag); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/utils/annotations/Invisible.java b/src/main/java/com/JayPi4c/RobbiSimulator/utils/annotations/Invisible.java index 6015cfd..a2e064b 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/utils/annotations/Invisible.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/utils/annotations/Invisible.java @@ -9,9 +9,8 @@ * Annotation to hide methods from the ContextMenu. Methods annotated with this * annotation will not show up in the ContextMenu. Nonetheless, they still can * be used in the code without any restrictions. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/view/MainStage.java b/src/main/java/com/JayPi4c/RobbiSimulator/view/MainStage.java index 461990a..39c7d96 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/view/MainStage.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/view/MainStage.java @@ -96,7 +96,7 @@ public class MainStage extends Stage { */ public static final Image menuScrewImage; /** - * Constant Image for nut icon. + * Constant Image for the nut icon. */ public static final Image menuNutImage; /** @@ -136,9 +136,6 @@ public class MainStage extends Stage { */ public static final Image robbiTake; - /** - * loading images - */ static { logger.debug("Loading stage images"); newImage = new Image(String.valueOf(MainStage.class.getResource("/img/New24.gif"))); @@ -167,26 +164,26 @@ public class MainStage extends Stage { robbiTake = new Image(String.valueOf(MainStage.class.getResource("/img/RobbiTake24.png"))); } - private Territory territory; - private ButtonState buttonState; + private final Territory territory; + private final ButtonState buttonState; // controllers - private MainStageController mainStageController; - private SimulationController simulationController; - private TerritorySaveController territorySaveController; - private ExamplesController examplesController; - private StudentController studenController; + private final MainStageController mainStageController; + private final SimulationController simulationController; + private final TerritorySaveController territorySaveController; + private final ExamplesController examplesController; + private StudentController studentController; private TutorController tutorController; - private LanguageController languageController; - private NotificationController notificationController; - private Program program; - private MenuBar menubar; - private Toolbar toolbar; + private final LanguageController languageController; + private final NotificationController notificationController; + private final Program program; + private final MenuBar menubar; + private final Toolbar toolbar; // Content Pane private MonacoFX textArea; private ScrollPane territoryScrollPane; private TerritoryPanel territoryPanel; private SplitPane splitPane; - private Scene mainStageScene; + private final Scene mainStageScene; /** * Constructor for the MainStage. It creates a mainStage for the given Program @@ -228,7 +225,7 @@ public MainStage(Program program) { if (PropertiesLoader.isTutor()) tutorController = new TutorController(this); else - studenController = new StudentController(this); + studentController = new StudentController(this); show(); textArea.requestFocus(); diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/view/MenuBar.java b/src/main/java/com/JayPi4c/RobbiSimulator/view/MenuBar.java index 943ebe0..7dc426b 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/view/MenuBar.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/view/MenuBar.java @@ -1,13 +1,7 @@ package com.JayPi4c.RobbiSimulator.view; import com.JayPi4c.RobbiSimulator.utils.PropertiesLoader; - -import javafx.scene.control.CheckMenuItem; -import javafx.scene.control.Menu; -import javafx.scene.control.MenuItem; -import javafx.scene.control.RadioMenuItem; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.ToggleGroup; +import javafx.scene.control.*; import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCodeCombination; @@ -16,310 +10,308 @@ import lombok.extern.slf4j.Slf4j; /** - * * The menuBar holds all possible actions for the application in one menuBar. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j @Getter public class MenuBar extends javafx.scene.control.MenuBar { - // Menu Bar - // editor Menu - private MenuItem newEditorMenuItem; - private MenuItem saveEditorMenuItem; - private MenuItem openEditorMenuItem; - private MenuItem formatSourceCodeMenuItem; - private MenuItem compileEditorMenuItem; - private MenuItem printEditorMenuItem; - - private MenuItem quitEditorMenuItem; - private Menu editorMenu; - - // territory Menu - private MenuItem saveXMLTerritoryMenuItem; - private MenuItem saveJAXBTerritoryMenuItem; - private MenuItem saveSerialTerritoryMenuItem; - - private Menu saveTerritoryMenu; - private MenuItem loadXMLTerritoryMenuItem; - private MenuItem loadJAXBTerritoryMenuItem; - private MenuItem loadSerialTerritoryMenuItem; - - private Menu loadTerritoryMenu; - private Menu saveAsPicMenu; - private MenuItem saveAsPNGMenuItem; - private MenuItem saveAsGifMenuItem; - private MenuItem printTerritoryMenuItem; - private MenuItem changeSizeTerritoryMenuItem; - private RadioMenuItem placeRobbiTerritoryRadioMenuItem; - private RadioMenuItem placeHollowTerritoryRadioMenuItem; - private RadioMenuItem placePileOfScrapTerritoryRadioMenuItem; - private RadioMenuItem placeStockpileTerritoryRadioMenuItem; - private RadioMenuItem placeAccuTerritoryRadioMenuItem; - private RadioMenuItem placeScrewTerritoryRadioMenuItem; - private RadioMenuItem placeNutTerritoryRadioMenuItem; - private RadioMenuItem deleteFieldRadioMenuItem; - private Menu territoryMenu; - private ToggleGroup placeGroupTerritoryMenu; - - // robbi Menu - private MenuItem itemPresentMenuItem; - private MenuItem isStockpileMenuItem; - private MenuItem hollowAheadMenuItem; - private MenuItem pileOfScrapAheadMenuItem; - private MenuItem isBagFullMenuItem; - private MenuItem pushPileOfScrapMenuItem; - private MenuItem moveMenuItem; - private MenuItem turnLeftMenuItem; - private MenuItem putMenuItem; - private MenuItem takeMenuItem; - private Menu robbiMenu; - - // simulation Menu - private MenuItem resetMenuItem; - private MenuItem startMenuItem; - private MenuItem pauseMenuItem; - private MenuItem stopMenuItem; - private Menu simulationMenu; - - // examples Menu - private MenuItem loadExampleMenuItem; - private MenuItem saveExampleMenuItem; - private Menu examplesMenu; - - // window Menu - private Menu languageMenu; - private MenuItem englishLanguageMenuItem; - private MenuItem germanLanguageMenuItem; - private CheckMenuItem changeCursorMenuItem; - private CheckMenuItem darkModeMenuItem; - private CheckMenuItem enableSoundsMenuItem; - private MenuItem infoMenuItem; - private MenuItem libraryMenuItem; - private Menu windowMenu; - - // tutor Menu - private Menu tutorMenu; - private MenuItem sendRequestMenuItem; - private MenuItem receiveAnswerMenuItem; - private MenuItem loadRequestMenuItem; - private MenuItem saveAnswerMenuItem; - - /** - * Creates a new MenuBar - */ - public MenuBar() { - createMenuBar(); - getMenus().addAll(editorMenu, territoryMenu, robbiMenu, simulationMenu, examplesMenu, tutorMenu, windowMenu); - } - - /** - * Creates the editor-related menu-bar elements. - */ - private void createEditor() { - logger.debug("Create editor entry for menubar"); - newEditorMenuItem = new MenuItem(); - newEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN)); - newEditorMenuItem.setMnemonicParsing(true); - newEditorMenuItem.setGraphic(new ImageView(MainStage.newImage)); - saveEditorMenuItem = new MenuItem(); - saveEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN)); - saveEditorMenuItem.setGraphic(new ImageView(MainStage.saveImage)); - openEditorMenuItem = new MenuItem(); - openEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN)); - openEditorMenuItem.setGraphic(new ImageView(MainStage.openImage)); - - formatSourceCodeMenuItem = new MenuItem(); - formatSourceCodeMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN)); // T - // for - // tidy - - compileEditorMenuItem = new MenuItem(); - compileEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.K, KeyCombination.CONTROL_DOWN)); - compileEditorMenuItem.setGraphic(new ImageView(MainStage.compileImage)); - - printEditorMenuItem = new MenuItem(); - printEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.P, KeyCombination.CONTROL_DOWN)); - printEditorMenuItem.setGraphic(new ImageView(MainStage.printImage)); - quitEditorMenuItem = new MenuItem(); - quitEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN)); - editorMenu = new Menu("", null, newEditorMenuItem, openEditorMenuItem, saveEditorMenuItem, - new SeparatorMenuItem(), formatSourceCodeMenuItem, compileEditorMenuItem, printEditorMenuItem, - new SeparatorMenuItem(), quitEditorMenuItem); - editorMenu.setMnemonicParsing(true); - } - - /** - * Creates the territory-related menu-bar elements. - */ - private void createTerritory() { - logger.debug("Create territory entry for menubar"); - saveXMLTerritoryMenuItem = new MenuItem(); - saveJAXBTerritoryMenuItem = new MenuItem(); - saveSerialTerritoryMenuItem = new MenuItem(); - - saveTerritoryMenu = new Menu("", null, saveXMLTerritoryMenuItem, saveJAXBTerritoryMenuItem, - saveSerialTerritoryMenuItem); - loadXMLTerritoryMenuItem = new MenuItem(); - loadJAXBTerritoryMenuItem = new MenuItem(); - loadSerialTerritoryMenuItem = new MenuItem(); - loadTerritoryMenu = new Menu("", null, loadXMLTerritoryMenuItem, loadJAXBTerritoryMenuItem, - loadSerialTerritoryMenuItem); - - saveAsPNGMenuItem = new MenuItem(); - saveAsGifMenuItem = new MenuItem(); - saveAsPicMenu = new Menu("", null, saveAsPNGMenuItem, saveAsGifMenuItem); - - printTerritoryMenuItem = new MenuItem(); - changeSizeTerritoryMenuItem = new MenuItem(); - - placeGroupTerritoryMenu = new ToggleGroup(); - - placeRobbiTerritoryRadioMenuItem = new RadioMenuItem(); - placeRobbiTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placeHollowTerritoryRadioMenuItem = new RadioMenuItem(); - placeHollowTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placePileOfScrapTerritoryRadioMenuItem = new RadioMenuItem(); - placePileOfScrapTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placeStockpileTerritoryRadioMenuItem = new RadioMenuItem(); - placeStockpileTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placeAccuTerritoryRadioMenuItem = new RadioMenuItem(); - placeAccuTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placeScrewTerritoryRadioMenuItem = new RadioMenuItem(); - placeScrewTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - placeNutTerritoryRadioMenuItem = new RadioMenuItem(); - placeNutTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - deleteFieldRadioMenuItem = new RadioMenuItem(); - deleteFieldRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); - - territoryMenu = new Menu("", null, saveTerritoryMenu, loadTerritoryMenu, saveAsPicMenu, printTerritoryMenuItem, - changeSizeTerritoryMenuItem, new SeparatorMenuItem(), placeRobbiTerritoryRadioMenuItem, - placeHollowTerritoryRadioMenuItem, placePileOfScrapTerritoryRadioMenuItem, - placeStockpileTerritoryRadioMenuItem, placeAccuTerritoryRadioMenuItem, placeScrewTerritoryRadioMenuItem, - placeNutTerritoryRadioMenuItem, deleteFieldRadioMenuItem); - } - - /** - * Creates the robbi-related menu-bar elements. - */ - private void createRobbi() { - logger.debug("Create Robbi entry for menubar"); - territoryMenu.setMnemonicParsing(true); - itemPresentMenuItem = new MenuItem(); - isStockpileMenuItem = new MenuItem(); - hollowAheadMenuItem = new MenuItem(); - pileOfScrapAheadMenuItem = new MenuItem(); - isBagFullMenuItem = new MenuItem(); - pushPileOfScrapMenuItem = new MenuItem(); - moveMenuItem = new MenuItem(); - moveMenuItem.setAccelerator( - new KeyCodeCombination(KeyCode.V, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); - turnLeftMenuItem = new MenuItem(); - turnLeftMenuItem.setAccelerator( - new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); - - putMenuItem = new MenuItem(); - putMenuItem.setAccelerator( - new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); - takeMenuItem = new MenuItem(); - takeMenuItem.setAccelerator( - new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); - robbiMenu = new Menu("", null, moveMenuItem, turnLeftMenuItem, putMenuItem, takeMenuItem, - pushPileOfScrapMenuItem, itemPresentMenuItem, isStockpileMenuItem, hollowAheadMenuItem, - pileOfScrapAheadMenuItem, isBagFullMenuItem); - robbiMenu.setMnemonicParsing(true); - } - - /** - * Creates the simulation-related menu-bar elements. - */ - private void createSimulation() { - logger.debug("Create simulation entry for menubar"); - - resetMenuItem = new MenuItem(); - resetMenuItem.setGraphic(new ImageView(MainStage.resetImage)); - startMenuItem = new MenuItem(); - startMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.F11, KeyCombination.CONTROL_DOWN)); - startMenuItem.setGraphic(new ImageView(MainStage.menuStartImage)); - pauseMenuItem = new MenuItem(); - pauseMenuItem.setGraphic(new ImageView(MainStage.menuPauseImage)); - stopMenuItem = new MenuItem(); - stopMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.F12, KeyCombination.CONTROL_DOWN)); - stopMenuItem.setGraphic(new ImageView(MainStage.menuStopImage)); - simulationMenu = new Menu("", null, resetMenuItem, startMenuItem, pauseMenuItem, stopMenuItem); - simulationMenu.setMnemonicParsing(true); - } - - /** - * Creates the examples-related menu-bar elements - */ - private void createExamplesMenu() { - saveExampleMenuItem = new MenuItem(); - loadExampleMenuItem = new MenuItem(); - examplesMenu = new Menu("", null, saveExampleMenuItem, loadExampleMenuItem); - } - - /** - * Creates the tutor-related menu-bar elements - */ - private void createTutorMenu() { - if (PropertiesLoader.isTutor()) { - loadRequestMenuItem = new MenuItem(); - saveAnswerMenuItem = new MenuItem(); - - tutorMenu = new Menu("", null, loadRequestMenuItem, saveAnswerMenuItem); - } else { - sendRequestMenuItem = new MenuItem(); - receiveAnswerMenuItem = new MenuItem(); - - tutorMenu = new Menu("", null, sendRequestMenuItem, receiveAnswerMenuItem); - } - } - - /** - * Creates the window-related menu-bar elements. - */ - private void createWindowMenu() { - englishLanguageMenuItem = new MenuItem(); - germanLanguageMenuItem = new MenuItem(); - languageMenu = new Menu("", null, englishLanguageMenuItem, germanLanguageMenuItem); - - changeCursorMenuItem = new CheckMenuItem(); - // https://stackoverflow.com/a/49159612/13670629 - darkModeMenuItem = new CheckMenuItem(); - enableSoundsMenuItem = new CheckMenuItem(); - - infoMenuItem = new MenuItem(); - libraryMenuItem = new MenuItem(); - - windowMenu = new Menu("", null, languageMenu, changeCursorMenuItem, darkModeMenuItem, enableSoundsMenuItem, - new SeparatorMenuItem(), infoMenuItem, libraryMenuItem); - } - - /** - * Creates the entire menuBar. - */ - private void createMenuBar() { - logger.debug("Create menubar"); - - createEditor(); - createTerritory(); - createRobbi(); - createSimulation(); - createExamplesMenu(); - createTutorMenu(); - createWindowMenu(); - - } + // Menu Bar + // editor Menu + private MenuItem newEditorMenuItem; + private MenuItem saveEditorMenuItem; + private MenuItem openEditorMenuItem; + private MenuItem formatSourceCodeMenuItem; + private MenuItem compileEditorMenuItem; + private MenuItem printEditorMenuItem; + + private MenuItem quitEditorMenuItem; + private Menu editorMenu; + + // territory Menu + private MenuItem saveXMLTerritoryMenuItem; + private MenuItem saveJAXBTerritoryMenuItem; + private MenuItem saveSerialTerritoryMenuItem; + + private Menu saveTerritoryMenu; + private MenuItem loadXMLTerritoryMenuItem; + private MenuItem loadJAXBTerritoryMenuItem; + private MenuItem loadSerialTerritoryMenuItem; + + private Menu loadTerritoryMenu; + private Menu saveAsPicMenu; + private MenuItem saveAsPNGMenuItem; + private MenuItem saveAsGifMenuItem; + private MenuItem printTerritoryMenuItem; + private MenuItem changeSizeTerritoryMenuItem; + private RadioMenuItem placeRobbiTerritoryRadioMenuItem; + private RadioMenuItem placeHollowTerritoryRadioMenuItem; + private RadioMenuItem placePileOfScrapTerritoryRadioMenuItem; + private RadioMenuItem placeStockpileTerritoryRadioMenuItem; + private RadioMenuItem placeAccuTerritoryRadioMenuItem; + private RadioMenuItem placeScrewTerritoryRadioMenuItem; + private RadioMenuItem placeNutTerritoryRadioMenuItem; + private RadioMenuItem deleteFieldRadioMenuItem; + private Menu territoryMenu; + private ToggleGroup placeGroupTerritoryMenu; + + // robbi Menu + private MenuItem itemPresentMenuItem; + private MenuItem isStockpileMenuItem; + private MenuItem hollowAheadMenuItem; + private MenuItem pileOfScrapAheadMenuItem; + private MenuItem isBagFullMenuItem; + private MenuItem pushPileOfScrapMenuItem; + private MenuItem moveMenuItem; + private MenuItem turnLeftMenuItem; + private MenuItem putMenuItem; + private MenuItem takeMenuItem; + private Menu robbiMenu; + + // simulation Menu + private MenuItem resetMenuItem; + private MenuItem startMenuItem; + private MenuItem pauseMenuItem; + private MenuItem stopMenuItem; + private Menu simulationMenu; + + // examples Menu + private MenuItem loadExampleMenuItem; + private MenuItem saveExampleMenuItem; + private Menu examplesMenu; + + // window Menu + private Menu languageMenu; + private MenuItem englishLanguageMenuItem; + private MenuItem germanLanguageMenuItem; + private CheckMenuItem changeCursorMenuItem; + private CheckMenuItem darkModeMenuItem; + private CheckMenuItem enableSoundsMenuItem; + private MenuItem infoMenuItem; + private MenuItem libraryMenuItem; + private Menu windowMenu; + + // tutor Menu + private Menu tutorMenu; + private MenuItem sendRequestMenuItem; + private MenuItem receiveAnswerMenuItem; + private MenuItem loadRequestMenuItem; + private MenuItem saveAnswerMenuItem; + + /** + * Creates a new MenuBar + */ + public MenuBar() { + createMenuBar(); + getMenus().addAll(editorMenu, territoryMenu, robbiMenu, simulationMenu, examplesMenu, tutorMenu, windowMenu); + } + + /** + * Creates the editor-related menu-bar elements. + */ + private void createEditor() { + logger.debug("Create editor entry for menubar"); + newEditorMenuItem = new MenuItem(); + newEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN)); + newEditorMenuItem.setMnemonicParsing(true); + newEditorMenuItem.setGraphic(new ImageView(MainStage.newImage)); + saveEditorMenuItem = new MenuItem(); + saveEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.S, KeyCombination.CONTROL_DOWN)); + saveEditorMenuItem.setGraphic(new ImageView(MainStage.saveImage)); + openEditorMenuItem = new MenuItem(); + openEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN)); + openEditorMenuItem.setGraphic(new ImageView(MainStage.openImage)); + + formatSourceCodeMenuItem = new MenuItem(); + formatSourceCodeMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN)); // T + // for + // tidy + + compileEditorMenuItem = new MenuItem(); + compileEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.K, KeyCombination.CONTROL_DOWN)); + compileEditorMenuItem.setGraphic(new ImageView(MainStage.compileImage)); + + printEditorMenuItem = new MenuItem(); + printEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.P, KeyCombination.CONTROL_DOWN)); + printEditorMenuItem.setGraphic(new ImageView(MainStage.printImage)); + quitEditorMenuItem = new MenuItem(); + quitEditorMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.Q, KeyCombination.CONTROL_DOWN)); + editorMenu = new Menu("", null, newEditorMenuItem, openEditorMenuItem, saveEditorMenuItem, + new SeparatorMenuItem(), formatSourceCodeMenuItem, compileEditorMenuItem, printEditorMenuItem, + new SeparatorMenuItem(), quitEditorMenuItem); + editorMenu.setMnemonicParsing(true); + } + + /** + * Creates the territory-related menu-bar elements. + */ + private void createTerritory() { + logger.debug("Create territory entry for menubar"); + saveXMLTerritoryMenuItem = new MenuItem(); + saveJAXBTerritoryMenuItem = new MenuItem(); + saveSerialTerritoryMenuItem = new MenuItem(); + + saveTerritoryMenu = new Menu("", null, saveXMLTerritoryMenuItem, saveJAXBTerritoryMenuItem, + saveSerialTerritoryMenuItem); + loadXMLTerritoryMenuItem = new MenuItem(); + loadJAXBTerritoryMenuItem = new MenuItem(); + loadSerialTerritoryMenuItem = new MenuItem(); + loadTerritoryMenu = new Menu("", null, loadXMLTerritoryMenuItem, loadJAXBTerritoryMenuItem, + loadSerialTerritoryMenuItem); + + saveAsPNGMenuItem = new MenuItem(); + saveAsGifMenuItem = new MenuItem(); + saveAsPicMenu = new Menu("", null, saveAsPNGMenuItem, saveAsGifMenuItem); + + printTerritoryMenuItem = new MenuItem(); + changeSizeTerritoryMenuItem = new MenuItem(); + + placeGroupTerritoryMenu = new ToggleGroup(); + + placeRobbiTerritoryRadioMenuItem = new RadioMenuItem(); + placeRobbiTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placeHollowTerritoryRadioMenuItem = new RadioMenuItem(); + placeHollowTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placePileOfScrapTerritoryRadioMenuItem = new RadioMenuItem(); + placePileOfScrapTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placeStockpileTerritoryRadioMenuItem = new RadioMenuItem(); + placeStockpileTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placeAccuTerritoryRadioMenuItem = new RadioMenuItem(); + placeAccuTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placeScrewTerritoryRadioMenuItem = new RadioMenuItem(); + placeScrewTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + placeNutTerritoryRadioMenuItem = new RadioMenuItem(); + placeNutTerritoryRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + deleteFieldRadioMenuItem = new RadioMenuItem(); + deleteFieldRadioMenuItem.setToggleGroup(placeGroupTerritoryMenu); + + territoryMenu = new Menu("", null, saveTerritoryMenu, loadTerritoryMenu, saveAsPicMenu, printTerritoryMenuItem, + changeSizeTerritoryMenuItem, new SeparatorMenuItem(), placeRobbiTerritoryRadioMenuItem, + placeHollowTerritoryRadioMenuItem, placePileOfScrapTerritoryRadioMenuItem, + placeStockpileTerritoryRadioMenuItem, placeAccuTerritoryRadioMenuItem, placeScrewTerritoryRadioMenuItem, + placeNutTerritoryRadioMenuItem, deleteFieldRadioMenuItem); + } + + /** + * Creates the robbi-related menu-bar elements. + */ + private void createRobbi() { + logger.debug("Create Robbi entry for menubar"); + territoryMenu.setMnemonicParsing(true); + itemPresentMenuItem = new MenuItem(); + isStockpileMenuItem = new MenuItem(); + hollowAheadMenuItem = new MenuItem(); + pileOfScrapAheadMenuItem = new MenuItem(); + isBagFullMenuItem = new MenuItem(); + pushPileOfScrapMenuItem = new MenuItem(); + moveMenuItem = new MenuItem(); + moveMenuItem.setAccelerator( + new KeyCodeCombination(KeyCode.V, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); + turnLeftMenuItem = new MenuItem(); + turnLeftMenuItem.setAccelerator( + new KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); + + putMenuItem = new MenuItem(); + putMenuItem.setAccelerator( + new KeyCodeCombination(KeyCode.L, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); + takeMenuItem = new MenuItem(); + takeMenuItem.setAccelerator( + new KeyCodeCombination(KeyCode.N, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)); + robbiMenu = new Menu("", null, moveMenuItem, turnLeftMenuItem, putMenuItem, takeMenuItem, + pushPileOfScrapMenuItem, itemPresentMenuItem, isStockpileMenuItem, hollowAheadMenuItem, + pileOfScrapAheadMenuItem, isBagFullMenuItem); + robbiMenu.setMnemonicParsing(true); + } + + /** + * Creates the simulation-related menu-bar elements. + */ + private void createSimulation() { + logger.debug("Create simulation entry for menubar"); + + resetMenuItem = new MenuItem(); + resetMenuItem.setGraphic(new ImageView(MainStage.resetImage)); + startMenuItem = new MenuItem(); + startMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.F11, KeyCombination.CONTROL_DOWN)); + startMenuItem.setGraphic(new ImageView(MainStage.menuStartImage)); + pauseMenuItem = new MenuItem(); + pauseMenuItem.setGraphic(new ImageView(MainStage.menuPauseImage)); + stopMenuItem = new MenuItem(); + stopMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.F12, KeyCombination.CONTROL_DOWN)); + stopMenuItem.setGraphic(new ImageView(MainStage.menuStopImage)); + simulationMenu = new Menu("", null, resetMenuItem, startMenuItem, pauseMenuItem, stopMenuItem); + simulationMenu.setMnemonicParsing(true); + } + + /** + * Creates the examples-related menu-bar elements + */ + private void createExamplesMenu() { + saveExampleMenuItem = new MenuItem(); + loadExampleMenuItem = new MenuItem(); + examplesMenu = new Menu("", null, saveExampleMenuItem, loadExampleMenuItem); + } + + /** + * Creates the tutor-related menu-bar elements + */ + private void createTutorMenu() { + if (PropertiesLoader.isTutor()) { + loadRequestMenuItem = new MenuItem(); + saveAnswerMenuItem = new MenuItem(); + + tutorMenu = new Menu("", null, loadRequestMenuItem, saveAnswerMenuItem); + } else { + sendRequestMenuItem = new MenuItem(); + receiveAnswerMenuItem = new MenuItem(); + + tutorMenu = new Menu("", null, sendRequestMenuItem, receiveAnswerMenuItem); + } + } + + /** + * Creates the window-related menu-bar elements. + */ + private void createWindowMenu() { + englishLanguageMenuItem = new MenuItem(); + germanLanguageMenuItem = new MenuItem(); + languageMenu = new Menu("", null, englishLanguageMenuItem, germanLanguageMenuItem); + + changeCursorMenuItem = new CheckMenuItem(); + // https://stackoverflow.com/a/49159612/13670629 + darkModeMenuItem = new CheckMenuItem(); + enableSoundsMenuItem = new CheckMenuItem(); + + infoMenuItem = new MenuItem(); + libraryMenuItem = new MenuItem(); + + windowMenu = new Menu("", null, languageMenu, changeCursorMenuItem, darkModeMenuItem, enableSoundsMenuItem, + new SeparatorMenuItem(), infoMenuItem, libraryMenuItem); + } + + /** + * Creates the entire menuBar. + */ + private void createMenuBar() { + logger.debug("Create menubar"); + + createEditor(); + createTerritory(); + createRobbi(); + createSimulation(); + createExamplesMenu(); + createTutorMenu(); + createWindowMenu(); + + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/view/RobbiContextMenu.java b/src/main/java/com/JayPi4c/RobbiSimulator/view/RobbiContextMenu.java index eaaf00b..38b9222 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/view/RobbiContextMenu.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/view/RobbiContextMenu.java @@ -1,201 +1,193 @@ package com.JayPi4c.RobbiSimulator.view; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import com.JayPi4c.RobbiSimulator.controller.MethodHandler; import com.JayPi4c.RobbiSimulator.model.Robbi; import com.JayPi4c.RobbiSimulator.model.Territory; import com.JayPi4c.RobbiSimulator.utils.I18nUtils; import com.JayPi4c.RobbiSimulator.utils.annotations.Default; import com.JayPi4c.RobbiSimulator.utils.annotations.Invisible; +import javafx.scene.control.*; -import javafx.scene.control.ContextMenu; -import javafx.scene.control.CustomMenuItem; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.SeparatorMenuItem; -import javafx.scene.control.Tooltip; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.ArrayList; +import java.util.List; /** * Class to for the ContextMenu which opens, when clicked on robbi in the * simulator. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ public class RobbiContextMenu extends ContextMenu { - private static final String EDITOR_CONTEXTMENU_TOOLTIP = "Editor.contextMenu.tooltip"; - - /** - * Constructor to create a new RobbiContextMenu. It fills itself with all - * methods that are provided by robbi and allows to run a particular method on - * its own. - * - * @param territory the territory this contextMenu is for - * @param parent the parent window in order to display the alerts relative to - * the calling window - */ - public RobbiContextMenu(Territory territory, MainStage parent) { - - for (Method method : getDefaultMethods()) { - MenuItem item = getMenuItem(method); - - // if method needs arguments and no Parameterized Annotation is set -> disable - if (method.getParameterCount() != 0) - item.setDisable(true); - else - // get Annotation parameters - item.setOnAction(new MethodHandler(method, territory, parent)); - - getItems().add(item); - } - - Method[] methods = getCustomMethods(territory.getRobbi()); - if (methods.length > 0) { - getItems().add(new SeparatorMenuItem()); - - for (Method method : methods) { - CustomMenuItem item = getMenuItem(method); - // if method needs arguments and no parameterized Annotation is set -> disable - if (method.getParameterCount() != 0 && !hasCorrectDefaultAnnotations(method)) { - item.setDisable(true); - // https://stackoverflow.com/a/43053529/13670629 - Tooltip tooltip = I18nUtils.createTooltip(EDITOR_CONTEXTMENU_TOOLTIP); - Tooltip.install(item.getContent(), tooltip); - - } else - item.setOnAction(new MethodHandler(method, territory, parent)); - - getItems().add(item); - } - } - - } - - /** - * This method checks if the given method m has the @Default annotation for all - * parameters set. - * - * @param m the method to check for - * @return true if all parameters have the default Annotation, false otherwise - */ - private boolean hasCorrectDefaultAnnotations(Method m) { - if (m.getParameterCount() != m.getAnnotatedParameterTypes().length) - return false; - - for (Parameter parameter : m.getParameters()) { - boolean valid = false; - for (Annotation anno : parameter.getAnnotations()) { - if (anno instanceof Default) { - valid = true; - break; - } - } - if (!valid) - return false; - } - return true; - } - - /** - * Creates the MenuItem for the given Method.
- * MenuItems will look like this:
- * foo(int, int)
- * bar(long = 7, int = 3) - * - * @param m the method to make a menuItem from - * @return a CustomMenuItem with the correct text - */ - private CustomMenuItem getMenuItem(Method m) { - StringBuilder bobTheBuilder = new StringBuilder(); - bobTheBuilder.append(m.getReturnType().toString()); - bobTheBuilder.append(" "); - bobTheBuilder.append(m.getName()); - bobTheBuilder.append("("); - for (Parameter parameter : m.getParameters()) { - bobTheBuilder.append(parameter.getType()); - List annos = Arrays.asList(parameter.getAnnotations()); - for (Annotation anno : annos) - if (anno instanceof Default a) { - bobTheBuilder.append(" = "); - bobTheBuilder.append(a.value()); - } - bobTheBuilder.append(", "); - } - if (m.getParameterCount() > 0) - bobTheBuilder.delete(bobTheBuilder.length() - 2, bobTheBuilder.length()); - bobTheBuilder.append(")"); - return new CustomMenuItem(new Label(bobTheBuilder.toString())); - } - - /** - * Get all methods that are part of the default implementation, that are - * visibile to the user. - * - * @return all methods that are part of the default implementation - */ - private Method[] getDefaultMethods() { - List methods = new ArrayList<>(); - - for (Method m : Robbi.class.getDeclaredMethods()) { - if (Modifier.isPublic(m.getModifiers()) && !isMainMethod(m)) - methods.add(m); - } - return methods.toArray(Method[]::new); - } - - /** - * Get all methods that are implemented by the user and are not part of the - * default implementation of robbi. - * - * @param robbi the Robbi instance to get the custom methods from - * @return all methods that are not part of the default implementation - */ - private Method[] getCustomMethods(Robbi robbi) { - List methods = new ArrayList<>(); - // if robbi is custom class - if (Robbi.class != robbi.getClass()) { - for (Method m : robbi.getClass().getDeclaredMethods()) { - - int modifiers = m.getModifiers(); - - if (!Modifier.isPrivate(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers) - && !isInvisible(m)) - methods.add(m); - } - } - - return methods.toArray(Method[]::new); - } - - /** - * Checks if a method has the invisible annotation. - * - * @param m the method to check for - * @return true if the Invisible annotation is set, false otherwise - */ - private boolean isInvisible(Method m) { - for (Annotation anno : m.getAnnotations()) - if (anno instanceof Invisible) - return true; - return false; - } - - /** - * Checks if the method is the main-Method. - * - * @param m method to check - * @return true if the name of the method equals "main", false otherwise - */ - private boolean isMainMethod(Method m) { - return m.getName().equals("main"); - } + private static final String EDITOR_CONTEXTMENU_TOOLTIP = "Editor.contextMenu.tooltip"; + + /** + * Constructor to create a new RobbiContextMenu. It fills itself with all + * methods that are provided by robbi and allows to run a particular method on + * its own. + * + * @param territory the territory this contextMenu is for + * @param parent the parent window in order to display the alerts relative to + * the calling window + */ + public RobbiContextMenu(Territory territory, MainStage parent) { + + for (Method method : getDefaultMethods()) { + MenuItem item = getMenuItem(method); + + // if method needs arguments and no Parameterized Annotation is set -> disable + if (method.getParameterCount() != 0) + item.setDisable(true); + else + // get Annotation parameters + item.setOnAction(new MethodHandler(method, territory, parent)); + + getItems().add(item); + } + + Method[] methods = getCustomMethods(territory.getRobbi()); + if (methods.length > 0) { + getItems().add(new SeparatorMenuItem()); + + for (Method method : methods) { + CustomMenuItem item = getMenuItem(method); + // if method needs arguments and no parameterized Annotation is set -> disable + if (method.getParameterCount() != 0 && !hasCorrectDefaultAnnotations(method)) { + item.setDisable(true); + // https://stackoverflow.com/a/43053529/13670629 + Tooltip tooltip = I18nUtils.createTooltip(EDITOR_CONTEXTMENU_TOOLTIP); + Tooltip.install(item.getContent(), tooltip); + + } else + item.setOnAction(new MethodHandler(method, territory, parent)); + + getItems().add(item); + } + } + + } + + /** + * This method checks if the given method m has the @Default annotation for all + * parameters set. + * + * @param m the method to check for + * @return true if all parameters have the default Annotation, false otherwise + */ + private boolean hasCorrectDefaultAnnotations(Method m) { + if (m.getParameterCount() != m.getAnnotatedParameterTypes().length) + return false; + + for (Parameter parameter : m.getParameters()) { + boolean valid = false; + for (Annotation anno : parameter.getAnnotations()) { + if (anno instanceof Default) { + valid = true; + break; + } + } + if (!valid) + return false; + } + return true; + } + + /** + * Creates the MenuItem for the given Method.
+ * MenuItems will look like this:
+ * foo(int, int)
+ * bar(long = 7, int = 3) + * + * @param m the method to make a menuItem from + * @return a CustomMenuItem with the correct text + */ + private CustomMenuItem getMenuItem(Method m) { + StringBuilder bobTheBuilder = new StringBuilder(); + bobTheBuilder.append(m.getReturnType()); + bobTheBuilder.append(" "); + bobTheBuilder.append(m.getName()); + bobTheBuilder.append("("); + for (Parameter parameter : m.getParameters()) { + bobTheBuilder.append(parameter.getType()); + Annotation[] annotations = parameter.getAnnotations(); + for (Annotation anno : annotations) + if (anno instanceof Default a) { + bobTheBuilder.append(" = "); + bobTheBuilder.append(a.value()); + } + bobTheBuilder.append(", "); + } + if (m.getParameterCount() > 0) + bobTheBuilder.delete(bobTheBuilder.length() - 2, bobTheBuilder.length()); + bobTheBuilder.append(")"); + return new CustomMenuItem(new Label(bobTheBuilder.toString())); + } + + /** + * Get all methods that are part of the default implementation, that are + * visible to the user. + * + * @return all methods that are part of the default implementation + */ + private Method[] getDefaultMethods() { + List methods = new ArrayList<>(); + + for (Method m : Robbi.class.getDeclaredMethods()) { + if (Modifier.isPublic(m.getModifiers()) && !isMainMethod(m)) + methods.add(m); + } + return methods.toArray(Method[]::new); + } + + /** + * Get all methods that are implemented by the user and are not part of the + * default implementation of robbi. + * + * @param robbi the Robbi instance to get the custom methods from + * @return all methods that are not part of the default implementation + */ + private Method[] getCustomMethods(Robbi robbi) { + List methods = new ArrayList<>(); + // if robbi is custom class + if (Robbi.class != robbi.getClass()) { + for (Method m : robbi.getClass().getDeclaredMethods()) { + + int modifiers = m.getModifiers(); + + if (!Modifier.isPrivate(modifiers) && !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers) + && !isInvisible(m)) + methods.add(m); + } + } + + return methods.toArray(Method[]::new); + } + + /** + * Checks if a method has the invisible annotation. + * + * @param m the method to check for + * @return true if the Invisible annotation is set, false otherwise + */ + private boolean isInvisible(Method m) { + for (Annotation anno : m.getAnnotations()) + if (anno instanceof Invisible) + return true; + return false; + } + + /** + * Checks if the method is the main-Method. + * + * @param m method to check + * @return true if the name of the method equals "main", false otherwise + */ + private boolean isMainMethod(Method m) { + return m.getName().equals("main"); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/view/TerritoryPanel.java b/src/main/java/com/JayPi4c/RobbiSimulator/view/TerritoryPanel.java index cb4f187..f05e430 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/view/TerritoryPanel.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/view/TerritoryPanel.java @@ -2,18 +2,9 @@ import com.JayPi4c.RobbiSimulator.controller.ButtonState; import com.JayPi4c.RobbiSimulator.controller.TerritoryEventHandler; -import com.JayPi4c.RobbiSimulator.model.Accu; -import com.JayPi4c.RobbiSimulator.model.Hollow; -import com.JayPi4c.RobbiSimulator.model.Item; -import com.JayPi4c.RobbiSimulator.model.Nut; -import com.JayPi4c.RobbiSimulator.model.PileOfScrap; -import com.JayPi4c.RobbiSimulator.model.Screw; -import com.JayPi4c.RobbiSimulator.model.Stockpile; -import com.JayPi4c.RobbiSimulator.model.Territory; -import com.JayPi4c.RobbiSimulator.model.Tile; +import com.JayPi4c.RobbiSimulator.model.*; import com.JayPi4c.RobbiSimulator.utils.Observable; import com.JayPi4c.RobbiSimulator.utils.Observer; - import javafx.application.Platform; import javafx.geometry.Bounds; import javafx.scene.canvas.Canvas; @@ -23,273 +14,267 @@ import lombok.extern.slf4j.Slf4j; /** - * * This class draws the territory on a panel to allow interacting with the * graphical interface. - * - * @author Jonas Pohl * + * @author Jonas Pohl */ @Slf4j public class TerritoryPanel extends Canvas implements Observer { - private Territory territory; - - private static final Image[] tileImages = new Image[4]; - private static final Image[] itemImages = new Image[3]; - private static final Image robbiImage; - - private static final int TILE = 0; - private static final int STOCKPILE = 1; - private static final int HOLLOW = 2; - private static final int PILEOFSCRAP = 3; - private static final int NUT = 0; - private static final int SCREW = 1; - private static final int ACCU = 2; - - private static final int CELLSIZE = 32; - private static final int CELLSPACER = 1; - - // store current bounds to allow centering on updated territory size - private Bounds bounds; - - /** - * loading territory images - */ - static { - - logger.debug("Loading territory images"); - - robbiImage = new Image(String.valueOf(MainStage.class.getResource("/img/0Robbi32.png"))); - - tileImages[TILE] = new Image(String.valueOf(MainStage.class.getResource("/img/Tile32.png"))); - tileImages[STOCKPILE] = new Image(String.valueOf(MainStage.class.getResource("/img/Stockpile32.png"))); - tileImages[HOLLOW] = new Image(String.valueOf(MainStage.class.getResource("/img/Hollow32.png"))); - tileImages[PILEOFSCRAP] = new Image(String.valueOf(MainStage.class.getResource("/img/PileOfScrap32.png"))); - - itemImages[NUT] = new Image(String.valueOf(MainStage.class.getResource("/img/Nut32.png"))); - itemImages[SCREW] = new Image(String.valueOf(MainStage.class.getResource("/img/Screw32.png"))); - itemImages[ACCU] = new Image(String.valueOf(MainStage.class.getResource("/img/Accu32.png"))); - } - - /** - * Constructor to create a new territory panel for the given territory. - * - * @param territory the territory this panel is for - * @param buttonState the buttonState to be able to create a - * TerritoryEventHandler - * @param parent the parent Window to show alerts relative to the calling - * window - */ - public TerritoryPanel(Territory territory, ButtonState buttonState, MainStage parent) { - this.territory = territory; - this.territory.addObserver(this); - - TerritoryEventHandler eventHandler = new TerritoryEventHandler(territory, this, buttonState, parent); - this.setOnMousePressed(eventHandler); - this.setOnMouseDragged(eventHandler); - this.setOnMouseReleased(eventHandler); - - drawPanel(); - } - - /** - * Getter for the CELLSIZE. - * - * @return CELLSIZE value - */ - public static int getCellsize() { - return CELLSIZE; - } - - /** - * Getter for the CELLSPACER. - * - * @return CELLSPACER value - */ - public static int getCellspacer() { - return CELLSPACER; - } - - /** - * updates the size of the territory if the size has changed. Paints the - * territory afterwards. - */ - private void drawPanel() { - if (getWidth() != getTerritoryWidth()) - setWidth(getTerritoryWidth()); - if (getHeight() != getTerritoryHeight()) - setHeight(getTerritoryHeight()); - paintTerritory(); - - } - - /** - * Getter for the territory width. - * - * @return the width of the territory, calculated by number of cols, Cellsize - * and cellspacer - */ - private int getTerritoryWidth() { - return (territory.getNumCols()) * (CELLSIZE + CELLSPACER); - } - - /** - * Getter for the territory height. - * - * @return the height of the territory, calculated by number of rows, Cellsize - * and cellspacer - */ - private int getTerritoryHeight() { - return (territory.getNumRows()) * (CELLSIZE + CELLSPACER); - } - - /** - * Paint all graphics for the territory and the robbi on the GUI. - */ - private void paintTerritory() { - - GraphicsContext gc = getGraphicsContext2D(); - for (int i = 0; i < territory.getNumCols(); i++) { - - for (int j = 0; j < territory.getNumRows(); j++) { - Tile t = territory.getTile(i, j); - gc.drawImage(tileImages[TILE], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - if (t instanceof Hollow) { - gc.drawImage(tileImages[HOLLOW], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - - } else if (t instanceof PileOfScrap) { - gc.drawImage(tileImages[PILEOFSCRAP], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - } else if (t instanceof Stockpile stockpile) { - gc.drawImage(tileImages[STOCKPILE], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - boolean nutDrawn = false; - boolean accuDrawn = false; - boolean screwDrawn = false; - for (Item item : stockpile.getAllItems()) { - if (!nutDrawn && item instanceof Nut) { - gc.drawImage(itemImages[NUT], getPos(i) + CELLSIZE / 2d, getPos(j), CELLSIZE / 2d, - CELLSIZE / 2d); - nutDrawn = true; - } else if (!accuDrawn && item instanceof Accu) { - gc.drawImage(itemImages[ACCU], getPos(i), getPos(j), CELLSIZE / 2d, CELLSIZE / 2d); - accuDrawn = true; - } else if (!screwDrawn && item instanceof Screw) { - gc.drawImage(itemImages[SCREW], getPos(i) + CELLSIZE / 3d, getPos(j) + CELLSIZE / 2d, - CELLSIZE / 2d, CELLSIZE / 2d); - screwDrawn = true; - } - if (nutDrawn && accuDrawn && screwDrawn) - break; - } - } - if (!(t instanceof Stockpile)) { - Item item = t.getItem(); - if (item instanceof Nut) { - gc.drawImage(itemImages[NUT], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - } else if (item instanceof Screw) { - gc.drawImage(itemImages[SCREW], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - } else if (item instanceof Accu) { - gc.drawImage(itemImages[ACCU], getPos(i), getPos(j), CELLSIZE, CELLSIZE); - } - - } - } - } - - double angle = switch (territory.getRobbiDirection()) { - case NORTH: - yield 270; - case WEST: - yield 180; - case SOUTH: - yield 90; - case EAST: - default: - yield 0; - }; - drawRotatedImage(gc, robbiImage, angle, (double) territory.getRobbiX() * (CELLSIZE + CELLSPACER) + CELLSPACER, - (double) territory.getRobbiY() * (CELLSIZE + CELLSPACER) + CELLSPACER, CELLSIZE, CELLSIZE); - } - - /** - * Sets the transform for the GraphicsContext to rotate around a pivot point. - * - * @param gc the graphics context the transform to applied to. - * @param angle the angle of rotation. - * @param px the x pivot co-ordinate for the rotation (in canvas - * co-ordinates). - * @param py the y pivot co-ordinate for the rotation (in canvas - * co-ordinates). - * @see Stackoverflow - */ - private void rotate(GraphicsContext gc, double angle, double px, double py) { - Rotate r = new Rotate(angle, px, py); - gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy()); - } - - /** - * Draws an image on a graphics context. - * - * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point: - * (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2) - * - * @param gc the graphics context the image is to be drawn on. - * @param angle the angle of rotation. - * @param tlpx the top left x co-ordinate where the image will be plotted (in - * canvas co-ordinates). - * @param tlpy the top left y co-ordinate where the image will be plotted (in - * canvas co-ordinates). - * @see Stackoverflow - */ - private void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy, double w, - double h) { - gc.save(); // saves the current state on stack, including the current transform - rotate(gc, angle, tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2); - gc.drawImage(image, tlpx, tlpy, w, h); - gc.restore(); // back to original state (before rotation) - } - - private int getPos(int val) { - return (val) * (CELLSIZE + CELLSPACER) + CELLSPACER; - } - - /** - * taken from Dibo
- * Centers the territory-panel in the center of the viewPortBounds. - * - * @param vpb The bounds in which the territory has to be centered - */ - public void center(Bounds vpb) { - this.bounds = vpb; - double w = vpb.getWidth(); - double h = vpb.getHeight(); - if (w > getTerritoryWidth()) { - setTranslateX((w - getTerritoryWidth()) / 2); - } else - setTranslateX(0); - if (h > getTerritoryHeight()) { - setTranslateY((h - getTerritoryHeight()) / 2); - } else - setTranslateY(0); - } - - @Override - public void update(Observable observable) { - Platform.runLater(this::update); - } - - /** - * Centers the territory if the size has changed. Afterwards, it draws the - * territorypanel. - */ - public void update() { - if (territory.hasSizeChanged()) { - center(bounds); - territory.setSizeChanged(false); - } - drawPanel(); - } + private final Territory territory; + + private static final Image[] tileImages = new Image[4]; + private static final Image[] itemImages = new Image[3]; + private static final Image robbiImage; + + private static final int TILE = 0; + private static final int STOCKPILE = 1; + private static final int HOLLOW = 2; + private static final int PILEOFSCRAP = 3; + private static final int NUT = 0; + private static final int SCREW = 1; + private static final int ACCU = 2; + + private static final int CELLSIZE = 32; + private static final int CELLSPACER = 1; + + // store current bounds to allow centering on updated territory size + private Bounds bounds; + + static { + + logger.debug("Loading territory images"); + + robbiImage = new Image(String.valueOf(MainStage.class.getResource("/img/0Robbi32.png"))); + + tileImages[TILE] = new Image(String.valueOf(MainStage.class.getResource("/img/Tile32.png"))); + tileImages[STOCKPILE] = new Image(String.valueOf(MainStage.class.getResource("/img/Stockpile32.png"))); + tileImages[HOLLOW] = new Image(String.valueOf(MainStage.class.getResource("/img/Hollow32.png"))); + tileImages[PILEOFSCRAP] = new Image(String.valueOf(MainStage.class.getResource("/img/PileOfScrap32.png"))); + + itemImages[NUT] = new Image(String.valueOf(MainStage.class.getResource("/img/Nut32.png"))); + itemImages[SCREW] = new Image(String.valueOf(MainStage.class.getResource("/img/Screw32.png"))); + itemImages[ACCU] = new Image(String.valueOf(MainStage.class.getResource("/img/Accu32.png"))); + } + + /** + * Constructor to create a new territory panel for the given territory. + * + * @param territory the territory this panel is for + * @param buttonState the buttonState to be able to create a + * TerritoryEventHandler + * @param parent the parent Window to show alerts relative to the calling + * window + */ + public TerritoryPanel(Territory territory, ButtonState buttonState, MainStage parent) { + this.territory = territory; + this.territory.addObserver(this); + + TerritoryEventHandler eventHandler = new TerritoryEventHandler(territory, this, buttonState, parent); + this.setOnMousePressed(eventHandler); + this.setOnMouseDragged(eventHandler); + this.setOnMouseReleased(eventHandler); + + drawPanel(); + } + + /** + * Getter for the CELLSIZE. + * + * @return CELLSIZE value + */ + public static int getCellsize() { + return CELLSIZE; + } + + /** + * Getter for the CELLSPACER. + * + * @return CELLSPACER value + */ + public static int getCellspacer() { + return CELLSPACER; + } + + /** + * updates the size of the territory if the size has changed. Paints the + * territory afterward. + */ + private void drawPanel() { + if (getWidth() != getTerritoryWidth()) + setWidth(getTerritoryWidth()); + if (getHeight() != getTerritoryHeight()) + setHeight(getTerritoryHeight()); + paintTerritory(); + + } + + /** + * Getter for the territory width. + * + * @return the width of the territory, calculated by number of cols, Cell-size + * and cell-spacer + */ + private int getTerritoryWidth() { + return (territory.getNumCols()) * (CELLSIZE + CELLSPACER); + } + + /** + * Getter for the territory height. + * + * @return the height of the territory, calculated by number of rows, Cellsize + * and cellspacer + */ + private int getTerritoryHeight() { + return (territory.getNumRows()) * (CELLSIZE + CELLSPACER); + } + + /** + * Paint all graphics for the territory and the robbi on the GUI. + */ + private void paintTerritory() { + + GraphicsContext gc = getGraphicsContext2D(); + for (int i = 0; i < territory.getNumCols(); i++) { + + for (int j = 0; j < territory.getNumRows(); j++) { + Tile t = territory.getTile(i, j); + gc.drawImage(tileImages[TILE], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + if (t instanceof Hollow) { + gc.drawImage(tileImages[HOLLOW], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + + } else if (t instanceof PileOfScrap) { + gc.drawImage(tileImages[PILEOFSCRAP], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + } else if (t instanceof Stockpile stockpile) { + gc.drawImage(tileImages[STOCKPILE], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + boolean nutDrawn = false; + boolean accuDrawn = false; + boolean screwDrawn = false; + for (Item item : stockpile.getAllItems()) { + if (!nutDrawn && item instanceof Nut) { + gc.drawImage(itemImages[NUT], getPos(i) + CELLSIZE / 2d, getPos(j), CELLSIZE / 2d, + CELLSIZE / 2d); + nutDrawn = true; + } else if (!accuDrawn && item instanceof Accu) { + gc.drawImage(itemImages[ACCU], getPos(i), getPos(j), CELLSIZE / 2d, CELLSIZE / 2d); + accuDrawn = true; + } else if (!screwDrawn && item instanceof Screw) { + gc.drawImage(itemImages[SCREW], getPos(i) + CELLSIZE / 3d, getPos(j) + CELLSIZE / 2d, + CELLSIZE / 2d, CELLSIZE / 2d); + screwDrawn = true; + } + if (nutDrawn && accuDrawn && screwDrawn) + break; + } + } + if (!(t instanceof Stockpile)) { + Item item = t.getItem(); + if (item instanceof Nut) { + gc.drawImage(itemImages[NUT], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + } else if (item instanceof Screw) { + gc.drawImage(itemImages[SCREW], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + } else if (item instanceof Accu) { + gc.drawImage(itemImages[ACCU], getPos(i), getPos(j), CELLSIZE, CELLSIZE); + } + + } + } + } + + double angle = switch (territory.getRobbiDirection()) { + case NORTH: + yield 270; + case WEST: + yield 180; + case SOUTH: + yield 90; + case EAST: + yield 0; + }; + drawRotatedImage(gc, robbiImage, angle, (double) territory.getRobbiX() * (CELLSIZE + CELLSPACER) + CELLSPACER, + (double) territory.getRobbiY() * (CELLSIZE + CELLSPACER) + CELLSPACER, CELLSIZE, CELLSIZE); + } + + /** + * Sets the transform for the GraphicsContext to rotate around a pivot point. + * + * @param gc the graphics context the transform to applied to. + * @param angle the angle of rotation. + * @param px the x pivot co-ordinate for the rotation (in canvas + * co-ordinates). + * @param py the y pivot co-ordinate for the rotation (in canvas + * co-ordinates). + * @see Stackoverflow + */ + private void rotate(GraphicsContext gc, double angle, double px, double py) { + Rotate r = new Rotate(angle, px, py); + gc.setTransform(r.getMxx(), r.getMyx(), r.getMxy(), r.getMyy(), r.getTx(), r.getTy()); + } + + /** + * Draws an image on a graphics context. + *

+ * The image is drawn at (tlpx, tlpy) rotated by angle pivoted around the point: + * (tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2) + * + * @param gc the graphics context the image is to be drawn on. + * @param angle the angle of rotation. + * @param tlpx the top left x co-ordinate where the image will be plotted (in + * canvas co-ordinates). + * @param tlpy the top left y co-ordinate where the image will be plotted (in + * canvas co-ordinates). + * @see Stackoverflow + */ + private void drawRotatedImage(GraphicsContext gc, Image image, double angle, double tlpx, double tlpy, double w, + double h) { + gc.save(); // saves the current state on stack, including the current transform + rotate(gc, angle, tlpx + image.getWidth() / 2, tlpy + image.getHeight() / 2); + gc.drawImage(image, tlpx, tlpy, w, h); + gc.restore(); // back to original state (before rotation) + } + + private int getPos(int val) { + return (val) * (CELLSIZE + CELLSPACER) + CELLSPACER; + } + + /** + * taken from Dibo
+ * Centers the territory-panel in the center of the viewPortBounds. + * + * @param vpb The bounds in which the territory has to be centered + */ + public void center(Bounds vpb) { + this.bounds = vpb; + double w = vpb.getWidth(); + double h = vpb.getHeight(); + if (w > getTerritoryWidth()) { + setTranslateX((w - getTerritoryWidth()) / 2); + } else + setTranslateX(0); + if (h > getTerritoryHeight()) { + setTranslateY((h - getTerritoryHeight()) / 2); + } else + setTranslateY(0); + } + + @Override + public void update(Observable observable) { + Platform.runLater(this::update); + } + + /** + * Centers the territory if the size has changed. Afterward, it draws the + * territory-panel. + */ + public void update() { + if (territory.hasSizeChanged()) { + center(bounds); + territory.setSizeChanged(false); + } + drawPanel(); + } } diff --git a/src/main/java/com/JayPi4c/RobbiSimulator/view/Toolbar.java b/src/main/java/com/JayPi4c/RobbiSimulator/view/Toolbar.java index fc18752..838a801 100644 --- a/src/main/java/com/JayPi4c/RobbiSimulator/view/Toolbar.java +++ b/src/main/java/com/JayPi4c/RobbiSimulator/view/Toolbar.java @@ -22,8 +22,8 @@ public class Toolbar extends ToolBar { * Constant for the maximum value for the speed slider. */ public static final int MAX_SPEED_VALUE = 10; - private MenuBar menubar; - // Tool bar + private final MenuBar menubar; + // Toolbar private Button newButtonToolbar; private Button loadButtonToolbar; private Button saveButtonToolbar; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index ee476db..1eb5585 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -22,8 +22,11 @@ requires org.apache.derby.tools; opens com.JayPi4c.RobbiSimulator.controller.examples to org.hibernate.orm.core; + opens com.JayPi4c.RobbiSimulator.model to jakarta.xml.bind; exports com.JayPi4c.RobbiSimulator.utils.annotations; exports com.JayPi4c.RobbiSimulator.model; exports com.JayPi4c.RobbiSimulator; + + exports com.JayPi4c.RobbiSimulator.controller.tutor to java.rmi; } \ No newline at end of file diff --git a/src/main/resources/css/dark-theme.css b/src/main/resources/css/dark-theme.css index c5f6a3c..262f9b9 100644 --- a/src/main/resources/css/dark-theme.css +++ b/src/main/resources/css/dark-theme.css @@ -1,3 +1,4 @@ +/* Taken from stack overflow: https://stackoverflow.com/a/49159612 */ .root { -fx-base: #3f474f; -fx-accent: #e7eff7; @@ -5,18 +6,18 @@ -fx-focus-color: #efefef; -fx-faint-focus-color: #efefef22; -fx-focused-text-base-color: ladder(-fx-selection-bar, - -fx-light-text-color 45%, - -fx-dark-text-color 46%, - -fx-dark-text-color 59%, - -fx-mid-text-color 60%); + -fx-light-text-color 45%, + -fx-dark-text-color 46%, + -fx-dark-text-color 59%, + -fx-mid-text-color 60%); -fx-focused-mark-color: -fx-focused-text-base-color; } .text-input:focused { -fx-highlight-text-fill: ladder(-fx-highlight-fill, - -fx-light-text-color 45%, - -fx-dark-text-color 46%, - -fx-dark-text-color 59%, - -fx-mid-text-color 60%); + -fx-light-text-color 45%, + -fx-dark-text-color 46%, + -fx-dark-text-color 59%, + -fx-mid-text-color 60%); } \ No newline at end of file diff --git a/src/main/resources/lang/messages_de_DE.properties b/src/main/resources/lang/messages_de_DE.properties index 7e0238d..f8ae153 100644 --- a/src/main/resources/lang/messages_de_DE.properties +++ b/src/main/resources/lang/messages_de_DE.properties @@ -1,15 +1,15 @@ ChangeSize.dialog.cols=Spalten: -ChangeSize.dialog.header=Bitte w\u00E4hle eine neue Gr\u00F6\u00DFe +ChangeSize.dialog.header=Bitte wähle eine neue Größe ChangeSize.dialog.rows=Reihen: -ChangeSize.dialog.title=Gr\u00F6\u00DFe \u00E4ndern +ChangeSize.dialog.title=Größe ändern Compilation.annotations.header=Annotationen fehlerhaft Compilation.annotations.msg.default=Aufgrund fehlerhafter Annotationen konnte Robbi nicht in das Territorium geladen werden. -Compilation.annotations.msg.info="%s" ist nicht anwendbar f\u00FCr den Typ "%s". +Compilation.annotations.msg.info="%s" ist nicht anwendbar für den Typ "%s". Compilation.annotations.title=Annotationenfehler Compilation.diagnostic=Kompilierungsfehler Compilation.diagnostic.CodeAndMessage=Code und Nachricht: %s: %s%n Compilation.diagnostic.kind=Art: %s%n -Compilation.diagnostic.override=Robbi \u00FCberschreibt nicht die main-Methode. +Compilation.diagnostic.override=Robbi überschreibt nicht die main-Methode. Compilation.diagnostic.row=Zeile: %s%n Compilation.diagnostic.source=Quelle: %s%n Compilation.diagnostic.title=Kompilierung Fehlgeschlagen @@ -19,22 +19,22 @@ Compilation.success.title=Erfolg Editor.contextMenu.executionError=Die @Default Annotation hat einen falschen String ('%s') in der Methode '%s'. Editor.contextMenu.tooltip=Bitte nutze die @Default Annotation. Examples.duplication.header=Es existiert bereits ein Programm mit dem Namen des Beispiels. -Examples.duplication.message=Altes Programm umbennen?\n(Das alte Programm wird sonst \u00FCberschrieben.) +Examples.duplication.message=Altes Programm umbennen?\n(Das alte Programm wird sonst überschrieben.) Examples.duplication.title=Namenduplikat -Examples.load.dialog.program.header=W\u00E4hle ein Programm aus. +Examples.load.dialog.program.header=Wähle ein Programm aus. Examples.load.dialog.program.name=Programm Examples.load.dialog.program.title=Programmauswahl Examples.load.dialog.tags.fail=Es konnten keine Tags in der Datenbank gefunden werden. -Examples.load.dialog.tags.header=W\u00E4hle einen Tag f\u00FCr ein Beispiel. +Examples.load.dialog.tags.header=Wähle einen Tag für ein Beispiel. Examples.load.dialog.tags.name=Tag Examples.load.dialog.tags.title=Tagauswahl Examples.save.tags.header=Gebe leerzeichengetrennt Tags ein. Examples.save.tags.name=Tags -Examples.save.tags.prompt=Tags f\u00FCr das Beispiel +Examples.save.tags.prompt=Tags für das Beispiel Examples.save.tags.title=Tageingabe Exception.BagIsEmpty=Ooops! Robbi kann kein Item ablegen. Die Tasche ist leer. Exception.BagIsFull=Ooops! Robbi kann kein Item aufnehmen. Seine Tasche ist voll. -Exception.HollowAhead=Ooops! Robbi kann nicht vorw\u00E4rts gehen. Es ist eine Kuhle voraus. +Exception.HollowAhead=Ooops! Robbi kann nicht vorwärts gehen. Es ist eine Kuhle voraus. Exception.NoItem=Ooops! Hier liegt kein Item, welches Robbi aufheben kann. Exception.NoPileOfScrapAhead=Ooops! Robbi Kann keinen Schrotthaufen zum Schieben finden. Exception.TileBlocked=Ooops! Robbi kann diesen Schrotthaufen nicht schieben. Die folgende Kachel ist blockiert. @@ -43,7 +43,7 @@ Execution.information.bag=Tasche voll: {0} Execution.information.hollow=Kuhle voraus: {0} Execution.information.itemPresent=Gegenstand da: {0} Execution.information.pileOfScrap=Schrotthaufen voraus: {0} -Execution.information.result=Das Ergebnis des Aufrufs ist: +Execution.information.result=Das Ergebnis des Aufrufs ist: Execution.information.stockpile=Lager da: {0} Init.error.header=Initialisierungsfehler Init.error.message=Der Program Controller konnte nicht initialisiert werden. @@ -53,7 +53,7 @@ Menu.editor=_Editor Menu.editor.compile=_Kompilieren Menu.editor.format=formatieren Menu.editor.new=_Neu -Menu.editor.open=_\u00D6ffnen +Menu.editor.open=_Öffnen Menu.editor.print=_Drucken Menu.editor.quit=_Beenden Menu.editor.save=_Speichern @@ -73,7 +73,7 @@ Menu.robbi.take=nehme auf Menu.robbi.turnLeft=links um Menu.simulation=_Simulation Menu.simulation.pause=Pause -Menu.simulation.reset=Zur\u00FCcksetzten +Menu.simulation.reset=Zurücksetzten Menu.simulation.start=Start/Fortsetzen Menu.simulation.stop=Stopp Menu.territory=_Territorium @@ -101,7 +101,7 @@ Menu.territory.saveAsPic.gif=Als GIF speichern Menu.territory.saveAsPic.png=Als PNG speichern Menu.territory.saveAsPic.png.descripion=png-Bilddateien Menu.territory.saveAsPic.png.extension=png -Menu.territory.size=_Gr\u00F6\u00DFe \u00E4ndern... +Menu.territory.size=_Größe ändern... Menu.tutor=Tutor Menu.tutor.loadRequest=Anfrage laden Menu.tutor.loadRequest.success=Anfrage #{0} erfolgreich geladen. @@ -117,7 +117,7 @@ Menu.tutor.sendRequest.information=Die Anfrage wurde verschickt. Menu.window=Fenster Menu.window.changeCursor=Angepasster Cursor Menu.window.darkmode=Dunkelmodus -Menu.window.enableSounds=T\u00F6ne aktivieren +Menu.window.enableSounds=Töne aktivieren Menu.window.info=Info Menu.window.info.content=Dieses Program wurde geschrieben von JayPi4c.\nDer Robbi-Simulator ist inspiriert an dem Hamster-Simulator von Dibo. Menu.window.info.header=Informationen zum Robbi-Simulator @@ -134,7 +134,7 @@ New.dialog.name=Name: New.dialog.prompt=Dateiname New.dialog.title=Neue Datei Open.dialog.filter=Java Dateien -Open.dialog.title=Program \u00F6ffnen +Open.dialog.title=Program öffnen Territory.load.dialog.filter.deserial=Serialisierungsdateien Territory.load.dialog.filter.jaxb=JAXB-Dateien Territory.load.dialog.filter.xml=XML-Dateien @@ -146,13 +146,13 @@ Territory.save.dialog.filter.xml=XML-Dateien Territory.save.dialog.title=Territorium speichern Territory.xml.error.dtd=Die dtd Datei konnte nicht geladen werden. Toolbar.action.pause=Pausiert die Simulation -Toolbar.action.reset=Zur\u00FCcksetzten +Toolbar.action.reset=Zurücksetzten Toolbar.action.speed=Stelle die Simulationsgeschwindigkeit ein Toolbar.action.start=Starte die Simulation Toolbar.action.stop=Stoppt die Simulation Toolbar.control.compile=Kompiliere den aktuellen Code -Toolbar.control.load=\u00D6ffne einen gespeicherten Simulator -Toolbar.control.new=\u00D6ffne einen neuen Simulator +Toolbar.control.load=Öffne einen gespeicherten Simulator +Toolbar.control.new=Öffne einen neuen Simulator Toolbar.control.save=Speichere den aktuellen Simulator Toolbar.robbi.move=Bewege Robbi ein Feld in Blickrichtung Toolbar.robbi.put=Lege den Gegenstand aus der Tasche auf der Kachel ab @@ -166,8 +166,8 @@ Toolbar.territory.placePileOfScrap=Platziere einen Schrotthaufen auf dem Schrott Toolbar.territory.placeRobbi=Platziere Robbi auf dem Schrottplatz Toolbar.territory.placeScrew=Platziere eine Schraube auf dem Schrottplatz Toolbar.territory.placeStockpile=Platziere ein Lager auf dem Schrottplatz -Toolbar.territory.size=Konfiguriere die Gr\u00F6\u00DFe des Territoriums -language.changed=Sprache ge\u00E4ndert! +Toolbar.territory.size=Konfiguriere die Größe des Territoriums +language.changed=Sprache geändert! not.implemented=Noch nicht implementiert! Snackbar.message.startup=Erfolgreich gestartet! Snackbar.message.compile.success=Kompilierung erfolgreich!