From 57eec554cf0ec14b872111d6d3654016a2c0cbb8 Mon Sep 17 00:00:00 2001 From: Elisabeth Berg Date: Sun, 24 May 2026 19:17:18 +0200 Subject: [PATCH 1/3] Added ExchangeObserver class --- src/main/java/Model/ExchangeObserver.java | 16 ++++++++++++++++ .../compile/default-compile/inputFiles.lst | 1 + 2 files changed, 17 insertions(+) create mode 100644 src/main/java/Model/ExchangeObserver.java diff --git a/src/main/java/Model/ExchangeObserver.java b/src/main/java/Model/ExchangeObserver.java new file mode 100644 index 0000000..ad3f6a5 --- /dev/null +++ b/src/main/java/Model/ExchangeObserver.java @@ -0,0 +1,16 @@ +package Model; + +/** + * Observer interface for the Exchange subject. + * Implement this interface to receive notifications whenever the exchange + * state changes (week advances, a trade is committed). + */ +public interface ExchangeObserver { + + /** + * Called by the Exchange after its state has changed. + * + * @param exchange the Exchange that triggered the notification + */ + void onExchangeUpdated(Exchange exchange); +} diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst index fc20747..f40803d 100644 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -1,5 +1,6 @@ C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Controller\StockFileHandler.java C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Model\Exchange.java +C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Model\ExchangeObserver.java C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Model\Player.java C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Model\Portfolio.java C:\Users\elisa\Downloads\progdel1\Programmering2_mappe_v26\src\main\java\Model\Purchase.java From d0b7b3fcdc94403c59f5125a63cf96ddf71b22bf Mon Sep 17 00:00:00 2001 From: Elisabeth Berg Date: Sun, 24 May 2026 19:17:39 +0200 Subject: [PATCH 2/3] Updated Exchange class for observer --- src/main/java/Model/Exchange.java | 34 +++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/main/java/Model/Exchange.java b/src/main/java/Model/Exchange.java index 320fae8..daf57c3 100644 --- a/src/main/java/Model/Exchange.java +++ b/src/main/java/Model/Exchange.java @@ -13,6 +13,9 @@ public class Exchange { private final Map stockMap; private final Random random; + // Registered observers + private final List observers = new ArrayList<>(); + public Exchange(String name, List stocks) { this.name = name; this.week = 1; @@ -22,9 +25,26 @@ public Exchange(String name, List stocks) { for (Stock stock : stocks) { stockMap.put(stock.getSymbol(), stock); } + } + + // ---- Observer ---- + + public void addObserver(ExchangeObserver observer) { + if (observer != null && !observers.contains(observer)) { + observers.add(observer); + } + } + public void removeObserver(ExchangeObserver observer) { + observers.remove(observer); } - + + private void notifyObservers() { + for (ExchangeObserver observer : observers) { + observer.onExchangeUpdated(this); + } + } + public String getName() { return name; } @@ -57,7 +77,7 @@ public List findStocks(String searchTerm) { public Transaction buy(String symbol, BigDecimal quantity, Player player) { Stock stock = getStock(symbol); - + // unngÄ nullpointerexception if (stock == null) { return null; @@ -71,7 +91,9 @@ public Transaction buy(String symbol, BigDecimal quantity, Player player) { // committer til player purchase.commit(player); - + + notifyObservers(); + return purchase; } @@ -86,7 +108,9 @@ public Transaction sell(Share share, Player player) { // commiter til player sale.commit(player); - + + notifyObservers(); + return sale; } @@ -108,6 +132,8 @@ public void advance() { stock.addNewSalesPrice(newPrice); } } + + notifyObservers(); } public List getGainers(int limit) { // viser "vinnerne" From b6c27e2b919114eb80a89b445d3dd28436145b70 Mon Sep 17 00:00:00 2001 From: Elisabeth Berg Date: Sun, 24 May 2026 19:17:56 +0200 Subject: [PATCH 3/3] Updated MainGameScene class for observer --- src/main/java/View/MainGameScene.java | 144 +++++++++++++------------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/src/main/java/View/MainGameScene.java b/src/main/java/View/MainGameScene.java index 00dfac2..9b57bc9 100644 --- a/src/main/java/View/MainGameScene.java +++ b/src/main/java/View/MainGameScene.java @@ -12,14 +12,19 @@ import java.math.BigDecimal; import java.util.List; -public class MainGameScene { +/** + * Main game UI. Implements ExchangeObserver so the view automatically refreshes + * whenever the Exchange notifies it of a state change (week advance or trade). + */ +public class MainGameScene implements ExchangeObserver { + private Scene scene; private Exchange exchange; private Player player; private Runnable onExit; private Label statusLabel; - - // References to UI components for refreshing + + // References to UI components that need refreshing private TableView portfolioTable; private ListView holdingsList; private TableView historyTable; @@ -29,9 +34,23 @@ public MainGameScene(Exchange exchange, Player player, Runnable onExit) { this.exchange = exchange; this.player = player; this.onExit = onExit; + + // Register this view as an observer of the exchange + this.exchange.addObserver(this); + this.scene = createScene(); } + /** + * Called automatically by Exchange whenever its state changes. + * Refreshes all UI elements to reflect the latest data. + */ + @Override + public void onExchangeUpdated(Exchange exchange) { + updateStatus(); + refreshAllUI(); + } + private Scene createScene() { VBox root = new VBox(0); @@ -49,12 +68,13 @@ private Scene createScene() { Button nextWeekBtn = new Button("Next week"); nextWeekBtn.getStyleClass().addAll("action-button"); - nextWeekBtn.setOnAction(e -> advance()); + nextWeekBtn.setOnAction(e -> exchange.advance()); // observer handles the UI update Button exitBtn = new Button("Exit"); exitBtn.getStyleClass().add("exit-button"); exitBtn.setOnAction(e -> { if (confirm("Exit Game?", "Final Net Worth: $" + formatMoney(getNetWorth()))) { + exchange.removeObserver(this); // clean up before closing onExit.run(); } }); @@ -156,11 +176,9 @@ private VBox createPortfolioPanel() { alert("Error", "Select a holding to sell."); return; } - Transaction trans = exchange.sell(selected.s, player); + Transaction trans = exchange.sell(selected.s, player); // observer fires refresh if (trans != null && trans.isCommitted()) { showConfirmation("Sale successful", trans); - updateStatus(); - refreshAllUI(); } else { alert("Failed", "Could not complete the sale."); } @@ -226,14 +244,12 @@ private VBox createBuyTab() { return; } BigDecimal qty = new BigDecimal(qtyField.getText()); - Transaction trans = exchange.buy(s.getSymbol(), qty, player); + Transaction trans = exchange.buy(s.getSymbol(), qty, player); // observer fires refresh if (trans != null && trans.isCommitted()) { showConfirmation("Purchase successful", trans); stockField.clear(); qtyField.clear(); infoLabel.setText(""); - updateStatus(); - refreshAllUI(); } else { alert("Failed", "Insufficient funds or error"); } @@ -247,62 +263,50 @@ private VBox createBuyTab() { } private VBox createSellTab() { - VBox box = new VBox(10); - box.getStyleClass().add("content-area"); - - Label heading = new Label("Your Holdings:"); + VBox box = new VBox(10); + box.getStyleClass().add("content-area"); - holdingsList = new ListView<>(); - holdingsList.setPrefHeight(400); + Label heading = new Label("Your Holdings:"); - holdingsList.setCellFactory(lv -> new ListCell() { - @Override - protected void updateItem(Share s, boolean empty) { - super.updateItem(s, empty); + holdingsList = new ListView<>(); + holdingsList.setPrefHeight(400); - if (empty || s == null) { - setText(null); - } else { - setText( - s.getStock().getSymbol() + " - " + - s.getQuantity() + " @ $" + - formatMoney(s.getStock().getSalesPrice()) - ); + holdingsList.setCellFactory(lv -> new ListCell() { + @Override + protected void updateItem(Share s, boolean empty) { + super.updateItem(s, empty); + if (empty || s == null) { + setText(null); + } else { + setText( + s.getStock().getSymbol() + " - " + + s.getQuantity() + " @ $" + + formatMoney(s.getStock().getSalesPrice()) + ); + } } - } - }); - - updateHoldingsList(holdingsList); - - Button sellBtn = new Button("Sell Selected"); - - sellBtn.setOnAction(e -> { - Share selected = holdingsList.getSelectionModel().getSelectedItem(); - - if (selected == null) { - alert("Error", "Select a holding to sell"); - return; - } - - Transaction trans = exchange.sell(selected, player); - - if (trans != null && trans.isCommitted()) { - showConfirmation("Sale successful", trans); - refreshAllUI(); - } else { - alert("Failed", "Could not complete sale"); - } - }); + }); - box.getChildren().addAll( - heading, - holdingsList, - sellBtn - ); + updateHoldingsList(holdingsList); - return box; -} + Button sellBtn = new Button("Sell Selected"); + sellBtn.setOnAction(e -> { + Share selected = holdingsList.getSelectionModel().getSelectedItem(); + if (selected == null) { + alert("Error", "Select a holding to sell"); + return; + } + Transaction trans = exchange.sell(selected, player); // observer fires refresh + if (trans != null && trans.isCommitted()) { + showConfirmation("Sale successful", trans); + } else { + alert("Failed", "Could not complete sale"); + } + }); + box.getChildren().addAll(heading, holdingsList, sellBtn); + return box; + } private VBox createHistoryPanel() { VBox panel = new VBox(10); @@ -317,7 +321,8 @@ private VBox createHistoryPanel() { weekFilterCombo.setOnAction(e -> updateHistory( historyTable, - weekFilterCombo.getValue() == null || weekFilterCombo.getValue() == 0 ? null : weekFilterCombo.getValue() + weekFilterCombo.getValue() == null || weekFilterCombo.getValue() == 0 + ? null : weekFilterCombo.getValue() )); HBox filterRow = new HBox(8); @@ -394,13 +399,8 @@ private void updatePortfolio(TableView table) { } private void updateHoldingsList(ListView list) { - ObservableList items = - FXCollections.observableArrayList(); - - items.addAll( - player.getPortfolio().getShares() - ); - + ObservableList items = FXCollections.observableArrayList(); + items.addAll(player.getPortfolio().getShares()); list.setItems(items); } @@ -457,19 +457,15 @@ private void refreshAllUI() { updateHoldingsList(holdingsList); } if (historyTable != null) { - updateHistory(historyTable, weekFilterCombo != null && weekFilterCombo.getValue() != null ? weekFilterCombo.getValue() : null); + updateHistory(historyTable, + weekFilterCombo != null && weekFilterCombo.getValue() != null + ? weekFilterCombo.getValue() : null); if (weekFilterCombo != null) { updateWeekCombo(weekFilterCombo); } } } - private void advance() { - exchange.advance(); - updateStatus(); - refreshAllUI(); - } - private BigDecimal getNetWorth() { return player.getMoney().add(player.getPortfolio().getNetWorth()); }