diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/PathsSingleton.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/PathsSingleton.java index 1c98afb3100fed235f8265f4132a6f4918cab934..9946f5eb6901098847ad10f86195f520b032559c 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/PathsSingleton.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/PathsSingleton.java @@ -3,6 +3,7 @@ package edu.ntnu.idatt2001.group_30.paths; import edu.ntnu.idatt2001.group_30.paths.model.Player; import edu.ntnu.idatt2001.group_30.paths.model.Story; import edu.ntnu.idatt2001.group_30.paths.model.goals.*; +import java.io.File; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -20,6 +21,7 @@ public enum PathsSingleton { INSTANCE; private Story story; + private File storyFile; private Player player = new Player("Default", 100, 100, 100); private boolean passageMoving = false; private HealthGoal healthGoal; @@ -44,18 +46,52 @@ public enum PathsSingleton { this.story = story; } + /** + * This method retrieves the file to the story. + * @return The file of the story, given as a File object. + */ + public File getStoryFile() { + return storyFile; + } + + /** + * This method changes the file of the story. + * @param storyFile New file, given as a File object. + */ + public void setStoryFile(File storyFile) { + this.storyFile = storyFile; + } + + /** + * This method retrieves the player. + * @return Current player of game, given as a Player object. + */ public Player getPlayer() { return player; } + /** + * This method sets the player to a new player. + * @param player New player, given as a Player object. + */ public void setPlayer(Player player) { this.player = player; } + /** + * This method allows a goal to be changed, given the goal type. + * @param newGoal New goal, given as a Goal implemented Object + */ public void changeGoal(Goal<?> newGoal) { setGoal(GoalType.getGoalType(newGoal.getClass().getSimpleName()), newGoal); } + /** + * This method sets a given goal to a new goal by the goal type. + * @param goalType Type of goal, given as a GoalType enum. + * @param goal New goal, given as a Goal object. + * @param <T> The type of Goal. + */ public <T> void setGoal(GoalType goalType, Goal<?> goal) { switch (goalType) { case HEALTH_GOAL -> healthGoal = (HealthGoal) goal; @@ -66,22 +102,44 @@ public enum PathsSingleton { } } + /** + * This method retrieves the health goal. + * @return Health goal, given as a HealthGoal object. + */ public HealthGoal getHealthGoal() { return healthGoal; } + /** + * This method retrieves the score goal. + * @return Score goal, given as a ScoreGoal object. + */ public ScoreGoal getScoreGoal() { return scoreGoal; } + /** + * This method retrieves the inventory goal. + * @return Inventory goal, given as a InventoryGoal object. + */ public InventoryGoal getInventoryGoal() { return inventoryGoal; } + /** + * This method retrieves the gold goal. + * @return Gold goal, given as a GoldGoal object. + */ public GoldGoal getGoldGoal() { return goldGoal; } + /** + * This method gets a goal variable given the GoalType. + * @param goalType Type of goal, given as a GoalType enum. + * @return The goal variable. + * @param <T> Type of goal. + */ public <T> Goal<?> getGoal(GoalType goalType) { return switch (goalType) { case HEALTH_GOAL -> healthGoal; @@ -91,10 +149,18 @@ public enum PathsSingleton { }; } + /** + * This method retrieves the character load out image. + * @return Image of the character created, given as an ImageView object. + */ public ImageView getCharacterImageView() { return characterImageView; } + /** + * This method sets the character load out. + * @param characterImageView New character image, given as an ImageView object. + */ public void setCharacterImageView(ImageView characterImageView) { this.characterImageView = characterImageView; } @@ -103,8 +169,8 @@ public enum PathsSingleton { * Returns a list of all the non-null goals. * @return A list of all the non-null goals, given as a List of Goal objects. */ - public List<Goal> getGoals() { - List<Goal> goals = Stream + public List<Goal<?>> getGoals() { + List<Goal<?>> goals = Stream .of(healthGoal, scoreGoal, goldGoal) .filter(Objects::nonNull) .collect(Collectors.toList()); diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/Controller.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/Controller.java index 4a62d0acd5453a9fbbda8ba8aa3494761a393c77..7ea189bd035cc0f2fbf24cb3cc0f00c9598b8957 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/Controller.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/Controller.java @@ -21,6 +21,10 @@ public class Controller { protected final StageManager STAGE_MANAGER = StageManager.getInstance(); protected final Map<Class<? extends View<?>>, Runnable> availableViews = new HashMap<>(); + /** + * Creates a new Controller with the given view classes. + * @param viewClasses The view classes that this controller is responsible for. + */ @SafeVarargs public Controller(Class<? extends View<?>>... viewClasses) { for (Class<? extends View<?>> viewClass : viewClasses) { @@ -53,10 +57,17 @@ public class Controller { return actionEvent -> STAGE_MANAGER.goBackTo(viewClass); } + /** + * This method is used to get the root stage of the application. + * @return The root stage of the application, which is the stage that is used to display the views. + */ public Stage getRootStage() { return STAGE_MANAGER.getStage(); } + /** + * This method is used to go to the home view. + */ public void goToHome() { STAGE_MANAGER.setCurrentView(ViewFactory.createView(HomeView.class)); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/CreatePlayerController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/CreatePlayerController.java index 01c52afc3b17a81c271d52b77ff23a99784b43b8..e197403d78fe5133cf606840d8e82b49f0d910b2 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/CreatePlayerController.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/CreatePlayerController.java @@ -1,10 +1,18 @@ package edu.ntnu.idatt2001.group_30.paths.controller; -import edu.ntnu.idatt2001.group_30.paths.view.views.NewGameView; +import edu.ntnu.idatt2001.group_30.paths.view.views.LoadGameView; +/** + * The class CreatePlayerController is responsible for managing the CreatePlayerView. + * + * @author Trym Hamer Gudvangen + */ public class CreatePlayerController extends Controller { + /** + * Creates a new CreatePlayerController. + */ public CreatePlayerController() { - super(NewGameView.class); + super(LoadGameView.class); } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HelpController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HelpController.java index 71d54a3c1d9e2db538ed3100a82b83a00b10278d..e2019fdca619ac953be249ef30894d5c21a025f1 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HelpController.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HelpController.java @@ -9,6 +9,9 @@ import edu.ntnu.idatt2001.group_30.paths.view.views.HomeView; */ public class HelpController extends Controller { + /** + * Creates a new HelpController. + */ public HelpController() { super(HomeView.class); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HomeController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HomeController.java index d3090acb250e365cfea8c71a85cb03b675af5d05..6753105984aed797a257c8a781bf4a4921878ba7 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HomeController.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/HomeController.java @@ -2,7 +2,7 @@ package edu.ntnu.idatt2001.group_30.paths.controller; import edu.ntnu.idatt2001.group_30.paths.view.views.CreatePlayerView; import edu.ntnu.idatt2001.group_30.paths.view.views.HelpView; -import edu.ntnu.idatt2001.group_30.paths.view.views.NewGameView; +import edu.ntnu.idatt2001.group_30.paths.view.views.LoadGameView; import edu.ntnu.idatt2001.group_30.paths.view.views.PlaythroughView; /** @@ -16,7 +16,7 @@ public class HomeController extends Controller { * Creates a new HomeController. */ public HomeController() { - super(HelpView.class, NewGameView.class, CreatePlayerView.class, PlaythroughView.class); + super(HelpView.class, LoadGameView.class, CreatePlayerView.class, PlaythroughView.class); } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java index fdd7934a5d125d1057255744eb36d2131cf4521b..7df50729abee2e0e5a6c06f3e6cb6ae0be566104 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewGameController.java @@ -3,20 +3,34 @@ package edu.ntnu.idatt2001.group_30.paths.controller; import static edu.ntnu.idatt2001.group_30.paths.PathsSingleton.INSTANCE; import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileReader; +import edu.ntnu.idatt2001.group_30.paths.view.views.NewStoryView; import edu.ntnu.idatt2001.group_30.paths.view.views.PlaythroughView; import java.io.File; import java.io.IOException; +/** + * This class is used to control the NewGameView. + * + * @author Trym Hamer Gudvangen + */ public class NewGameController extends Controller { + /** + * Creates a new NewGameController. + */ public NewGameController() { - super(PlaythroughView.class); + super(PlaythroughView.class, NewStoryView.class); } + /** + * Sets the story to the storyFile. + * @param storyFile The story to set, as a File. + */ public void setStory(File storyFile) { StoryFileReader storyFileReader = new StoryFileReader(); try { INSTANCE.setStory(storyFileReader.parse(storyFile)); + INSTANCE.setStoryFile(storyFile); } catch (IOException | InstantiationException ex) { throw new RuntimeException(ex); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewStoryController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewStoryController.java new file mode 100644 index 0000000000000000000000000000000000000000..6a646143eafc077e06fdb225f1a0047a4ac98e63 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/NewStoryController.java @@ -0,0 +1,63 @@ +package edu.ntnu.idatt2001.group_30.paths.controller; + +import static edu.ntnu.idatt2001.group_30.paths.PathsSingleton.INSTANCE; + +import edu.ntnu.idatt2001.group_30.paths.model.Passage; +import edu.ntnu.idatt2001.group_30.paths.model.Story; +import edu.ntnu.idatt2001.group_30.paths.model.filehandling.StoryFileWriter; +import edu.ntnu.idatt2001.group_30.paths.view.views.NewStoryView; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import javafx.stage.FileChooser; + +/** + * This class is used to control the NewStoryView. + * + * @author Trym Hamer Gudvangen + */ +public class NewStoryController extends Controller { + + /** + * Creates a new NewStoryController. + */ + public NewStoryController() { + super(NewStoryView.class); + } + + /** + * Adds a story to the PathsSingleton. + * @param title The title of the story, as a String. + * @param passages The passages of the story, as a List of Passages. + * @throws IOException If the story could not be saved to file system. + */ + public void addStory(String title, List<Passage> passages) throws IOException { + Story story = new Story(title, passages.isEmpty() ? null : passages.get(0)); + passages.forEach(story::addPassage); + INSTANCE.setStory(story); + + saveStory(story); + } + + /** + * This method saves the story to the file system. + * @param story The story to save, as a Story. + * @throws IOException If the story could not be saved to file system. + */ + public void saveStory(Story story) throws IOException { + FileChooser fileChooser = new FileChooser(); + fileChooser.setInitialDirectory(new File("./src/main/resources/story-files")); + fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Paths files", "*.paths")); + File selectedFile = fileChooser.showSaveDialog(null); + + if (selectedFile != null) { + StoryFileWriter storyFileWriter = new StoryFileWriter(); + storyFileWriter.create(story, selectedFile); + } else { + throw new FileNotFoundException("File was not saved to file system"); + } + + INSTANCE.setStoryFile(selectedFile); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaytroughController.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaythroughController.java similarity index 97% rename from src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaytroughController.java rename to src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaythroughController.java index 7a1f987e4e74536604e92ae687aeff4c57fbf4da..9cf00291bb89c8bbc3ebef9ef562c91f4f8af6ec 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaytroughController.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/controller/PlaythroughController.java @@ -20,7 +20,7 @@ import javafx.scene.image.ImageView; * * @author Nicolai H. Brand. */ -public class PlaytroughController extends Controller { +public class PlaythroughController extends Controller { private Playthrough playthrough; @@ -30,7 +30,7 @@ public class PlaytroughController extends Controller { private final StringProperty passageContent = new SimpleStringProperty(); private final ObservableList<Link> links = FXCollections.observableList(new ArrayList<>()); private final ObservableList<String> inventory = FXCollections.observableList(new ArrayList<>()); - private final ObservableMap<Goal, Boolean> goals = FXCollections.observableMap(new HashMap<>()); + private final ObservableMap<Goal<?>, Boolean> goals = FXCollections.observableMap(new HashMap<>()); private final StringProperty health = new SimpleStringProperty(); private final StringProperty score = new SimpleStringProperty(); private final StringProperty gold = new SimpleStringProperty(); @@ -40,7 +40,7 @@ public class PlaytroughController extends Controller { * Creates a new instance of the controller. * It initializes the controller and starts a new game. */ - public PlaytroughController() { + public PlaythroughController() { super(HomeView.class, HelpView.class); startNewPlaythrough(); } @@ -178,7 +178,7 @@ public class PlaytroughController extends Controller { * Returns the goals of the game as an observable map. * @return the goals of the game. */ - public ObservableMap<Goal, Boolean> getGoals() { + public ObservableMap<Goal<?>, Boolean> getGoals() { return goals; } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Game.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Game.java index 287a0131c96daa0f057331ac88f3a9fb7d484b40..f1399d8c02934cadba13d12ba55b69ad7d3d60ac 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Game.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Game.java @@ -9,7 +9,7 @@ import java.util.List; * * @author Nicolai H. Brand, Trym Hamer Gudvangen */ -public record Game(Player player, Story story, List<Goal> goals) { +public record Game(Player player, Story story, List<Goal<?>> goals) { /** * This method constructs a Game object with the given parameters. * diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java index a22f45d073c6aaab575aec1aa0cef99fc28c95d5..183490579c36ad8c7277f8433eb551b23503ff76 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/Story.java @@ -13,7 +13,7 @@ import java.util.Objects; */ public class Story { - private final String title; + private String title; private final Map<Link, Passage> passages; private final Passage openingPassage; @@ -25,13 +25,7 @@ public class Story { * @throws IllegalArgumentException This exception is thrown if title or openingPassage is invalid */ public Story(String title, Passage openingPassage) throws IllegalArgumentException { - //if (title.isBlank() || !title.matches("[a-zA-Z]")) { - // throw new IllegalArgumentException("Title cannot be blank, empty, or contain special characters."); - //} - if (title.isBlank()) throw new IllegalArgumentException( - "Title cannot be blank, empty, or contain special characters." - ); - this.title = title; + setTitle(title); if (openingPassage == null) throw new IllegalArgumentException("Opening passage cannot be null"); this.openingPassage = openingPassage; this.passages = new HashMap<>(); @@ -107,6 +101,17 @@ public class Story { return title; } + /** + * This method sets the title of the story. + * @param title The new title of the story, given as a {@code String}. + */ + public void setTitle(String title) { + if (title == null || title.isBlank()) throw new IllegalArgumentException( + "Title cannot be blank, empty, or contain special characters." + ); + this.title = title; + } + /** * This method retrieves all the passages of a story. * @return All the passages of the Story as a {@code Collection<Passages>}. diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ActionType.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ActionType.java index 0d4afa902a3c42ae0edf0a85488b120b48402398..bedbaf92da351ab21f79d3ce6534fa9f4840b6b5 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ActionType.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ActionType.java @@ -6,8 +6,18 @@ package edu.ntnu.idatt2001.group_30.paths.model.actions; * @author Trym Hamer Gudvangen */ public enum ActionType { - GOLD_ACTION, - HEALTH_ACTION, - INVENTORY_ACTION, - SCORE_ACTION, + GOLD_ACTION("Gold Action"), + HEALTH_ACTION("Health Action"), + INVENTORY_ACTION("Inventory Action"), + SCORE_ACTION("Score Action"); + + private final String displayName; + + ActionType(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/GoldAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/GoldAction.java index 1101d8c660bbc86d1207c26adcc070c35d6a35af..f479b4826f43348845ddf5d583ff51b87cd76763 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/GoldAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/GoldAction.java @@ -18,7 +18,6 @@ public class GoldAction implements Action<Integer> { */ public GoldAction(int gold) { this.gold = gold; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/HealthAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/HealthAction.java index bf588fe6767b34ffe4dc4f26c41238032ef579b5..55a4afd0def466b0947c3ba49f16881a21dbbdfa 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/HealthAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/HealthAction.java @@ -18,7 +18,6 @@ public class HealthAction implements Action<Integer> { */ public HealthAction(int health) { this.health = health; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/InventoryAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/InventoryAction.java index a8b5939b85a62fb5fce85ab0ad6a1ed7827b177f..040768f0cd0e2e59ba83e4564cd45fed6c6f6901 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/InventoryAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/InventoryAction.java @@ -18,7 +18,6 @@ public class InventoryAction implements Action<String> { */ public InventoryAction(String item) { this.item = item; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ScoreAction.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ScoreAction.java index bf20494e9decc5c7910fe1d5842d0f0b8f3dd4c9..9c09207642e0b830dd1a90578c38a7aff1e2bd21 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ScoreAction.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/actions/ScoreAction.java @@ -18,7 +18,6 @@ public class ScoreAction implements Action<Integer> { */ public ScoreAction(int points) { this.points = points; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java index 40256fd7981c102e3eb8f9d8a2a9b6a1f83ce154..3bbc14c868a9f8c3726d4dee9678b828722892f6 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriter.java @@ -20,7 +20,24 @@ import java.util.*; public class StoryFileWriter { /** - * Creates a new story file with the given name and writes the story to it. + * This method takes a story and writes its contents to a .paths file. The story information is transcribed + * in the given format: + * <pre> + * Story title + * + * ::Opening Passage Title + * Opening Passage Content + * [Link Text](Link Reference) + * + * ::Another Passage Title + * Passage Content + * [Link Text](Link Reference) + * {@code <Action Type>}\Action Value/ + * [Link Text](Link Reference) + * + * ... + * </pre> + * * @param story The story to be written to the file. * @param fileName The name of the file to be created. * @throws IOException if an I/O error occurs with the writer, or if the file already exists. @@ -30,6 +47,37 @@ public class StoryFileWriter { Objects.requireNonNull(fileName, "File name cannot be null"); File file = FileHandler.createFile(fileName); + + create(story, file); + } + + /** + * This method takes a story and writes its contents to a .paths file. The story information is transcribed + * in the given format: + * <pre> + * Story title + * + * ::Opening Passage Title + * Opening Passage Content + * [Link Text](Link Reference) + * + * ::Another Passage Title + * Passage Content + * [Link Text](Link Reference) + * {@code <Action Type>}\Action Value/ + * [Link Text](Link Reference) + * + * ... + * </pre> + * + * @param story The story to be written to the file. + * @param file The file the story is going to be written to. + * @throws IOException if an I/O error occurs with the writer, or if the file already exists. + */ + public void create(Story story, File file) throws IOException { + Objects.requireNonNull(story, "Story cannot be null"); + Objects.requireNonNull(file, "File cannot be null"); + if (FileHandler.fileExists(file)) throw new FileAlreadyExistsException( "You cannot overwrite a pre-existing story file" ); @@ -38,6 +86,8 @@ public class StoryFileWriter { writeStory(story, file); } + //TODO: add test for story files... + /** * Writes the story to the given file. * @param story The story to be written to the file. diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactory.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactory.java index d18f5aca79e7d6cc095031c106cc2aa6757bc99e..92cd32b22b19d5de62826f245e7b56bce350ef0d 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactory.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalFactory.java @@ -1,12 +1,23 @@ package edu.ntnu.idatt2001.group_30.paths.model.goals; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +/** + * This class is a factory for creating Goal objects. + * + * @author Trym Hamer Gudvangen + */ public class GoalFactory { + /** + * This method creates a Goal object based on the given goal type and goal value. + * @param goalType The type of goal, given as a GoalType object. + * @param goalValue The value of the goal, given as an Object. + * @return A Goal object. + * @throws IllegalArgumentException If the goal type or value is invalid. + */ public static Goal<?> getGoal(GoalType goalType, Object goalValue) throws IllegalArgumentException { switch (goalType) { case GOLD_GOAL, HEALTH_GOAL, SCORE_GOAL -> { @@ -37,6 +48,13 @@ public class GoalFactory { throw new IllegalArgumentException("Invalid goal type or value"); } + /** + * This method creates a Goal object based on the given goal type and goal value. + * @param goalType The type of goal, given as a String. + * @param goalValue The value of the goal, given as an Object. + * @return A Goal object. + * @throws IllegalArgumentException If the goal type or value is invalid. + */ public static Goal<?> getGoal(String goalType, Object goalValue) throws IllegalArgumentException { return getGoal(GoalType.getGoalType(goalType), goalValue); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalType.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalType.java index b164bc07972740fa0a901c84fde99c1f568a7fb9..0d369287e785abccae76c20a16577372f6afc9c8 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalType.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoalType.java @@ -3,6 +3,11 @@ package edu.ntnu.idatt2001.group_30.paths.model.goals; import java.util.HashMap; import java.util.Map; +/** + * This enum represents the different types of goals. + * + * @author Trym Hamer Gudvangen + */ public enum GoalType { GOLD_GOAL("GoldGoal"), HEALTH_GOAL("HealthGoal"), @@ -18,14 +23,27 @@ public enum GoalType { } } + /** + * This constructor creates a GoalType object based on the given string value. + * @param stringVal The string value of the GoalType object. + */ GoalType(String stringVal) { this.stringVal = stringVal; } + /** + * This method retrieves the GoalType object based on the given string value. + * @param goalType The string value of the GoalType object. + * @return The GoalType object. + */ public static GoalType getGoalType(String goalType) { return stringToEnum.get(goalType); } + /** + * This method retrieves the string value of the GoalType object. + * @return The string value of the GoalType object. + */ public String getStringVal() { return stringVal; } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoldGoal.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoldGoal.java index 2f51d2165a9119654d5222d1ffaf3726e37f5abf..79ebf1121f6a17db6510b49bf46567444614298f 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoldGoal.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/GoldGoal.java @@ -18,7 +18,6 @@ public class GoldGoal implements Goal<Integer> { */ public GoldGoal(int minimumGold) { this.minimumGold = minimumGold; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/ScoreGoal.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/ScoreGoal.java index def6210020b1873a56698fab33ed53fde778fb77..a0d688e1a83839e47d140a9cf9fdeba326abb315 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/ScoreGoal.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/goals/ScoreGoal.java @@ -18,7 +18,6 @@ public class ScoreGoal implements Goal<Integer> { */ public ScoreGoal(int minimumPoints) { this.minimumPoints = minimumPoints; - //TODO: Add exception? } /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidation.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidation.java index 57610f010601a59de1a2a514bc3cc0e1fbad11e3..edfd723757903064ad2f91e31b1a8a0799b8ec70 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidation.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/model/utils/TextValidation.java @@ -3,12 +3,26 @@ package edu.ntnu.idatt2001.group_30.paths.model.utils; import javafx.scene.control.TextFormatter; import javafx.util.converter.IntegerStringConverter; +/** + * This class represents a text validation. + * + * @author Trym Hamer Gudvangen + */ public class TextValidation { + /** + * This method creates a text formatter for integers. + * @return A text formatter for integers. + */ public static TextFormatter<Integer> createIntegerTextFormatter() { return createIntegerTextFormatter(100); } + /** + * This method creates a text formatter for integers. + * @param startValue The start value of the text formatter, given as an integer. + * @return A text formatter for integers. + */ public static TextFormatter<Integer> createIntegerTextFormatter(int startValue) { return new TextFormatter<>( new IntegerStringConverter(), diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/App.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/App.java index 8f18add2be461aff2bd711a220fe267c2aa003a8..6f149869142bbc25642d016dd475b994cc9083d1 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/App.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/App.java @@ -32,7 +32,7 @@ public class App extends Application { @Override public void start(Stage stage) { stage.initStyle(StageStyle.UTILITY); - stage.setAlwaysOnTop(true); + stage.setAlwaysOnTop(false); stage.setTitle("Paths"); /* initialize STAGE_MANAGER */ STAGE_MANAGER = StageManager.init(stage); diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/PassageNode.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/PassageNode.java deleted file mode 100644 index 05882d9d03a540638019bd0441e305cae01fca50..0000000000000000000000000000000000000000 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/PassageNode.java +++ /dev/null @@ -1,91 +0,0 @@ -package edu.ntnu.idatt2001.group_30.paths.view; - -import edu.ntnu.idatt2001.group_30.paths.PathsSingleton; -import edu.ntnu.idatt2001.group_30.paths.model.Passage; -import java.util.ArrayList; -import java.util.List; -import javafx.geometry.Point2D; -import javafx.scene.Cursor; -import javafx.scene.layout.Pane; -import javafx.scene.paint.Color; -import javafx.scene.paint.Paint; -import javafx.scene.shape.Line; -import javafx.scene.shape.Rectangle; -import javafx.scene.text.Text; - -/* - TODO: - - add ability to edit. - - add links (double click to draw? click again on another passage to add link?) - - problems: reconstructing the layout of shapes (need to store positions) - */ - -public class PassageNode extends Pane { - - private final Passage passage; - private final Rectangle rectangle; - private final Text text; - private Point2D passageInitOffset; - - private final List<Line> links = new ArrayList<>(); //TODO: may need to actually make a linkNode class... - - public PassageNode(Passage passage) { - this(100, 100, 100, 100, passage); - } - - public PassageNode(double v, double v1, Passage passage) { - this(v, v1, 100, 100, passage); - } - - public PassageNode(double v, double v1, Paint paint, Passage passage) { - this(v, v1, 100, 100, passage); - this.rectangle.setFill(paint); - } - - public PassageNode(double v, double v1, double v2, double v3, Passage passage) { - this.passage = passage; - this.rectangle = new Rectangle(0, 0, v2, v3); - this.rectangle.setFill(Color.WHITE); - this.rectangle.setStyle("-fx-border-color: black;"); - this.text = new Text(passage.toString()); - this.text.setFill(Color.BLACK); - - addPassageEventListener(); - - getChildren().addAll(this.rectangle, this.text); - this.setLayoutX(v); - this.setLayoutY(v1); - this.setPrefSize(v2, v3); - // this.setTranslateX(v); - // this.setTranslateY(v1); - - } - - private void addPassageEventListener() { - this.setOnMousePressed(mouseEvent -> { - this.setCursor(Cursor.HAND); - this.passageInitOffset = - new Point2D(mouseEvent.getX(), mouseEvent.getY()) - .subtract(this.getTranslateX(), this.getTranslateY()); - }); - - this.setOnMouseDragged(event -> { - this.setCursor(Cursor.MOVE); - PathsSingleton.INSTANCE.setPassageMoving(true); - - double newX = event.getX() - this.passageInitOffset.getX(); - double newY = event.getY() - this.passageInitOffset.getY(); - - this.setTranslateX(newX); - this.setTranslateY(newY); - // this.getChildren().forEach(child -> child.setTranslateX(event.getX() - this.getWidth()/2)); - // this.setX(event.getX() - this.getWidth()/2); - // this.setY(event.getY() - this.getHeight()/2); - //TODO: adjust link as well - }); - - this.setOnMouseReleased(mouseDragEvent -> { - PathsSingleton.INSTANCE.setPassageMoving(false); - }); - } -} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryCreation.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryCreation.java deleted file mode 100644 index 51e4144d1365f0f98d7fe03fb07262bcd9a14365..0000000000000000000000000000000000000000 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryCreation.java +++ /dev/null @@ -1,130 +0,0 @@ -package edu.ntnu.idatt2001.group_30.paths.view; - -import edu.ntnu.idatt2001.group_30.paths.PathsSingleton; -import edu.ntnu.idatt2001.group_30.paths.model.Passage; -import javafx.application.Application; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.geometry.Point2D; -import javafx.scene.Cursor; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.ScrollPane; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import javafx.scene.shape.Line; -import javafx.stage.Stage; - -public class StoryCreation extends Application { - - public static final int DEFAULT_WIDTH = 1000; - public static final int DEFAULT_HEIGHT = 1000; - private static Stage stage; - private Point2D contentPaneInitOffset; - private final ObservableList<PassageNode> passages = FXCollections.observableArrayList(); - - /** - * The entry point of the application. - * @param args The command line arguments. - */ - public static void main(String[] args) { - launch(); - } - - /** - * The start method is called by the JavaFX runtime after the init method has returned. - * @param stage The primary stage for this application, onto which the application scene can be set. - */ - @Override - public void start(Stage stage) { - StoryCreation.stage = stage; - StoryCreation.stage.setTitle("Paths"); - AnchorPane anchorPane = new AnchorPane(); - - ScrollPane scrollPane = new ScrollPane(); - scrollPane.setPrefSize(1000, 1000); - - Pane contentPane = new Pane(); - contentPane.setStyle("-fx-border-color: black;"); - scrollPane.setContent(contentPane); - - PassageNode passage1 = new PassageNode(50, 50, 100, 50, new Passage("Passage title", "Content")); - PassageNode passage2 = new PassageNode(200, 200, 100, 50, new Passage("Passage title2", "Content2")); - - passages.addAll(passage1, passage2); - //TODO: make class for GUI passage, containing place for GUI link... - Line link1 = new Line(100, 75, 200, 225); - - contentPane.getChildren().addAll(passage1, passage2, link1); - - addContentPaneEventListeners(contentPane); - - scrollPane.setOnZoom(event -> { - double zoomFactor = event.getTotalZoomFactor(); - contentPane.setScaleX(contentPane.getScaleX() * zoomFactor); - contentPane.setScaleY(contentPane.getScaleY() * zoomFactor); - }); - - Button addPassage = new Button("Add Passage"); - VBox menu = new VBox(addPassage); - menu.setTranslateX(300); - menu.setTranslateY(300); - - anchorPane.getChildren().addAll(scrollPane, menu); - - addPassage - .onActionProperty() - .set(actionEvent -> { - PassageNode newPassage = new PassageNode( - 200 + 100 * passages.size(), - 200, - 100, - 50, - new Passage("Passage title", "Content2") - ); - passages.add(newPassage); - contentPane.getChildren().add(newPassage); - }); - - Scene scene = new Scene(anchorPane, DEFAULT_WIDTH, DEFAULT_HEIGHT); - StoryCreation.stage.setScene(scene); - StoryCreation.stage.show(); - } - - private void addContentPaneEventListeners(Pane contentPane) { - contentPane.setOnMousePressed(mouseEvent -> { - contentPane.setCursor(Cursor.HAND); - contentPaneInitOffset = - new Point2D(mouseEvent.getX(), mouseEvent.getY()) - .subtract(contentPane.getTranslateX(), contentPane.getTranslateY()); - }); - - contentPane.setOnMouseReleased(mouseEvent -> { - contentPane.setCursor(Cursor.DEFAULT); - }); - - contentPane.setOnMouseDragged(mouseEvent -> { - if (!PathsSingleton.INSTANCE.isPassageMoving()) { - contentPane.setCursor(Cursor.HAND); - - double newX = mouseEvent.getX() - contentPaneInitOffset.getX(); - double newY = mouseEvent.getY() - contentPaneInitOffset.getY(); - contentPane.setTranslateX(newX); - contentPane.setTranslateY(newY); - } - }); - - contentPane.setOnMouseClicked(mouseEvent -> { - PassageNode newPassage = new PassageNode( - mouseEvent.getX(), - mouseEvent.getY(), - 100, - 50, - new Passage("Passage title", "Content2") - ); - passages.add(newPassage); - contentPane.getChildren().add(newPassage); - }); - } -} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/CreatePlayer.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/CreatePlayer.java index bc00aca590e12118c59f808f3e0e7bac31c6598f..004702c843a858ab8e3fa8116170b0569e8ce169 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/CreatePlayer.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/CreatePlayer.java @@ -18,6 +18,9 @@ public class CreatePlayer extends GridPane { private final TextField goldField; private final ComboBox<String> goalBox; + /** + * Constructor for the CreatePlayer component. + */ public CreatePlayer() { setHgap(10); setVgap(5); @@ -38,18 +41,34 @@ public class CreatePlayer extends GridPane { add(goalBox, 1, 3); } + /** + * Method for getting the name of the player. + * @return The name of the player, as a String. + */ public String getName() { return nameField.getText(); } + /** + * Method for getting the health of the player. + * @return The health of the player, as an int. + */ public int getHealth() { return Integer.parseInt(healthField.getText()); } + /** + * Method for getting the gold of the player. + * @return The gold of the player, as an int. + */ public int getGold() { return Integer.parseInt(goldField.getText()); } + /** + * Method for getting the goal of the player. + * @return The goal of the player, as a String. + */ public String getGoal() { return goalBox.getValue(); } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/ImageCarousel.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/ImageCarousel.java index 7858c3660988b7b2c5fc96b46d8ce4d473f7e1fe..a95573f21a490516385765e79f952d6f1154b2f9 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/ImageCarousel.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/ImageCarousel.java @@ -9,6 +9,11 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; +/** + * This class represents a component for displaying a carousel of images. + * + * @author Trym Hamer Gudvangen + */ public class ImageCarousel { private final LinkedList<Image> images = new LinkedList<>(); @@ -18,6 +23,10 @@ public class ImageCarousel { private final int WIDTH = 150; private final int HEIGHT = 150; + /** + * Constructor for the ImageCarousel component. + * @param imageNames A list of image names, as Strings. + */ public ImageCarousel(List<String> imageNames) { if (imageNames == null || imageNames.isEmpty()) { throw new IllegalArgumentException("Image URI list must not be empty."); @@ -39,6 +48,10 @@ public class ImageCarousel { this.currentImage.setImage(images.getFirst()); } + /** + * Method for getting the carousel component. + * @return The carousel component, as an HBox. + */ public HBox getCarousel() { Button leftButton = new Button("<"); leftButton.setOnAction(e -> previous()); @@ -51,20 +64,34 @@ public class ImageCarousel { return carousel; } + /** + * Method for getting the next image. + */ public void next() { currentIndex = (currentIndex + 1) % size; currentImage.setImage(images.get(currentIndex)); } + /** + * Method for getting the previous image. + */ public void previous() { currentIndex = (currentIndex - 1 + size) % size; currentImage.setImage(images.get(currentIndex)); } + /** + * Method for getting the size of the list of images. + * @return The size of the list of images, as an int. + */ public int size() { return size; } + /** + * Method for getting the current image. + * @return The current image, as an ImageView. + */ public ImageView getCurrentImage() { return currentImage; } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryDisplay.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java similarity index 99% rename from src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryDisplay.java rename to src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java index 9b4b4457463b28bbe96f725157a070bf01ae04a6..0ef5e184defa013b60cb6b9db158008c44b60088 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/StoryDisplay.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/StoryDisplay.java @@ -1,4 +1,4 @@ -package edu.ntnu.idatt2001.group_30.paths.view; +package edu.ntnu.idatt2001.group_30.paths.view.components; import edu.ntnu.idatt2001.group_30.paths.model.Story; import edu.ntnu.idatt2001.group_30.paths.model.filehandling.FileHandler; diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/common/DefaultInputField.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/common/DefaultInputField.java new file mode 100644 index 0000000000000000000000000000000000000000..a030a4bd51bd011df7e4c4f6ed4768859013e228 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/common/DefaultInputField.java @@ -0,0 +1,26 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.common; + +import javafx.scene.control.TextField; +import javafx.scene.layout.HBox; +import javafx.scene.text.Text; + +/** + * This class contains methods to create different input fields with default layouts. + * + * @author Trym Hamer Gudvangen + */ +public class DefaultInputField { + + /** + * This method creates a text input field with a given label and prompt. + * @param label The label of the input field, given as a String. + * @param prompt The prompt of the input field, given as a String. + * @return An HBox containing the label and the input field. + */ + public static HBox inputWithLabelAndPrompt(String label, String prompt) { + Text labelText = new Text(label); + TextField textField = new TextField(); + textField.setPromptText(prompt); + return new HBox(labelText, textField); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/AbstractPopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/AbstractPopUp.java new file mode 100644 index 0000000000000000000000000000000000000000..35fa07f2d7b7444bbcb12bba3eb96c8004d17b1e --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/AbstractPopUp.java @@ -0,0 +1,32 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.pop_up; + +/** + * This class provides a template for creating pop-ups. + * + * @author Trym Hamer Gudvangen + */ +public abstract class AbstractPopUp { + + /** + * This method initializes the pop-up by setting up the UI components and the behavior. + */ + protected void initialize() { + setupUiComponents(); + setupBehavior(); + } + + /** + * This method sets up the UI components of the pop-up. + */ + protected abstract void setupUiComponents(); + + /** + * This method sets up the behavior of the pop-up. + */ + protected abstract void setupBehavior(); + + /** + * This method creates the pop-up. + */ + protected abstract void createPopUp(); +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/GoalsPopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/GoalsPopUp.java index c60ab50127f111cadef1dc0aef67c6bafd9dd6c7..71e19b86a45896a37c987674488faaadb51b28ef 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/GoalsPopUp.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/GoalsPopUp.java @@ -16,14 +16,39 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; -public class GoalsPopUp { +/** + * This class contains a pop-up for creating and editing goals. + * + * @author Trym Hamer Gudvangen + */ +public class GoalsPopUp extends AbstractPopUp { private TextField healthField; private TextField goldField; private TextField scoreField; private Button saveButton; - + private Button addButton; + private Button deleteButton; + private TextField inventoryField; + private ObservableList<String> items; + private TableView<String> inventoryTable; + private VBox content; + private ScrollPane scrollPane; + private PopUp<ScrollPane, ?> popUp; + + /** + * This constructor creates a new GoalsPopUp. + */ public GoalsPopUp() { + initialize(); + createPopUp(); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setupUiComponents() { healthField = new TextField(); healthField.setTextFormatter( TextValidation.createIntegerTextFormatter( @@ -50,10 +75,10 @@ public class GoalsPopUp { saveButton = new Button("Save"); - TextField inventoryField = new TextField(); + inventoryField = new TextField(); inventoryField.setPromptText("Add inventory item"); - Button addButton = new Button(); + addButton = new Button(); URL imageUrl = getClass().getResource("/images/plus.png"); if (imageUrl != null) { ImageView addIcon = new ImageView(new Image(imageUrl.toString())); @@ -64,18 +89,18 @@ public class GoalsPopUp { System.err.println("Something is wrong with the trash image resource link"); } - ObservableList<String> items = FXCollections.observableArrayList(); + items = FXCollections.observableArrayList(); if (INSTANCE.getInventoryGoal() != null) { items.addAll(INSTANCE.getInventoryGoal().getGoalValue()); } - TableView<String> inventoryTable = new TableView<>(items); + inventoryTable = new TableView<>(items); TableColumn<String, String> itemColumn = new TableColumn<>("Items"); itemColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue())); inventoryTable.getColumns().add(itemColumn); itemColumn.prefWidthProperty().bind(inventoryTable.widthProperty()); inventoryTable.setMaxHeight(200); - Button deleteButton = new Button(); + deleteButton = new Button(); imageUrl = getClass().getResource("/images/trash.png"); if (imageUrl != null) { ImageView trashIcon = new ImageView(new Image(imageUrl.toString())); @@ -86,6 +111,33 @@ public class GoalsPopUp { System.err.println("Something is wrong with the trash image resource link"); } + content = + new VBox( + new Label("Health:"), + healthField, + new Label("Gold:"), + goldField, + new Label("Score:"), + scoreField, + new Label("Inventory"), + new HBox(inventoryField, addButton), + inventoryTable, + deleteButton, + saveButton + ); + + content.setAlignment(Pos.CENTER); + content.setSpacing(20); + + scrollPane = new ScrollPane(content); + scrollPane.setFitToWidth(true); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setupBehavior() { addButton.setOnAction(e -> { if (!inventoryField.getText().isBlank()) { items.add(inventoryField.getText()); @@ -100,33 +152,6 @@ public class GoalsPopUp { } }); - VBox content = new VBox( - new Label("Health:"), - healthField, - new Label("Gold:"), - goldField, - new Label("Score:"), - scoreField, - new Label("Inventory"), - new HBox(inventoryField, addButton), - inventoryTable, - deleteButton, - saveButton - ); - - content.setAlignment(Pos.CENTER); - content.setSpacing(20); - - ScrollPane scrollPane = new ScrollPane(content); - scrollPane.setFitToWidth(true); - - PopUp<ScrollPane, ?> popUp = PopUp - .<ScrollPane>create() - .withTitle("Add goals to your player") - .withoutCloseButton() - .withContent(scrollPane) - .withDialogSize(400, 500); - saveButton.setOnAction(e -> { if (healthField.getText().isBlank() || goldField.getText().isBlank()) { AlertDialog.showWarning("The different fields cannot be blank."); @@ -139,6 +164,21 @@ public class GoalsPopUp { popUp.close(); } }); + } + + /** + * {@inheritDoc} + */ + @Override + protected void createPopUp() { + popUp = + PopUp + .<ScrollPane>create() + .withTitle("Add goals to your player") + .withoutCloseButton() + .withContent(scrollPane) + .withDialogSize(400, 750); + popUp.showAndWait(); } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/LinkPopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/LinkPopUp.java new file mode 100644 index 0000000000000000000000000000000000000000..54bd0ee6d0f05d650d73ff237281e3cbbda0e58d --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/LinkPopUp.java @@ -0,0 +1,213 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.pop_up; + +import edu.ntnu.idatt2001.group_30.paths.model.Link; +import edu.ntnu.idatt2001.group_30.paths.model.Passage; +import edu.ntnu.idatt2001.group_30.paths.model.actions.Action; +import edu.ntnu.idatt2001.group_30.paths.model.actions.ActionFactory; +import edu.ntnu.idatt2001.group_30.paths.model.actions.ActionType; +import edu.ntnu.idatt2001.group_30.paths.model.utils.TextValidation; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.ActionTable; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.TableDisplay; +import java.util.HashMap; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * This class is a pop-up for creating a new link or editing an existing one. + * + * @author Trym Hamer Gudvangen + */ +public class LinkPopUp extends AbstractPopUp { + + private TextField textField; + private TextField actionTextField; + private Button saveButton; + private Button addActionButton; + private Button removeActionButton; + private ComboBox<String> reference; + private ComboBox<ActionType> actionComboBox; + private ActionTable<Action<?>> actionTable; + private VBox content; + private final ObservableList<Passage> passages; + private ObservableList<Action<?>> actions; + private HashMap<String, Passage> passageHashMap; + private Link link; + private PopUp<VBox, ?> popUp; + + /** + * This constructor allows a new link to be created. + * @param passages Other passages in the story, given as an ObservableList of passages. + */ + public LinkPopUp(ObservableList<Passage> passages) { + this.actions = FXCollections.observableArrayList(); + this.passages = passages; + this.passageHashMap = new HashMap<>(); + passages.forEach(passage -> passageHashMap.put(passage.getTitle(), passage)); + + initialize(); + createPopUp(); + } + + /** + * This constructor allows a pre-existing link to be edited. + * @param passages Other passages in the story, given as an ObservableList of passages. + * @param link The link to be edited, given as a Link object. + */ + public LinkPopUp(ObservableList<Passage> passages, Link link) { + this.link = link; + this.actions = FXCollections.observableArrayList(link.getActions()); + this.passages = passages; + this.passageHashMap = new HashMap<>(); + passages.forEach(passage -> passageHashMap.put(passage.getTitle(), passage)); + + initialize(); + loadLink(); + createPopUp(); + } + + /** + * This method loads the link to be edited into the pop-up. + */ + @Override + protected void setupUiComponents() { + textField = new TextField(); + textField.setPromptText("Enter the text of the link"); + + reference = new ComboBox<>(FXCollections.observableArrayList(passageHashMap.keySet())); + reference.setPromptText("Select reference passage of the link"); + + saveButton = new Button("Save"); + + ObservableList<ActionType> actionTypes = FXCollections.observableArrayList(ActionType.values()); + + actionComboBox = new ComboBox<>(actionTypes); + actionComboBox.setPromptText("Select an action"); + + actionTextField = new TextField(); + + removeActionButton = new Button("Remove Action"); + removeActionButton.setDisable(true); + + addActionButton = new Button("Add Action"); + + HBox actionHbox = new HBox(actionComboBox, actionTextField, addActionButton); + actionHbox.setAlignment(Pos.CENTER); + + actionTable = + new ActionTable<>( + new TableDisplay.Builder<Action<?>>() + .addColumnWithComplexValue("Type", action -> action.getClass().getSimpleName()) + .addColumnWithComplexValue("Value", action -> action.getActionValue().toString()) + ); + + actionTable.setItems(actions); + + actionTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + + content = + new VBox( + new Label("Link Text:"), + textField, + new Label("Link Reference:"), + reference, + new Label("Actions:"), + actionHbox, + actionTable, + removeActionButton, + saveButton + ); + + content.setAlignment(Pos.CENTER); + content.setSpacing(20); + } + + /** + * This method sets up the behavior of the Ui components. + */ + @Override + protected void setupBehavior() { + removeActionButton.setOnAction(event -> actions.remove(actionTable.getSelectionModel().getSelectedItem())); + + actionTable + .getSelectionModel() + .selectedItemProperty() + .addListener((obs, oldSelection, newSelection) -> { + removeActionButton.setDisable(newSelection == null); + }); + + addActionButton.setOnAction(e -> { + if (actionComboBox.getValue() != null) { + actions.add(ActionFactory.getAction(actionComboBox.getValue(), actionTextField.getText())); + actionComboBox.setValue(null); + } + }); + + saveButton.setOnAction(e -> { + if (textField.getText().isBlank() || reference.getValue() == null) { + AlertDialog.showWarning("The text or reference cannot be blank."); + } else { + link = new Link(textField.getText(), passageHashMap.get(reference.getValue()).getTitle()); + actions.forEach(action -> link.addAction(action)); + popUp.close(); + } + }); + + actionComboBox.setCellFactory(listView -> + new ListCell<>() { + @Override + protected void updateItem(ActionType actionType, boolean empty) { + super.updateItem(actionType, empty); + if (empty || actionType == null) { + setText(null); + } else { + setText(actionType.getDisplayName()); + switch (actionType) { + case SCORE_ACTION, GOLD_ACTION, HEALTH_ACTION -> actionTextField.setTextFormatter( + TextValidation.createIntegerTextFormatter() + ); + case INVENTORY_ACTION -> actionTextField.setTextFormatter(null); + } + } + } + } + ); + + actionComboBox.setButtonCell(actionComboBox.getCellFactory().call(null)); + } + + /** + * This method creates the pop-up. + */ + @Override + protected void createPopUp() { + popUp = + PopUp + .<VBox>create() + .withTitle("Create a Link") + .withoutCloseButton() + .withContent(content) + .withDialogSize(400, 500); + + popUp.showAndWait(); + } + + /** + * This method loads the link to be edited into the pop-up. + */ + private void loadLink() { + textField.setText(this.link.getText()); + reference.setValue(this.link.getReference()); + } + + /** + * This method retrieves the link created in the pop-up. + * @return Link created in pop-up, given as a Link object. + */ + public Link getLink() { + return link; + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PassagePopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PassagePopUp.java new file mode 100644 index 0000000000000000000000000000000000000000..3b25186dcc066391c7d7de2ac6678e971d28efbe --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PassagePopUp.java @@ -0,0 +1,187 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.pop_up; + +import edu.ntnu.idatt2001.group_30.paths.model.Link; +import edu.ntnu.idatt2001.group_30.paths.model.Passage; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.LinkTable; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.TableDisplay; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; + +/** + * This class contains a pop-up for creating a new passage. + * + * @author Trym Hamer Gudvangen + */ +public class PassagePopUp extends AbstractPopUp { + + private TextField titleField; + private TextArea contentArea; + private Button saveButton; + private Button removeLinkButton; + private Button addLinkButton; + private Button editLinkButton; + private VBox content; + private LinkTable<Link> linkTable; + private final ObservableList<Passage> passages; + private final ObservableList<Link> links; + private Passage passage; + private PopUp<VBox, ?> popUp; + + /** + * This constructor allows a new passage to be created. + * @param passages Other passages in the story, given as an ObservableList of passages. + */ + public PassagePopUp(ObservableList<Passage> passages) { + this.passages = passages; + this.links = FXCollections.observableArrayList(); + initialize(); + createPopUp(); + } + + /** + * This constructor allows a pre-existing passage to be edited. + * @param passages Other passages in the story, given as an ObservableList of passages. + * @param passage Passage to edit, given as a Passage object. + */ + public PassagePopUp(ObservableList<Passage> passages, Passage passage) { + this.passages = passages; + this.passage = passage; + this.links = FXCollections.observableArrayList(passage.getLinks()); + initialize(); + loadPassage(passage); + createPopUp(); + } + + /** + * This method sets up the UI components for the pop-up. + */ + @Override + protected void setupUiComponents() { + titleField = new TextField(); + titleField.setPromptText("Enter the title of the passage"); + + contentArea = new TextArea(); + contentArea.setPromptText("Enter the content of the passage"); + contentArea.setMinHeight(150); + + saveButton = new Button("Save"); + + linkTable = + new LinkTable<>( + new TableDisplay.Builder<Link>().addColumn("Link Title", "text").addColumn("Reference", "reference") + ); + + linkTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + linkTable.setItems(links); + + editLinkButton = new Button("Edit Link"); + editLinkButton.setDisable(true); + + removeLinkButton = new Button("Remove Link"); + removeLinkButton.setDisable(true); + + addLinkButton = new Button("Add Link"); + if (passages.isEmpty()) addLinkButton.setDisable(true); + + HBox linkTableButtonHBox = new HBox(editLinkButton, addLinkButton, removeLinkButton); + linkTableButtonHBox.setAlignment(Pos.CENTER); + + content = + new VBox( + new Label("Passage Title:"), + titleField, + new Label("Passage Content:"), + contentArea, + new Label("Links:"), + linkTable, + linkTableButtonHBox, + saveButton + ); + + content.setAlignment(Pos.CENTER); + content.setSpacing(20); + } + + /** + * This method sets up the behavior for the pop-up. + */ + @Override + protected void setupBehavior() { + editLinkButton.setOnAction(e -> { + Link newLink = new LinkPopUp(this.passages, linkTable.getSelectionModel().getSelectedItem()).getLink(); + if (newLink != null) { + this.links.remove(linkTable.getSelectionModel().getSelectedItem()); + this.links.add(newLink); + } + }); + + removeLinkButton.setOnAction(e -> links.remove(linkTable.getSelectionModel().getSelectedItem())); + linkTable + .getSelectionModel() + .selectedItemProperty() + .addListener((obs, oldSelection, newSelection) -> { + removeLinkButton.setDisable(newSelection == null); + editLinkButton.setDisable(newSelection == null); + }); + + addLinkButton.setOnAction(e -> { + Link newLink = new LinkPopUp(this.passages).getLink(); + if (newLink != null) { + this.links.add(newLink); + } + }); + + saveButton.setOnAction(e -> { + if (titleField.getText().isBlank() || contentArea.getText().isBlank()) { + AlertDialog.showWarning("The title or content cannot be blank."); + } else if ( + this.passages.stream() + .anyMatch(passage1 -> passage1.getTitle().equals(titleField.getText()) && passage != passage1) + ) { + AlertDialog.showWarning("A passage with the title " + titleField.getText() + " already exists."); + } else { + this.passage = new Passage(titleField.getText(), contentArea.getText()); + + this.links.forEach(link -> this.passage.addLink(link)); + popUp.close(); + } + }); + } + + /** + * {@inheritDoc} + */ + @Override + protected void createPopUp() { + popUp = + PopUp + .<VBox>create() + .withTitle("Create a Passage") + .withoutCloseButton() + .withContent(content) + .withDialogSize(400, 750); + + popUp.showAndWait(); + } + + /** + * This method loads a passage into the pop-up. + * @param passage Passage to load, given as a Passage object. + */ + private void loadPassage(Passage passage) { + titleField.setText(passage.getTitle()); + contentArea.setText(passage.getContent()); + } + + /** + * This method retrieves the passages created from the pop-up. + * @return Passages created, given as a List of Passage objects. + */ + public Passage getPassage() { + return passage; + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PopUp.java index 7b38f065463c9e8b0261fcbe23728c39c34cfd7d..9fff0bfd999acf0d5a905339dcb4daf1a60c1473 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PopUp.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/PopUp.java @@ -3,15 +3,28 @@ package edu.ntnu.idatt2001.group_30.paths.view.components.pop_up; import javafx.scene.control.*; import javafx.scene.layout.Region; +/** + * This class provides a template for creating pop-ups. + * @param <T> The type of the content of the pop-up. + * @param <SELF> The type of the pop-up. + */ public class PopUp<T extends Region, SELF extends PopUp<T, SELF>> extends Dialog<Void> { private final DialogPane dialogPane; + /** + * This constructor sets up the dialog pane. + */ protected PopUp() { dialogPane = new DialogPane(); setDialogPane(dialogPane); } + /** + * This method creates a pop-up. + * @return The pop-up. + * @param <T> The type of the content of the pop-up. + */ public static <T extends Region> PopUp<T, ?> create() { return new PopUp<>(); } @@ -21,16 +34,30 @@ public class PopUp<T extends Region, SELF extends PopUp<T, SELF>> extends Dialog return self(); } + /** + * This method returns the dialog pane. + * @param content The content of the dialog pane. + * @return The dialog pane. + */ public SELF withContent(T content) { dialogPane.setContent(content); return self(); } + /** + * This method returns the dialog pane. + * @param buttonType The button type of the dialog pane. + * @return The dialog pane. + */ public SELF withButton(ButtonType buttonType) { dialogPane.getButtonTypes().add(buttonType); return self(); } + /** + * This method returns the dialog pane. + * @return The dialog pane. + */ public SELF withoutCloseButton() { // Add a close button type to the dialog ButtonType closeButtonType = new ButtonType("Close", ButtonBar.ButtonData.CANCEL_CLOSE); @@ -44,12 +71,22 @@ public class PopUp<T extends Region, SELF extends PopUp<T, SELF>> extends Dialog return self(); } + /** + * This method returns the dialog pane. + * @param width The width of the dialog pane. + * @param height The height of the dialog pane. + * @return The dialog pane. + */ public SELF withDialogSize(double width, double height) { getDialogPane().setMinSize(width, height); getDialogPane().setMaxSize(width, height); return self(); } + /** + * This method returns the dialog pane. + * @return The dialog pane. + */ @SuppressWarnings("unchecked") protected SELF self() { return (SELF) this; diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/StatsPopUp.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/StatsPopUp.java index dca6f643b11a972f75cfd7d50f2d45b1042cd9ab..5e6ba2692d8d81b5937c13fac36729ab07d5ff52 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/StatsPopUp.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/StatsPopUp.java @@ -9,13 +9,48 @@ import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.layout.VBox; -public class StatsPopUp { +/** + * This class contains a pop-up for adding stats to the player. + * + * @author Trym Hamer Gudvangen + */ +public class StatsPopUp extends AbstractPopUp { private TextField healthField; private TextField goldField; private Button saveButton; + private VBox content; + private PopUp<VBox, ?> popUp; + /** + * This constructor creates a new StatsPopUp. + */ public StatsPopUp() { + initialize(); + createPopUp(); + } + + /** + * This method retrieves the health value from the pop-up. + * @return The health value, as an int. + */ + public int getHealth() { + return Integer.parseInt(healthField.getText()); + } + + /** + * This method retrieves the gold value from the pop-up. + * @return The gold value, as an int. + */ + public int getGold() { + return Integer.parseInt(goldField.getText()); + } + + /** + * {@inheritDoc} + */ + @Override + protected void setupUiComponents() { healthField = new TextField(); healthField.setTextFormatter(TextValidation.createIntegerTextFormatter(INSTANCE.getPlayer().getHealth())); @@ -27,17 +62,16 @@ public class StatsPopUp { saveButton = new Button("Save"); - VBox content = new VBox(new Label("Health:"), healthField, new Label("Gold:"), goldField, saveButton); + content = new VBox(new Label("Health:"), healthField, new Label("Gold:"), goldField, saveButton); content.setAlignment(Pos.CENTER); content.setSpacing(20); + } - PopUp<VBox, ?> popUp = PopUp - .<VBox>create() - .withTitle("Add stats to your player") - .withoutCloseButton() - .withContent(content) - .withDialogSize(400, 300); - + /** + * {@inheritDoc} + */ + @Override + protected void setupBehavior() { saveButton.setOnAction(e -> { if (healthField.getText().isBlank() || goldField.getText().isBlank()) { AlertDialog.showWarning("The different fields cannot be blank."); @@ -47,14 +81,21 @@ public class StatsPopUp { popUp.close(); } }); - popUp.showAndWait(); } - public int getHealth() { - return Integer.parseInt(healthField.getText()); - } + /** + * {@inheritDoc} + */ + @Override + protected void createPopUp() { + popUp = + PopUp + .<VBox>create() + .withTitle("Add stats to your player") + .withoutCloseButton() + .withContent(content) + .withDialogSize(400, 300); - public int getGold() { - return Integer.parseInt(goldField.getText()); + popUp.showAndWait(); } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/ActionTable.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/ActionTable.java new file mode 100644 index 0000000000000000000000000000000000000000..31719edef73503f62471e6fc6e08fd5d9a481baf --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/ActionTable.java @@ -0,0 +1,19 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.table; + +/** + * This class contains the table display implementation for the action object. + * @param <Action> Type of table, which is for Action. + * + * @author Trym Hamer Gudvangen + */ +public class ActionTable<Action> extends TableDisplay<Action> { + + /** + * This is a constructor which is used to construct a table for different actions. + * + * @param tableBuilder The builder used to construct a table, represented using an tableBuilder object. + */ + public ActionTable(Builder<Action> tableBuilder) { + super(tableBuilder); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/GoalTable.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/GoalTable.java index be5916a7410212bd28a4740820b490e3e6b4d080..c9646a11b7d1f7fff6ec658b8d90751dc145d50a 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/GoalTable.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/GoalTable.java @@ -1,5 +1,11 @@ package edu.ntnu.idatt2001.group_30.paths.view.components.table; +/** + * This class contains the specific table display implementation for the Goal classes. + * @param <Goal> Type of table, which is Goal. + * + * @author Trym Hamer Gudvangen + */ public class GoalTable<Goal> extends TableDisplay<Goal> { /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/LinkTable.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/LinkTable.java new file mode 100644 index 0000000000000000000000000000000000000000..4a4dbaccc42362bc0bc7ced9c876aad4e75b3acf --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/LinkTable.java @@ -0,0 +1,17 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.table; + +/** + * This class concerns itself with the aspects intrinsic to a link table. + * @param <Link> The type of the table, represented using a Link object. + */ +public class LinkTable<Link> extends TableDisplay<Link> { + + /** + * This is a constructor which is used to construct a table for different links. + * + * @param tableBuilder The builder used to construct a table, represented using an tableBuilder object. + */ + public LinkTable(Builder<Link> tableBuilder) { + super(tableBuilder); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/PassageTable.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/PassageTable.java new file mode 100644 index 0000000000000000000000000000000000000000..50ade57fad82d379fe538d430571577c291e8947 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/PassageTable.java @@ -0,0 +1,17 @@ +package edu.ntnu.idatt2001.group_30.paths.view.components.table; + +/** + * This class concerns itself with the aspects intrinsic to a passage table. + * @param <Passage> The type of the table, represented using a Passage object. + */ +public class PassageTable<Passage> extends TableDisplay<Passage> { + + /** + * This is a constructor which is used to construct a table for different passages. + * + * @param tableBuilder The builder used to construct a table, represented using an tableBuilder object. + */ + public PassageTable(Builder<Passage> tableBuilder) { + super(tableBuilder); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/StatsTable.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/StatsTable.java index a0fec2282aa03daa29e5e0eeb6a1aab3ade3f70f..e639b45d7b44b74cc947efa52a7400eacce32c61 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/StatsTable.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/StatsTable.java @@ -1,5 +1,9 @@ package edu.ntnu.idatt2001.group_30.paths.view.components.table; +/** + * This class concerns itself with the aspects intrinsic to a stats table. + * @param <Player> The type of the table, represented using a Player object. + */ public class StatsTable<Player> extends TableDisplay<Player> { /** diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/TableDisplay.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/TableDisplay.java index bd8a5d874cd8be3f42093127b6725ee0d6c9b8c1..ad2f18c18b60760a46df91631850afe3113dccde 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/TableDisplay.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/table/TableDisplay.java @@ -1,5 +1,7 @@ package edu.ntnu.idatt2001.group_30.paths.view.components.table; +import java.util.function.Function; +import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.control.TableColumn; @@ -47,6 +49,23 @@ public class TableDisplay<T> extends TableView<T> { return this; } + /** + * This method attaches a desired column {@link TableDisplayColumn#TableDisplayColumn(String, String)} to the + * tableview that is complex. + * @param infoHeader The name of the column, represented using a String. + * @param complexValueFunction The attribute the information will be extracted from, represented as a String. + * @return The builder itself is returned, represented as a Builder object. + */ + public Builder<T> addColumnWithComplexValue(String infoHeader, Function<T, String> complexValueFunction) { + TableColumn<T, String> column = new TableColumn<>(infoHeader); + column.setCellValueFactory(cellData -> + new SimpleStringProperty(complexValueFunction.apply(cellData.getValue())) + ); + column.setStyle("-fx-alignment: CENTER"); + this.tableColumns.add(column); + return this; + } + /** * This method actually constructs the table by creating an TableDisplay object. * @return The table view, represented using an TableDisplay object. diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/CreatePlayerView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/CreatePlayerView.java index b7eb60f988d387c435faa4081d2f3c6ae4aa3d2d..30947754877071704ec83cfa210b0d0ff006d75e 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/CreatePlayerView.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/CreatePlayerView.java @@ -19,18 +19,26 @@ import javafx.scene.control.Button; import javafx.scene.control.TextField; import javafx.scene.image.*; import javafx.scene.layout.BorderPane; -import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; +/** + * The view for creating a player. This view therefore contains the character layout implementation and pop-ups + * for goals and stats. + * + * @author Trym Hamer Gudvangen + */ public class CreatePlayerView extends View<BorderPane> { private final CreatePlayerController createPlayerController; private TextField nameField; private Button continueButton, returnButton; + /** + * Creates the view for creating a player. + */ public CreatePlayerView() { super(BorderPane.class); createPlayerController = new CreatePlayerController(); @@ -73,9 +81,9 @@ public class CreatePlayerView extends View<BorderPane> { VBox leftVBox = new VBox(statsButton, goalsButton); leftVBox.setSpacing(20); leftVBox.setPadding(new Insets(300, 20, 0, 20)); - HBox leftHBox = new HBox(leftVBox); - leftHBox.setAlignment(Pos.CENTER_LEFT); - getParentPane().setLeft(leftHBox); + leftVBox.setAlignment(Pos.CENTER); + getParentPane().setLeft(leftVBox); + getParentPane().getLeft().setTranslateY(-200); statsButton.setOnAction(e -> new StatsPopUp()); @@ -112,13 +120,13 @@ public class CreatePlayerView extends View<BorderPane> { nameField.setMinWidth(200); continueButton = new Button("Continue"); - returnButton = new Button("Return"); - HBox viewButtons = new HBox(returnButton, continueButton); - returnButton.setAlignment(Pos.CENTER_LEFT); - continueButton.setAlignment(Pos.CENTER_RIGHT); - viewButtons.setSpacing(200); + returnButton = new Button("Back"); - VBox bottomBox = new VBox(nameField, viewButtons); + getParentPane().setBottom(returnButton); + getParentPane().getBottom().setTranslateY(-50); + getParentPane().getBottom().setTranslateX(10); + + VBox bottomBox = new VBox(nameField, continueButton); bottomBox.setSpacing(20); bottomBox.setAlignment(Pos.CENTER); bottomBox.setPadding(new Insets(0, 0, 0, 0)); @@ -159,7 +167,7 @@ public class CreatePlayerView extends View<BorderPane> { ImageView characterImageView = new ImageView(characterImage); INSTANCE.setCharacterImageView(characterImageView); - createPlayerController.goTo(NewGameView.class).handle(event); + createPlayerController.goTo(LoadGameView.class).handle(event); } catch (Exception e) { AlertDialog.showWarning(e.getMessage()); } @@ -167,6 +175,12 @@ public class CreatePlayerView extends View<BorderPane> { returnButton.setOnAction(e -> StageManager.getInstance().goBack()); } + /** + * Copies the image onto the writable image. + * @param image the image to copy + * @param writer the pixel writer + * @param yOffset the y offset + */ private void copyImageOnto(Image image, PixelWriter writer, int yOffset) { PixelReader reader = image.getPixelReader(); for (int y = 0; y < image.getHeight(); y++) { diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java index 715e930126add6ef7e7fc5dcaa394da14d1c6c0c..d4df12b733ef8de4db37e94681b0556c644d8bbb 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/HelpView.java @@ -22,6 +22,9 @@ public class HelpView extends View<VBox> { private final HelpController controller = new HelpController(); + /** + * Creates the help page. + */ public HelpView() { super(VBox.class); VBox parent = getParentPane(); diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewGameView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java similarity index 62% rename from src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewGameView.java rename to src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java index e4a5469cff642c6e9e718b708df66e7649df3c17..a4c2f3ba84ab8c86488377534a1f5b08cfdf3948 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewGameView.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java @@ -4,7 +4,7 @@ import static edu.ntnu.idatt2001.group_30.paths.PathsSingleton.INSTANCE; import edu.ntnu.idatt2001.group_30.paths.controller.NewGameController; import edu.ntnu.idatt2001.group_30.paths.controller.StageManager; -import edu.ntnu.idatt2001.group_30.paths.view.StoryDisplay; +import edu.ntnu.idatt2001.group_30.paths.view.components.StoryDisplay; import edu.ntnu.idatt2001.group_30.paths.view.components.common.DefaultButton; import edu.ntnu.idatt2001.group_30.paths.view.components.pop_up.AlertDialog; import java.io.File; @@ -25,19 +25,22 @@ import javafx.stage.FileChooser; * * @author Trym Hamer Gudvangen */ -public class NewGameView extends View<BorderPane> { +public class LoadGameView extends View<BorderPane> { private final NewGameController newGameController; private BorderPane titlePane; private VBox buttonVBox; private Button startButton; + private Button loadButton; + private Button newButton; + private HBox buttonBox; /** * The constructor of the View class. * It creates a new instance of the Pane that the View wraps. */ - public NewGameView() { + public LoadGameView() { super(BorderPane.class); newGameController = new NewGameController(); @@ -45,31 +48,46 @@ public class NewGameView extends View<BorderPane> { VBox mainContainer = createMainContainerVBox(titlePane); + if (INSTANCE.getStory() != null) { + try { + addStoryPane(); + } catch (IOException e) { + AlertDialog.showError(e.getMessage()); + } + } + setupParentPane(mainContainer); } + /** + * Adds the story pane to the view. + * @param titlePane The title pane of the view. + * @return The main container of the view. + */ private VBox createMainContainerVBox(BorderPane titlePane) { VBox mainContainer = new VBox(); mainContainer.getChildren().addAll(titlePane); - mainContainer.setAlignment(Pos.CENTER); - mainContainer.setSpacing(40); + mainContainer.setAlignment(Pos.TOP_CENTER); + mainContainer.setSpacing(100); Button backButton = new Button("Back"); backButton.setOnAction(e -> StageManager.getInstance().goBack()); + getParentPane().setBottom(backButton); startButton = DefaultButton.medium("Start game", newGameController.goTo(PlaythroughView.class)); startButton.setVisible(false); - HBox buttonBox = new HBox(10, backButton, startButton); - buttonBox.setAlignment(Pos.CENTER); - - VBox containerWithButtons = new VBox(mainContainer, buttonBox); + VBox containerWithButtons = new VBox(mainContainer, startButton); containerWithButtons.setSpacing(20); containerWithButtons.setAlignment(Pos.CENTER); return containerWithButtons; } + /** + * Sets up the parent pane of the view. + * @param mainContainer The main container of the view. + */ private void setupParentPane(VBox mainContainer) { getParentPane().setCenter(mainContainer); getParentPane().setStyle("-fx-background-color: #f5f5f5"); @@ -80,6 +98,10 @@ public class NewGameView extends View<BorderPane> { getParentPane().setPadding(new Insets(20)); } + /** + * Adds the story pane to the view. + * @return The story pane. + */ private BorderPane createTitlePane() { BorderPane titlePane = new BorderPane(); titlePane.setPadding(new Insets(20)); @@ -89,11 +111,12 @@ public class NewGameView extends View<BorderPane> { title.setStyle("-fx-font-size: 20px; -fx-font-weight: bold"); titlePane.setTop(title); BorderPane.setAlignment(title, Pos.TOP_CENTER); + titlePane.getTop().setTranslateY(-70); - Button loadButton = new Button("Load"); - Button newButton = new Button("New"); + loadButton = new Button("Load"); + newButton = new Button("New"); - HBox buttonBox = new HBox(10, loadButton, newButton); + buttonBox = new HBox(10, loadButton, newButton); buttonBox.setAlignment(Pos.CENTER); buttonVBox = new VBox(buttonBox); buttonVBox.setAlignment(Pos.CENTER); @@ -110,29 +133,7 @@ public class NewGameView extends View<BorderPane> { if (selectedFile != null) { try { newGameController.setStory(selectedFile); - VBox storyVBox = new StoryDisplay.Builder(INSTANCE.getStory()) - .addStoryName() - .addFileInfo(selectedFile) - .build(); - storyVBox.setAlignment(Pos.CENTER); - - Button pencilButton = createIconButton("/images/pencil.png", 16, 16); - Button xButton = createIconButton("/images/remove.png", 16, 16); - - HBox buttonIcons = new HBox(10, pencilButton, xButton); - buttonIcons.setAlignment(Pos.CENTER_LEFT); - - VBox storyContainer = new VBox(storyVBox, buttonIcons); - storyContainer.setAlignment(Pos.CENTER); - - xButton.setOnAction(event -> { - titlePane.getChildren().remove(storyContainer); - titlePane.setCenter(buttonBox); - startButton.setVisible(false); - }); - - titlePane.setCenter(storyContainer); - startButton.setVisible(true); + addStoryPane(); } catch (RuntimeException runtimeException) { AlertDialog.showError(runtimeException.getMessage()); } catch (IOException ex) { @@ -141,9 +142,19 @@ public class NewGameView extends View<BorderPane> { } }); + newButton.setOnAction(newGameController.goTo(NewStoryView.class)); + + this.titlePane = titlePane; return titlePane; } + /** + * Creates an icon button. + * @param imagePath The path to the image. + * @param width The width of the image. + * @param height The height of the image. + * @return The button. + */ private Button createIconButton(String imagePath, int width, int height) { Button button = new Button(); URL imageUrl = getClass().getResource(imagePath); @@ -157,4 +168,38 @@ public class NewGameView extends View<BorderPane> { } return button; } + + /** + * Adds the story pane to the view. + * @throws IOException If the story pane cannot be added. + */ + private void addStoryPane() throws IOException { + VBox storyVBox = new StoryDisplay.Builder(INSTANCE.getStory()) + .addStoryName() + .addFileInfo(INSTANCE.getStoryFile()) + .build(); + storyVBox.setAlignment(Pos.CENTER); + + Button pencilButton = createIconButton("/images/pencil.png", 16, 16); + Button xButton = createIconButton("/images/remove.png", 16, 16); + + HBox buttonIcons = new HBox(10, pencilButton, xButton); + buttonIcons.setAlignment(Pos.CENTER); + + VBox storyContainer = new VBox(storyVBox, buttonIcons); + storyContainer.setAlignment(Pos.CENTER); + + pencilButton.setOnAction(newGameController.goTo(NewStoryView.class)); + + xButton.setOnAction(event -> { + titlePane.getChildren().remove(storyContainer); + titlePane.setCenter(buttonBox); + startButton.setVisible(false); + + INSTANCE.setStory(null); + }); + + titlePane.setCenter(storyContainer); + startButton.setVisible(true); + } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewStoryView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewStoryView.java new file mode 100644 index 0000000000000000000000000000000000000000..eedaa1d4d4c259148d1d926a775dab26a37dae03 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/NewStoryView.java @@ -0,0 +1,188 @@ +package edu.ntnu.idatt2001.group_30.paths.view.views; + +import static edu.ntnu.idatt2001.group_30.paths.PathsSingleton.INSTANCE; + +import edu.ntnu.idatt2001.group_30.paths.controller.NewStoryController; +import edu.ntnu.idatt2001.group_30.paths.controller.StageManager; +import edu.ntnu.idatt2001.group_30.paths.model.Link; +import edu.ntnu.idatt2001.group_30.paths.model.Passage; +import edu.ntnu.idatt2001.group_30.paths.model.Story; +import edu.ntnu.idatt2001.group_30.paths.view.components.common.DefaultText; +import edu.ntnu.idatt2001.group_30.paths.view.components.pop_up.AlertDialog; +import edu.ntnu.idatt2001.group_30.paths.view.components.pop_up.PassagePopUp; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.PassageTable; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.TableDisplay; +import java.net.URL; +import java.util.Objects; +import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.control.TableView; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; + +/** + * This class contains the view for creating/writing a new story. It, therefore, contains the title and passages. + * The passages can be changed and the corresponding object variables such as links and actions can also be changed. + * + * @author Trym Hamer Gudvangen + */ +public class NewStoryView extends View<BorderPane> { + + private final NewStoryController newStoryController; + private String title = ""; + private Story story; + private final ObservableList<Passage> passages; + private final Button removePassageButton; + private final Button editPassageButton; + + /** + * The constructor to create the NewStoryView. + */ + public NewStoryView() { + super(BorderPane.class); + newStoryController = new NewStoryController(); + + if (INSTANCE.getStory() != null) { + story = INSTANCE.getStory(); + } + + if (story != null) title = story.getTitle(); + + passages = + story == null + ? FXCollections.observableArrayList() + : FXCollections.observableArrayList(story.getPassages()); + Text titleText = DefaultText.big("Create a new/edit a Story"); + + Text labelText = new Text("Story Title: "); + TextField textField = new TextField(title); + textField.setPromptText("Enter story title"); + + HBox titleBox = new HBox(labelText, textField); + titleBox.setSpacing(20); + + textField.setOnKeyTyped(event -> title = textField.getText()); + + titleBox.setAlignment(Pos.CENTER); + + PassageTable<Passage> passageTable = new PassageTable<>( + new TableDisplay.Builder<Passage>() + .addColumn("Name of Passage", "title") + .addColumn("Passage Content", "content") + .addColumnWithComplexValue( + "Links", + passage -> + passage == null + ? null + : passage.getLinks().stream().map(Link::getText).collect(Collectors.joining(", ")) + ) + ); + + passageTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + passageTable.setItems(passages); + passageTable.setMaxWidth(1000); + + removePassageButton = new Button("Remove Passage"); + removePassageButton.setDisable(true); + removePassageButton.setOnAction(e -> { + passages.forEach(passage -> + passage + .getLinks() + .removeIf(link -> + Objects.equals( + link.getReference(), + passageTable.getSelectionModel().getSelectedItem().getTitle() + ) + ) + ); + passages.remove(passageTable.getSelectionModel().getSelectedItem()); + }); + + editPassageButton = new Button("Edit Passage"); + editPassageButton.setDisable(true); + editPassageButton.setOnAction(e -> { + Passage selectedPassage = passageTable.getSelectionModel().getSelectedItem(); + if (selectedPassage != null) { + Passage updatedPassage = new PassagePopUp(passages, selectedPassage).getPassage(); + if (updatedPassage != null && !selectedPassage.equals(updatedPassage)) { + passages.forEach(passage -> + passage + .getLinks() + .replaceAll(link -> + link.getReference().equals(selectedPassage.getTitle()) + ? new Link(link.getText(), updatedPassage.getTitle()) + : link + ) + ); + passages.remove(selectedPassage); + passages.add(updatedPassage); + } + } + }); + + passageTable + .getSelectionModel() + .selectedItemProperty() + .addListener((obs, oldSelection, newSelection) -> { + removePassageButton.setDisable(newSelection == null); + editPassageButton.setDisable(newSelection == null); + }); + + Button addPassageButton = new Button(); + URL imageUrl = getClass().getResource("/images/plus.png"); + if (imageUrl != null) { + ImageView addIcon = new ImageView(new Image(imageUrl.toString())); + addIcon.setFitHeight(25); + addIcon.setFitWidth(25); + addPassageButton.setGraphic(addIcon); + } else { + System.err.println("Something is wrong with the trash image resource link"); + } + + VBox editTableButtons = new VBox(addPassageButton, removePassageButton, editPassageButton); + editTableButtons.setAlignment(Pos.CENTER); + editTableButtons.setSpacing(20); + + addPassageButton.setOnAction(event -> { + if (passages.isEmpty()) { + AlertDialog.showInformation( + "Every story needs an opening passage.", + "The opening passage" + " will by default be the first passage added." + ); + } + PassagePopUp passagePopUp = new PassagePopUp(passages); + if (passagePopUp.getPassage() != null) this.passages.addAll(passagePopUp.getPassage()); + }); + + Button saveButton = new Button("Save Story"); + saveButton.setOnAction(event -> { + try { + newStoryController.addStory(title, passages); + StageManager.getInstance().setCurrentView(new LoadGameView()); + } catch (Exception ex) { + AlertDialog.showWarning(ex.getMessage()); + } + }); + + VBox display = new VBox(titleText, titleBox, passageTable, saveButton); + display.setAlignment(Pos.CENTER); + display.setSpacing(10); + display.setPrefWidth(500); + + Button backButton = new Button("Back"); + backButton.setOnAction(newStoryController.goBack()); + + getParentPane().setCenter(display); + getParentPane().setBottom(backButton); + getParentPane().setRight(editTableButtons); + getParentPane().getRight().setTranslateX(-50); + } +} diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/PlaythroughView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/PlaythroughView.java index 09598a34a33ca34dd5868ab09a900217e393942d..0f9da678288c54ba019f4258fe16e8c9203c1363 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/PlaythroughView.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/PlaythroughView.java @@ -1,6 +1,6 @@ package edu.ntnu.idatt2001.group_30.paths.view.views; -import edu.ntnu.idatt2001.group_30.paths.controller.PlaytroughController; +import edu.ntnu.idatt2001.group_30.paths.controller.PlaythroughController; import edu.ntnu.idatt2001.group_30.paths.model.Link; import edu.ntnu.idatt2001.group_30.paths.model.PlaythroughState; import edu.ntnu.idatt2001.group_30.paths.model.goals.Goal; @@ -35,7 +35,7 @@ import javafx.scene.text.Text; */ public class PlaythroughView extends View<VBox> { - private final PlaytroughController controller; + private final PlaythroughController controller; /** * Creates a new instance of the view. @@ -44,7 +44,7 @@ public class PlaythroughView extends View<VBox> { */ public PlaythroughView() { super(VBox.class); - controller = new PlaytroughController(); + controller = new PlaythroughController(); /* * The view is divided into three parts: @@ -54,7 +54,7 @@ public class PlaythroughView extends View<VBox> { * | | player & game | * | | info | * | | --------------- | - * | play-trough window | goals | + * | play-through window | goals | * | | --------------- | * | | inventory | * | | | @@ -317,9 +317,9 @@ public class PlaythroughView extends View<VBox> { content.setSpacing(20); content.setPadding(new Insets(0, 0, 0, 20)); - ObservableMap<Goal, Boolean> goals = controller.getGoals(); + ObservableMap<Goal<?>, Boolean> goals = controller.getGoals(); goals.addListener( - (MapChangeListener<Goal, Boolean>) change -> { + (MapChangeListener<Goal<?>, Boolean>) change -> { showGoals(goals, content); } ); @@ -388,7 +388,7 @@ public class PlaythroughView extends View<VBox> { * @param goals The goals to show. * @param content The pane to show the goals in. */ - private void showGoals(ObservableMap<Goal, Boolean> goals, Pane content) { + private void showGoals(ObservableMap<Goal<?>, Boolean> goals, Pane content) { content.getChildren().clear(); goals.forEach((goal, completed) -> { HBox goalBox = new HBox(); diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/View.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/View.java index 0ba45db74582e52ac25b7b09f433cb7dc6d7e523..e549e73a5ab571aae955301d855b93469f3804ab 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/View.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/View.java @@ -7,7 +7,6 @@ import java.util.Objects; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.layout.*; -import javafx.scene.shape.SVGPath; /** * A View is a wrapper for a JavaFX Pane. @@ -40,7 +39,6 @@ public class View<T extends Pane> { } catch ( InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e ) { - //TODO: better error handling e.printStackTrace(); } } diff --git a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/ViewFactory.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/ViewFactory.java index ce9cabadbe943f5063446ede9b28fa1894fc4ae0..9674ac5f1536e3f4d80b3f4cfe498d80661cb24b 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/ViewFactory.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/ViewFactory.java @@ -2,8 +2,17 @@ package edu.ntnu.idatt2001.group_30.paths.view.views; import java.lang.reflect.InvocationTargetException; +/** + * A factory for creating views. + */ public class ViewFactory { + /** + * Given a class of a view, this method creates an instance of that view. + * @param viewClass The class of the view to be created. + * @return An instance of the view. + * @param <T> The type of the view. + */ public static <T extends View<?>> T createView(Class<T> viewClass) { try { return viewClass.getDeclaredConstructor().newInstance(); diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index e7626c24e21cbd777c172d66d1187bf7486cb596..566bcec21c7ba5336dc035ea8de557aadf69cf00 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -6,6 +6,7 @@ module edu.ntnu.idatt2001.group_30.paths { exports edu.ntnu.idatt2001.group_30.paths.view; exports edu.ntnu.idatt2001.group_30.paths.model; exports edu.ntnu.idatt2001.group_30.paths.model.goals; + exports edu.ntnu.idatt2001.group_30.paths.model.actions; exports edu.ntnu.idatt2001.group_30.paths.view.components; exports edu.ntnu.idatt2001.group_30.paths.view.components.common; exports edu.ntnu.idatt2001.group_30.paths.view.components.pane; diff --git a/src/main/resources/stylesheet.css b/src/main/resources/stylesheet.css index 2d16dd20a814676381d110b5100cdbcad85c47eb..8aeae865e557fef7f334a291f96731308bd7f609 100644 --- a/src/main/resources/stylesheet.css +++ b/src/main/resources/stylesheet.css @@ -1,10 +1,36 @@ +* { + /*-fx-font-family: Arial;*/ + -fx-transition: all 0.3s ease-in-out; +} + .border-pane { background-color: #f5f5f5; } +.label { + -fx-font-size: 14px; + -fx-font-weight: bold; + -fx-padding: 5px; +} + +.text-field { + -fx-padding: 8px; + -fx-border-color: #ccc; + -fx-border-width: 1px; + -fx-border-radius: 5px; +} + + +.text-field:focused { + -fx-border-color: #0077ff; +} + + + #title { - -fx-font-size: 20px; + -fx-font-size: 22px; -fx-font-weight: bold; + -fx-color: #2c3e50; } #player-container, #goal-container { @@ -75,7 +101,6 @@ Button { -fx-border-color: #303f9f; -fx-border-width: 1px; -fx-padding: 10 20; - -fx-font-weight: bold; } Button:hover { diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/GameTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/GameTest.java index 7c6cdd07e3a182b89bc5350d3fa10daf6c039b82..093517875e56dcadcc3b7817896dc990b3209219 100644 --- a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/GameTest.java +++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/GameTest.java @@ -22,7 +22,7 @@ public class GameTest { Passage attackPassage; Story story; - List<Goal> goals; + List<Goal<?>> goals; @BeforeEach void setup() { diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java index fd49df0b77d10fee055a9072165ac5806dd63a88..d90ddb67c9bdb85ec0620905778dfc576218d61b 100644 --- a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java +++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/PlaythroughTest.java @@ -18,7 +18,7 @@ class PlaythroughTest { openingPassage = new Passage("Opening passage", "This is the opening passage"); Player player = new Player("Player", 10, 20, 30); Story story = new Story("My story", openingPassage); - List<Goal> goals = List.of(new GoldGoal(50)); + List<Goal<?>> goals = List.of(new GoldGoal(50)); Game game = new Game(player, story, goals); playthrough = new Playthrough(game); diff --git a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java index d6815495ee00802ed3a0bc64e5d0f9c02c2c5161..0adf5335ce2c7717b5f744bd193f3708e668d228 100644 --- a/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java +++ b/src/test/java/edu/ntnu/idatt2001/group_30/paths/model/filehandling/StoryFileWriterImplTest.java @@ -220,7 +220,7 @@ public class StoryFileWriterImplTest { Assertions.assertThrows( NullPointerException.class, () -> { - storyFileWriter.create(story, null); + storyFileWriter.create(story, (String) null); } ); }