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 f9e49bc5dcc03c2eb2fedb6d120878ef1df87a5e..d34f98274239ae9ddef55fb4726d51f88079a9a8 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 @@ -5,6 +5,8 @@ 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; @@ -23,4 +25,5 @@ public class NewGameController extends Controller { 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 index 80537a9b8aec8cdb999af750fbb295120aaa15aa..481a23edb0f9436c73062b01f49c1ead77fe5064 100644 --- 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 @@ -7,6 +7,7 @@ import edu.ntnu.idatt2001.group_30.paths.view.views.NewStoryView; import javafx.stage.FileChooser; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; @@ -37,6 +38,10 @@ public class NewStoryController extends Controller{ 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/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..00247c3ce451807c90630830162f3b1d558e6d97 --- /dev/null +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/components/pop_up/LinkPopUp.java @@ -0,0 +1,79 @@ +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 javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; + +public class LinkPopUp { + + private TextField textField; + private TextField referenceField; + private Button saveButton; + private ObservableList<Passage> passages; + private ObservableList<Link> links; + + private Link link; + + public LinkPopUp(ObservableList<Passage> passages, ObservableList<Link> links) { + this.passages = passages; + this.links = links; + + textField = new TextField(); + textField.setPromptText("Enter the text of the link"); + + referenceField = new TextField(); + referenceField.setPromptText("Enter the reference of the link"); + + saveButton = new Button("Save"); + + ComboBox<Action<?>> actionComboBox = new ComboBox<>(null); + Button addActionButton = new Button("Add Action"); + addActionButton.setOnAction(e -> { + if (actionComboBox.getValue() != null) { + //TODO: add the action to the link + actionComboBox.setValue(null); + } + }); + + VBox content = new VBox( + new Label("Link Text:"), + textField, + new Label("Link Reference:"), + referenceField, + new Label("Actions:"), + actionComboBox, + addActionButton, + saveButton + ); + + content.setAlignment(Pos.CENTER); + content.setSpacing(20); + + PopUp<VBox, ?> popUp = PopUp + .<VBox>create() + .withTitle("Create a Link") + .withoutCloseButton() + .withContent(content) + .withDialogSize(400, 500); + + saveButton.setOnAction(e -> { + if (textField.getText().isBlank() || referenceField.getText().isBlank()) { + AlertDialog.showWarning("The text or reference cannot be blank."); + } else { + link = new Link(textField.getText(), referenceField.getText()); + + popUp.close(); + } + }); + + popUp.showAndWait(); + } + + 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 index 1bf38ef86cad79ddad51112c42d5a8e1d893660c..f549f821e9be8d3d624e70519ee4f42a7d3b6c64 100644 --- 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 @@ -1,19 +1,40 @@ package edu.ntnu.idatt2001.group_30.paths.view.components.pop_up; import edu.ntnu.idatt2001.group_30.paths.model.Passage; +import edu.ntnu.idatt2001.group_30.paths.model.Link; +import edu.ntnu.idatt2001.group_30.paths.model.actions.Action; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.LinkTable; +import edu.ntnu.idatt2001.group_30.paths.view.components.table.PassageTable; +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; -public class PassagePopUp { +import java.util.stream.Collectors; - private TextField titleField; - private TextArea contentArea; - private Button saveButton; +/** + * This class contains a pop-up for creating a new passage. + * + * @author Trym Hamer Gudvangen + */ +public class PassagePopUp { + private final TextField titleField; + private final TextArea contentArea; + private final Button saveButton; + private final Button removeLinkButton; + private final LinkTable<Link> linkTable; + private final ObservableList<Passage> passages; + private final ObservableList<Link> links; + private Passage passage; + public PassagePopUp(ObservableList<Passage> passages) { + this.passages = passages; + this.links = FXCollections.observableArrayList(); - public PassagePopUp() { titleField = new TextField(); titleField.setPromptText("Enter the title of the passage"); @@ -22,11 +43,34 @@ public class PassagePopUp { 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); + + removeLinkButton = new Button("Remove Link"); + removeLinkButton.setDisable(true); + + removeLinkButton.setOnAction(e -> links.remove(linkTable.getSelectionModel().getSelectedItem())); + linkTable.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> + removeLinkButton.setDisable(newSelection == null)); + + Button addLinkButton = new Button("Add Link"); + HBox linkTableButtonHBox = new HBox(addLinkButton, removeLinkButton); + linkTableButtonHBox.setAlignment(Pos.CENTER); + + addLinkButton.setOnAction(e -> this.links.add(new LinkPopUp(passages, links).getLink())); + VBox content = new VBox( new Label("Passage Title:"), titleField, new Label("Passage Content:"), contentArea, + new Label("Links:"), + linkTable, + linkTableButtonHBox, saveButton ); @@ -39,18 +83,29 @@ public class PassagePopUp { .withoutCloseButton() .withContent(content) .withDialogSize(400, 500); + ; saveButton.setOnAction(e -> { if (titleField.getText().isBlank() || contentArea.getText().isBlank()) { AlertDialog.showWarning("The title or content cannot be blank."); } else { - Passage newPassage = new Passage(titleField.getText(), contentArea.getText()); + this.passage = new Passage(titleField.getText(), contentArea.getText()); //TODO: save the new passage + //TODO: add links from the table to the new passage + popUp.close(); } }); popUp.showAndWait(); } + + /** + * This method retrieves the passages created from the pop-up. + * @return Passags 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/views/LoadGameView.java b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java index 8131982eb317ffeae4bffeaa46a78966f492d937..ea9b732a8b1e5735a29b1841ea589bab968a57b0 100644 --- a/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java +++ b/src/main/java/edu/ntnu/idatt2001/group_30/paths/view/views/LoadGameView.java @@ -48,14 +48,22 @@ public class LoadGameView extends View<BorderPane> { VBox mainContainer = createMainContainerVBox(titlePane); + if(INSTANCE.getStory() != null) { + try { + addStoryPane(); + } catch (IOException e) { + AlertDialog.showError(e.getMessage()); + } + } + setupParentPane(mainContainer); } 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()); @@ -90,6 +98,7 @@ public class LoadGameView 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); loadButton = new Button("Load"); newButton = new Button("New"); @@ -156,9 +165,7 @@ public class LoadGameView extends View<BorderPane> { VBox storyContainer = new VBox(storyVBox, buttonIcons); storyContainer.setAlignment(Pos.CENTER); - pencilButton.setOnAction(event -> { - StageManager.getInstance().setCurrentView(new NewStoryView()); - }); + pencilButton.setOnAction(newGameController.goTo(NewStoryView.class)); xButton.setOnAction(event -> { titlePane.getChildren().remove(storyContainer); 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 index 4332df530ebe4ef099860267cd85b0bd4225113f..6fe9c962a56e492fefc728d0513f408bd1d1804e 100644 --- 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 @@ -28,19 +28,18 @@ import javafx.scene.text.Text; import java.net.URL; import java.util.stream.Collectors; -//TODO: Add message that first passage will be opening passage - 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; + public NewStoryView() { super(BorderPane.class); + newStoryController = new NewStoryController(); if (INSTANCE.getStory() != null) { @@ -72,14 +71,24 @@ public class NewStoryView extends View<BorderPane> { PassageTable<Passage> passageTable = new PassageTable<>(new TableDisplay.Builder<Passage>() .addColumn("Name of Passage", "title") .addColumn("Passage Content", "content") - .addColumnWithComplexValue("Links", passage -> passage.getLinks().stream() - .map(Link::getText) - .collect(Collectors.joining(", ")))); + .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.remove(passageTable.getSelectionModel().getSelectedItem())); + passageTable.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> + removePassageButton.setDisable(newSelection == null)); + + Button addPassageButton = new Button(); URL imageUrl = getClass().getResource("/images/plus.png"); if (imageUrl != null) { @@ -91,24 +100,28 @@ public class NewStoryView extends View<BorderPane> { System.err.println("Something is wrong with the trash image resource link"); } - addPassageButton.setOnAction(event -> new PassagePopUp()); + 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(INSTANCE.getStory() == null ? + FXCollections.observableArrayList() : FXCollections.observableArrayList(INSTANCE.getStory().getPassages())); + if(passagePopUp.getPassage() != null) this.passages.addAll(passagePopUp.getPassage()); + }); Button saveButton = new Button("Save"); saveButton.setOnAction(event -> { try { - - //TODO: if everything goes right, give a little feedback and - // then take back to load with story selected - // Add passage with links newStoryController.addStory(title, passages); - - } catch (Exception ex) { + StageManager.getInstance().setCurrentView(new LoadGameView()); + } + catch (Exception ex) { AlertDialog.showWarning(ex.getMessage()); } - StageManager.getInstance().setCurrentView(new LoadGameView()); }); - VBox display = new VBox(titleText, titleBox, passageTable, addPassageButton, saveButton); + VBox display = new VBox(titleText, titleBox, passageTable, addPassageButton, removePassageButton, saveButton); display.setAlignment(Pos.CENTER); display.setSpacing(10); display.setPrefWidth(500); @@ -118,10 +131,6 @@ public class NewStoryView extends View<BorderPane> { getParentPane().setCenter(display); getParentPane().setBottom(backButton); - - } - - } 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/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;