From 517518d9049188b956bd6cbc37d039e3c8b3d2f5 Mon Sep 17 00:00:00 2001
From: Roar Sets up necessary components and shows the first view
* of the application: {@link StartView}. Uses a {@link LanguageManager} for methods to change text dynamically. Creates the player and exchange to be used by the game from
+ * data from the {@link GameSetupController}. Creates the player and exchange to be used by the game from
- * data from the {@link GameSetupController}. MarketView lets the player perform {@link no.ntnu.gruppe53.model.Purchase} transactions. MarketView lets the player perform {@link Purchase} transactions. Contains the data from a player's {@link no.ntnu.gruppe53.model.Portfolio}. PortfolioView lets theEndView player perform
+ * {@link no.ntnu.gruppe53.model.Sale} transactions. Contains the data from a player's {@link Portfolio}. PortfolioView lets theEndView player perform {@link Sale} transactions. TransactionArchiveView contains data from
+ * {@link no.ntnu.gruppe53.model.TransactionArchive} TransactionArchiveView contains data from {@link TransactionArchive} Binds functionality to exposed buttons and lists in views. Sets subscriptions for observable values for views. Sets the method for setting the selected language locale for the footer. Binds functionality to exposed buttons and lists in views. Sets subscriptions for observable values for views. Sets the method for setting the selected language locale for the footer. Utilizes the buy method from {@link Exchange}. Utilizes the buy method from {@link Exchange}. Lets the {@link Player} set their name, starting money
* and provide a .csv file of {@link Stock} data to populate
* the {@link Exchange}. Uses default values if the player does not enter their desired values:
- *
- *
Uses default values if the player does not enter their desired values: + *
Contains three choices: *
Uses a {@link LanguageManager} to change the UI language.
*/ public class StartViewController { - /** - * Handles the events when "New Game" and "Quit" is pressed. - * - * @param view the StartView to be displayed - * @param vm the {@link ViewController} to handle switching of views - */ - public StartViewController(StartView view, ViewController vm) { - view.setOnNewGame(() -> { - GameController gameController = new GameController(vm); - gameController.startNewGame(); - }); - - view.setOnLanguage(() -> { - LanguageManager lm = LanguageManager.getInstance(); - ListUses a {@link HashMap} as an archive for registered views that * are possible to switch between.
*/ public class ViewController { - private final Stage stage; - private final Scene scene; - private final MapUses a {@link BorderPane} layout for views.
- */ - public ViewController(Stage stage) { - this.stage = stage; - this.mainLayout = new BorderPane(); - this.scene = new Scene(mainLayout, 1200, 900); - this.stage.setScene(scene); - } + /** + * Initializes a ViewController using the {@link Stage} as the first default view. + * + *Uses a {@link BorderPane} layout for views.
+ */ + public ViewController(Stage stage) { + this.stage = stage; + this.mainLayout = new BorderPane(); + Scene scene = new Scene(mainLayout, 1200, 900); + this.stage.setScene(scene); + } - /** - * Returns the stage of the ViewController. - * - * @return the stage of the ViewController. - */ - public Stage getStage() { - return this.stage; - } + /** + * Returns the stage of the ViewController. + * + * @return the stage of the ViewController. + */ + public Stage getStage() { + return this.stage; + } - /** - * Sets the top and bottom part of the BorderPane. - *Uses {@link NavigationBar} as the top bar, - * and {@link FooterBar} as the bottom bar.
- */ - public void setGlobalPanels(NavigationBar navigationBar, FooterBar footerBar) { - this.mainLayout.setTop(navigationBar); - this.mainLayout.setBottom(footerBar); - } + /** + * Sets the top and bottom part of the BorderPane. + * + *Uses {@link NavigationBar} as the top bar, + * and {@link FooterBar} as the bottom bar.
+ */ + public void setGlobalPanels(NavigationBar navigationBar, FooterBar footerBar) { + this.mainLayout.setTop(navigationBar); + this.mainLayout.setBottom(footerBar); + } - /** - * Adds a view to the stored archive of possible views. - * - * @param name the name/key to refer to the view when switching view - * @param view the view to be added - */ - public void addView(String name, Parent view) { - views.put(name, view); - } + /** + * Adds a view to the stored archive of possible views. + * + * @param name the name/key to refer to the view when switching view + * @param view the view to be added + */ + public void addView(String name, Parent view) { + views.put(name, view); + } - /** - * Switches the to the given view based on the string key - * stored in the view archive. - *Only switches the center pane.
- * - * @param name the name/key of the view to switch to - */ - public void switchView(String name) { - Parent view = views.get(name); + /** + * Switches the to the given view based on the string key + * stored in the view archive. + * + *Only switches the center pane.
+ * + * @param name the name/key of the view to switch to + */ + public void switchView(String name) { + Parent view = views.get(name); - if (view == null) { - throw new IllegalArgumentException("No views found matching: " + name); - } - - mainLayout.setCenter(view); + if (view == null) { + throw new IllegalArgumentException("No views found matching: " + name); } + + mainLayout.setCenter(view); + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/model/Exchange.java b/millions/src/main/java/no/ntnu/gruppe53/model/Exchange.java index f20919c..86fef14 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/model/Exchange.java +++ b/millions/src/main/java/no/ntnu/gruppe53/model/Exchange.java @@ -1,252 +1,284 @@ package no.ntnu.gruppe53.model; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.stream.Collectors; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.*; -import java.util.stream.Collectors; - /** - * Represents an exchange/market containing {@link Stock}s and allows a {@link Player} to buy {@link Share}s - * of said stocks. - *Contains method to advance the week of the market, finding stocks, gainers, and losers on the exchange.
+ * Represents an exchange/market containing {@link Stock}s and allows + * a {@link Player} to buy {@link Share}s of said stocks. + * + *Contains method to advance the week of the market, finding stocks, + * gainers, and losers on the exchange.
*/ public class Exchange { - private final String name; - private int week; - private final MapValidates that the values are proper before creating the exchange.
- *Initializes factories for creating a {@link Transaction}.
- * - * @param name the name of the exchange - * @param stocks the list of stocks to be tradeable on the exchange - * @throws IllegalArgumentException if exchange is null or blank, if list of stocks is null, or if - * the list of stocks contains a null or duplicate symbol stock - */ - public Exchange(String name, ListValidates that the values are proper before creating the exchange.
+ * + *Initializes factories for creating a {@link Transaction}.
+ * + * @param name the name of the exchange + * @param stocks the list of stocks to be tradeable on the exchange + * @throws IllegalArgumentException if exchange is null or blank, if list of stocks is null, or if + * the list of stocks contains a null or duplicate symbol stock + */ + public Exchange(String name, ListReturns {@code true} if it does,v{@code false} otherwise.
- * - * @param symbol the symbol/ticker of the stock - * @return {@code true} if the exchange contains the stock, otherwise {@code false} - */ - public boolean hasStock(String symbol) { - return stockMap.containsKey(symbol); - } + for (Stock stock : stocks) { + if (stock == null) { + throw new IllegalArgumentException("Stock cannot be null"); + } - /** - * Returns the stock object matching the given symbol/ticker. - * - * @param symbol the stock symbol/ticker - * @return the stock object matching the symbol/ticker - * @throws IllegalArgumentException if search symbol is null or symbol is not in stockMap - */ - public Stock getStock(String symbol) { - if (symbol == null || !stockMap.containsKey(symbol)) { - throw new IllegalArgumentException("Stock not found: " + symbol); - } - return stockMap.get(symbol); + if (stockMap.containsKey(stock.getSymbol())) { + throw new IllegalArgumentException("Duplicate stock symbol: " + stock.getSymbol()); + } + + stockMap.put(stock.getSymbol(), stock); + this.stocks.add(stock); } - /** - * Returns an {@link ObservableList} of the list of stocks for JavaFX to observe. - * - * @return an observable list of the stocks in the exchange - */ - public ObservableListReturns {@code true} if it does,v{@code false} otherwise.
+ * + * @param symbol the symbol/ticker of the stock + * @return {@code true} if the exchange contains the stock, otherwise {@code false} + */ + public boolean hasStock(String symbol) { + return stockMap.containsKey(symbol); + } + + /** + * Returns the stock object matching the given symbol/ticker. + * + * @param symbol the stock symbol/ticker + * @return the stock object matching the symbol/ticker + * @throws IllegalArgumentException if search symbol is null or symbol is not in stockMap + */ + public Stock getStock(String symbol) { + if (symbol == null || !stockMap.containsKey(symbol)) { + throw new IllegalArgumentException("Stock not found: " + symbol); + } + return stockMap.get(symbol); + } + + /** + * Returns an {@link ObservableList} of the list of stocks for JavaFX to observe. + * + * @return an observable list of the stocks in the exchange + */ + public ObservableListCreates a {@link Purchase} transaction for the + * purchase.
+ * + * @param symbol the symbol/ticker of the stock + * @param quantity the quantity of shares to buy for said stock + * @param player the player making the purchase + * @return a purchase transaction containing all details of the purchase + * @throws IllegalArgumentException if player or quantity is null + */ + public Transaction buy(String symbol, BigDecimal quantity, Player player) { + if (player == null) { + throw new IllegalArgumentException("Player cannot be null"); } - /** - * Represents a player buying a share on the exchange. - *Creates a {@link Purchase} transaction for the - * purchase.
- * - * @param symbol the symbol/ticker of the stock - * @param quantity the quantity of shares to buy for said stock - * @param player the player making the purchase - * @return a purchase transaction containing all details of the purchase - * @throws IllegalArgumentException if player or quantity is null - */ - public Transaction buy(String symbol, BigDecimal quantity, Player player) { - if (player == null) throw new IllegalArgumentException("Player cannot be null"); - if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) - throw new IllegalArgumentException("Quantity must be positive"); - - Stock stock = getStock(symbol); - Share share = new Share(stock, quantity, stock.getSalesPrice()); - Transaction transaction = purchaseFactory.create(share, week); - transaction.commit(player); - - return transaction; + if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) { + throw new IllegalArgumentException("Quantity must be positive"); } - /** - * Represents a player selling a share on the exchange. - *Creates a {@link Sale} transaction for the sale.
- * - * @param share the share to be sold - * @param player the player selling the share - * @return a sale transaction containing all details of the sale - * @throws IllegalArgumentException if player or share is null - */ - public Transaction sell(Share share, Player player) { - if (player == null) throw new IllegalArgumentException("Player cannot be null"); - if (share == null) throw new IllegalArgumentException("Share cannot be null"); - - Transaction transaction = saleFactory.create(share, week); - transaction.commit(player); - return transaction; + Stock stock = getStock(symbol); + Share share = new Share(stock, quantity, stock.getSalesPrice()); + Transaction transaction = purchaseFactory.create(share, week); + transaction.commit(player); + + return transaction; + } + + /** + * Represents a player selling a share on the exchange. + * + *Creates a {@link Sale} transaction for the sale.
+ * + * @param share the share to be sold + * @param player the player selling the share + * @return a sale transaction containing all details of the sale + * @throws IllegalArgumentException if player or share is null + */ + public Transaction sell(Share share, Player player) { + if (player == null) { + throw new IllegalArgumentException("Player cannot be null"); } - /** - * Advances the timeline of the exchange by 1 week. - *Uses a randomized value for the increase and decrease of a stocks sales price, simulating market - * fluctuations on a weekly basis.
- */ - public void advance() { - this.week++; - this.currentWeekProperty.set(week); - - double negativePriceChange = -0.05; - double positivePriceChange = 0.1; - - for (Stock stock : stockMap.values()) { - BigDecimal currentPrice = stock.getSalesPrice(); - double randomPriceMultiplier = negativePriceChange + (positivePriceChange * random.nextDouble()); - BigDecimal bdRandomPriceMultiplier = BigDecimal.valueOf(1 + randomPriceMultiplier); + if (share == null) { + throw new IllegalArgumentException("Share cannot be null"); + } - BigDecimal changedPrice = currentPrice.multiply(bdRandomPriceMultiplier) + Transaction transaction = saleFactory.create(share, week); + transaction.commit(player); + return transaction; + } + + /** + * Advances the timeline of the exchange by 1 week. + * + *Uses a randomized value for the increase and decrease + * of a stocks sales price, simulating market fluctuations on a weekly basis.
+ */ + public void advance() { + this.week++; + this.currentWeekProperty.set(week); + + double negativePriceChange = -0.05; + double positivePriceChange = 0.1; + + for (Stock stock : stockMap.values()) { + BigDecimal currentPrice = stock.getSalesPrice(); + double randomPriceMultiplier = negativePriceChange + + (positivePriceChange * random.nextDouble()); + BigDecimal bdRandomPriceMultiplier = BigDecimal.valueOf(1 + randomPriceMultiplier); + + BigDecimal changedPrice = currentPrice.multiply(bdRandomPriceMultiplier) .setScale(2, RoundingMode.HALF_UP); - if (changedPrice.compareTo(BigDecimal.ZERO) <= 0) { - changedPrice = new BigDecimal(1); - } + if (changedPrice.compareTo(BigDecimal.ZERO) <= 0) { + changedPrice = new BigDecimal(1); + } - stock.addNewSalesPrice(changedPrice); - } + stock.addNewSalesPrice(changedPrice); + } + } + + /** + * Sorts the stocks in descending order and returns a list of stocks. + * + * @param entries amount of entries in the list to display + * @param comparator the comparator used to compare the stocks + * @return a list of stocks + * @throws IllegalArgumentException if the amount of entries is negative + */ + private List- * A {@code Player} has a name, a monetary balance, a {@link Portfolio} + * + *
A {@code Player} has a name, a monetary balance, a {@link Portfolio} * of owned {@link Share}s, and a {@link TransactionArchive} containing - * a history of the player's transactions. - *
+ * a history of the player's transactions. * - *- * The player starts with an initial amount of money and may gain or - * lose funds through transactions. - *
+ *The player starts with an initial amount of money and may gain or + * lose funds through transactions.
*/ public class Player { - private final String name; - private final BigDecimal startingMoney; - private BigDecimal money; - private final Portfolio portfolio; - private final TransactionArchive transactionArchive; - - private final ObjectPropertySubscribes to the netWorth property to notify of changes in the player's net worth.
- * - * @param name the player's name; must not be {@code null} or blank - * @param startingMoney the initial monetary balance of the - * player; must not be {@code null} or negative - * @throws IllegalArgumentException if {@code name} is {@code null} or - * blank, or if {@code startingMoney} - * is {@code null}, negative, or 0 - */ - public Player(String name, BigDecimal startingMoney) { - if (name == null || name.isBlank()) { - throw new IllegalArgumentException("Player name must not be null or empty."); - } - - if (startingMoney == null || startingMoney.signum() <= 0 ) { - throw new IllegalArgumentException("Starting money must not be null, negative, nor 0."); - } - - this.name = name; - this.startingMoney = startingMoney; - this.money = startingMoney; - this.moneyProperty.set(startingMoney); - this.portfolio = new Portfolio(); - this.transactionArchive = new TransactionArchive(); - - portfolio.netWorthProperty().subscribe(price -> updateNetWorth()); - updateNetWorth(); + private final String name; + private final BigDecimal startingMoney; + private BigDecimal money; + private final Portfolio portfolio; + private final TransactionArchive transactionArchive; + + private final ObjectPropertySubscribes to the netWorth property to notify of changes in the player's net worth.
+ * + * @param name the player's name; must not be {@code null} or blank + * @param startingMoney the initial monetary balance of the + * player; must not be {@code null} or negative + * @throws IllegalArgumentException if {@code name} is {@code null} or + * blank, or if {@code startingMoney} + * is {@code null}, negative, or 0 + */ + public Player(String name, BigDecimal startingMoney) { + if (name == null || name.isBlank()) { + throw new IllegalArgumentException("Player name must not be null or empty."); } - /** - * Returns an {@link ObjectProperty} of the player's net worth. - * - * @return an observable of the player's net worth - */ - public ObjectPropertyMoney added must be a {@code positive} number.
+ * + * @param amount the amount to add; must be positive and not {@code null} + * @throws IllegalArgumentException if {@code amount} is {@code null} + * or not positive + */ + public void addMoney(BigDecimal amount) { + if (amount == null) { + throw new IllegalArgumentException("Amount must not be null."); } - - /** - * Returns the full name of the player. - * - * @return the player's name - */ - public String getName() { - return this.name; + if (amount.signum() <= 0) { + throw new IllegalArgumentException("Amount must be positive."); } - /** - * Returns the player's current monetary balance. - * - * @return the player's current balance. - */ - public BigDecimal getMoney() { - return this.money; + this.money = this.money.add(amount); + this.moneyProperty.set(this.money); + updateNetWorth(); + } + + /** + * Decreases the player's monetary balance by the given amount. + * + *The player's monetary balance must not decrease below {@code 0} + * (overdrawn not possible).
+ * + * @param amount the amount to subtract; must not be negative or {@code null} + * @throws IllegalArgumentException if the amount is not positive, + * {@code null}, or insufficient funds are available + */ + public void withdrawMoney(BigDecimal amount) { + if (amount == null) { + throw new IllegalArgumentException("Amount must not be null."); } - /** - * Increases the players monetary balance by the given amount. - *- * Money added must be a {@code positive} number. - *
- * - * @param amount the amount to add; must be positive and not {@code null} - * @throws IllegalArgumentException if {@code amount] is {@code null} - * or not positive - */ - public void addMoney(BigDecimal amount) { - if (amount == null) throw new IllegalArgumentException("Amount must not be null."); - if (amount.signum() <= 0) throw new IllegalArgumentException("Amount must be positive."); - this.money = this.money.add(amount); - this.moneyProperty.set(this.money); - updateNetWorth(); + if (amount.signum() <= 0) { + throw new IllegalArgumentException("Amount must be positive."); } - /** - * Decreases the player's monetary balance by the given amount. - *- * The player's monetary balance must not decrease below {@code 0} - * (overdrawn not possible). - *
- * - * @param amount the amount to subtract; must not be negative or {@code null} - * @throws IllegalArgumentException if the amount is not positive, {@code null} - * , or insufficient funds are available - */ - public void withdrawMoney(BigDecimal amount) { - if (amount == null) throw new IllegalArgumentException("Amount must not be null."); - if (amount.signum() <= 0) throw new IllegalArgumentException("Amount must be positive."); - if (this.money.subtract(amount).signum() < 0) throw new IllegalArgumentException("Insufficient funds."); - this.money = this.money.subtract(amount); - this.moneyProperty.set(this.money); - updateNetWorth(); + if (this.money.subtract(amount).signum() < 0) { + throw new IllegalArgumentException("Insufficient funds."); } - - /** - * Returns an observable of the player's current monetary funds - * @return an observable of the player's current money - */ - public ObjectPropertyThe net worth is the sum of the player's current money and + * all the value of their shares in their portfolio.
+ * + * @return the player's current net worth + */ + public BigDecimal getNetWorth() { + return money.add(portfolio.getNetWorth()); + } + + /** + * Returns the current status/title of the player, representing their achievements. + * + * @param exchange the exchange the player is trading at + * @return a string representing the players current status + */ + public String getStatus(Exchange exchange) { + String status = "Novice"; + BigDecimal ratio = getNetWorth().divide(this.startingMoney, RoundingMode.HALF_EVEN); + + if (ratio.compareTo(new BigDecimal("1.20")) >= 0 && exchange.getWeek() >= 10) { + status = "Investor"; } - - /** - * Return's the player's portfolio of shares. - * - * @return the player's portfolio - */ - public Portfolio getPortfolio() { - return this.portfolio; + if (ratio.compareTo(new BigDecimal("2")) >= 0 && exchange.getWeek() >= 20) { + status = "Speculator"; } - /** - * Returns the archive of the player's transaction history. - * - * @return the player's transaction archive - */ - public TransactionArchive getTransactionArchive() { - return this.transactionArchive; - } - - /** - * Returns the player's current net worth. - *The net worth is the sum of the player's current money and all the value of their shares in their - * portfolio.
- * - * @return the player's current net worth - */ - public BigDecimal getNetWorth() { - return money.add(portfolio.getNetWorth()); - } - - /** - * Returns the current status/title of the player, representing their achievements. - * - * @param exchange the exchange the player is trading at - * @return a string representing the players current status - */ - public String getStatus(Exchange exchange) { - String status = "Novice"; - BigDecimal ratio = getNetWorth().divide(this.startingMoney, RoundingMode.HALF_EVEN); - if (ratio.compareTo(new BigDecimal("1.20")) >= 0 && exchange.getWeek() >= 10) status = "Investor"; - if (ratio.compareTo(new BigDecimal("2")) >= 0 && exchange.getWeek() >= 20) status = "Speculator"; - return status; - } + return status; + } } \ No newline at end of file diff --git a/millions/src/main/java/no/ntnu/gruppe53/model/Portfolio.java b/millions/src/main/java/no/ntnu/gruppe53/model/Portfolio.java index 6a3c5f9..31fda6d 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/model/Portfolio.java +++ b/millions/src/main/java/no/ntnu/gruppe53/model/Portfolio.java @@ -11,155 +11,152 @@ /** * Represents the portfolio of the Player, containing information * about which {@link Share}s are owned. - *- * A {@code Portfolio} manages a mutable collection of shares, allowing - * shares to be added, removed, and queried. - *
* - *- * Shares are associated with a unique Transaction, however, multiple - * shares from the same stock can exist in the portfolio. - *
+ *A {@code Portfolio} manages a mutable collection of shares, allowing + * shares to be added, removed, and queried.
+ * + *Shares are associated with a unique Transaction, however, multiple + * shares from the same stock can exist in the portfolio.
*/ public class Portfolio { - private final ObservableListThe {@link Stock} must not be {@code null} and the share quantity + * and purchase price must be above zero.
+ * + * @param share the share owned by the player; must not be {@code null} + * @return {@code true} if the share was added successfully, + * {@code false} otherwise + * @throws IllegalArgumentException if {@code share} is {@code null} + */ + public boolean addShare(Share share) { + if (share == null) { + throw new IllegalArgumentException("Share cannot be null"); } - /** - * Adds a share to the player's portfolio. - *- * The {@link Stock} must not be {@code null} and the share quantity - * and purchase price must be above zero. - *
- * - * @param share the share owned by the player; must not be {@code null} - * @return {@code true} if the share was added successfully, - * {@code false} otherwise - * @throws IllegalArgumentException if {@code share} is {@code null} - */ - public boolean addShare(Share share) { - if (share == null) { - throw new IllegalArgumentException("Share cannot be null"); - } - - this.shares.add(share); - - share.getStock().salesPriceProperty() + this.shares.add(share); + + share.getStock().salesPriceProperty() .subscribe(price -> updateNetWorth()); - updateNetWorth(); - return true; + updateNetWorth(); + + return true; + } + + /** + * Removes a share from the player's portfolio. + * + *The list must already exist in the portfolio to be successfully + * removed.
+ * + * @param share the share being removed; must not be {@code null} + * @return {@code true} if the share removal was successful, + * {@code false} otherwise. + * @throws IllegalArgumentException if {@code share} is {@code null} + */ + public boolean removeShare(Share share) { + if (share == null) { + throw new IllegalArgumentException("Share cannot be null"); } - /** - * Removes a share from the player's portfolio. - *- * The list must already exist in the portfolio to be successfully - * removed. - *
- * - * @param share the share being removed; must not be {@code null} - * @return {@code true} if the share removal was successful, - * {@code false} otherwise. - * @throws IllegalArgumentException if {@code share} is {@code null} - */ - public boolean removeShare(Share share) { - if (share == null) { - throw new IllegalArgumentException("Share cannot be null"); - } - - boolean removed = this.shares.removeIf(s -> s.equals(share)); - - if (removed) { - updateNetWorth(); - } - - return removed; - } + boolean removed = this.shares.removeIf(s -> s.equals(share)); - /** - * Returns a list of the shares currently in the player's portfolio. - * - * @return a list of the shares in this portfolio - */ - public ObservableList- * Portfolio value is based on current market price, not transaction rules. - *
- * - * @return the total market value of the portfolio - */ - public BigDecimal getNetWorth() { - return this.shares.stream() + return tempSymbols; + } + + /** + * Determines whether the player's portfolio contains the specified + * share. + * + * @param share the share to search for in this portfolio + * @return {@code true} if the player's portfolio contains the share + * {@code false} otherwise + */ + public boolean contains(Share share) { + return shares.stream().anyMatch(s -> s.equals(share)); + } + + /** + * Calculates the net total value of the shares in the portfolio. + * + *Portfolio value is based on current market price, not transaction rules.
+ * + * @return the total market value of the portfolio + */ + public BigDecimal getNetWorth() { + return this.shares.stream() .map(share -> share.getStock().getSalesPrice() .multiply(share.getQuantity()) ) .reduce(BigDecimal.ZERO, BigDecimal::add); - } - - /** - * Returns an {@link ObjectProperty} of the net worth of the portfolio - * - * @return an observable of the portfolio's net worth - */ - public ObjectProperty- * A purchase can only be commited if: + * a {@link Share}. + * + *
A purchase can only be commited if: *
If the transaction is not already committed, and the player + * has sufficient funds, the transaction will: + *
- * If the transaction is not already committed, and the player - * has sufficient funds, the transaction will: - *
Also sets up the ObjectProperties of the different calculations such - * that Subscriptions can listen to the calculations
- * @param share the share to calculate purchase costs for - */ - public PurchaseCalculator(Share share) { - - this.purchasePrice = share.getPurchasePrice(); - this.quantity = share.getQuantity(); - - this.grossProperty.set(calculateGross()); - this.commissionProperty.set(calculateCommission()); - this.totalProperty.set(calculateTotal()); - - } - - /** - * Calculates the gross purchase price of the given share. - * - * @return the gross associated cost of purchasing the share - */ - @Override - public BigDecimal calculateGross(){ - - return this.quantity.multiply(this.purchasePrice); - } - - /** - * Calculates the commission of the exchange for purchasing a share. - *Commission is set to a fixed 0.5% of gross purchase price.
- * - * @return the commission taken by the exchange - */ - @Override +public class PurchaseCalculator implements TransactionCalculator { + private final BigDecimal purchasePrice; + private final BigDecimal quantity; + + // Objectproperties + private final ObjectPropertyAlso sets up the ObjectProperties of the different calculations such + * that Subscriptions can listen to the calculations
+ * + * @param share the share to calculate purchase costs for + */ + public PurchaseCalculator(Share share) { + this.purchasePrice = share.getPurchasePrice(); + this.quantity = share.getQuantity(); + + this.grossProperty.set(calculateGross()); + this.commissionProperty.set(calculateCommission()); + this.totalProperty.set(calculateTotal()); + + } + + /** + * Calculates the gross purchase price of the given share. + * + * @return the gross associated cost of purchasing the share + */ + @Override + public BigDecimal calculateGross() { + return this.quantity.multiply(this.purchasePrice); + } + + /** + * Calculates the commission of the exchange for purchasing a share. + * + *Commission is set to a fixed 0.5% of gross purchase price.
+ * + * @return the commission taken by the exchange + */ + @Override public BigDecimal calculateCommission() { - BigDecimal commission = new BigDecimal("0.005"); - - - - return calculateGross().multiply(commission); - } - - /** - * Calculates the tax for a purchase. - *For a purchase, there is no tax.
- * - * @return the tax for a purchase, in this case zero - */ - @Override - public BigDecimal calculateTax() { - return new BigDecimal(0); - } - - /** - * Calculates the total costs associated with the purchase of a share - * - * @return the net total cost of purchasing a share - */ - @Override - public BigDecimal calculateTotal() { - - - return calculateGross().add(calculateCommission()).add(calculateTax()); - } - - /** - * Returns an observable of the calculated gross - * @return an observable of the calculated gross - */ - public ObjectPropertyFor a purchase, there is no tax.
+ * + * @return the tax for a purchase, in this case zero + */ + @Override + public BigDecimal calculateTax() { + return new BigDecimal(0); + } + + /** + * Calculates the total costs associated with the purchase of a share. + * + * @return the net total cost of purchasing a share + */ + @Override + public BigDecimal calculateTotal() { + return calculateGross().add(calculateCommission()).add(calculateTax()); + } + + /** + * Returns an observable of the calculated gross. + * + * @return an observable of the calculated gross + */ + public ObjectProperty- * A sale can only be commited if: + * a {@link Share}. + * + *
A sale can only be commited if: *
If the player ows the share, the transaction will: + *
- * If the player ows the share, the transaction will: - *
The commission is set to a fixed 1% of the gross total sale value.
- * - * @return the commission taken by the exchange - */ - @Override + } + + /** + * Calculates the exchange's commission for selling the share. + * + *The commission is set to a fixed 1% of the gross total sale value.
+ * + * @return the commission taken by the exchange + */ + @Override public BigDecimal calculateCommission() { - BigDecimal commissionRate = new BigDecimal("0.01"); + BigDecimal commissionRate = new BigDecimal("0.01"); - return calculateGross() + return calculateGross() .multiply(commissionRate) .setScale(2, RoundingMode.HALF_UP); - } + } - /** - * Calculates the taxable profit from the sale. - *Only calculates tax for profitable sales.
> - * - * @return the tax amount - */ - @Override - public BigDecimal calculateTax() { + /** + * Calculates the taxable profit from the sale. + * + *Only calculates tax for profitable sales.
> + * + * @return the tax amount + */ + @Override + public BigDecimal calculateTax() { - BigDecimal taxRate = new BigDecimal("0.30"); + BigDecimal taxRate = new BigDecimal("0.30"); - BigDecimal originalCost = purchasePrice.multiply(quantity); + BigDecimal originalCost = purchasePrice.multiply(quantity); - BigDecimal profit = calculateGross() + BigDecimal profit = calculateGross() .subtract(calculateCommission()) .subtract(originalCost); - if (profit.compareTo(BigDecimal.ZERO) <= 0) { - return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); - } + if (profit.compareTo(BigDecimal.ZERO) <= 0) { + return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); + } - return profit.multiply(taxRate) + return profit.multiply(taxRate) .setScale(2, RoundingMode.HALF_UP); - } + } - /** - * Returns the net total gain for selling the share. - * - * @return the net total winnings of selling the share - */ - @Override - public BigDecimal calculateTotal() { + /** + * Returns the net total gain for selling the share. + * + * @return the net total winnings of selling the share + */ + @Override + public BigDecimal calculateTotal() { - return calculateGross() + return calculateGross() .subtract(calculateCommission()) .subtract(calculateTax()) .setScale(2, RoundingMode.HALF_UP); - } - - /** - * Returns an observable of the calculated gross - * @return an observable of the calculated gross - */ - public ObjectProperty- * A {@code Share} contains the quantity of shares owned and + * + *
A {@code Share} contains the quantity of shares owned and * the price per share at the time of purchase. Future price * fluctuations are not included in share. *
*/ public class Share { - private final Stock stock; - private final BigDecimal quantity; - private final BigDecimal purchasePrice; + private final Stock stock; + private final BigDecimal quantity; + private final BigDecimal purchasePrice; - /** - * Creates a share for a given stock. - * - * @param stock the stock associated with the share; must not be {@code null} - * @param quantity the number of shares purchased; must not be {@code null}, negative, or zero - * @param purchasePrice price per share at the time of purchase; must not be {@code null}, negative or zero - * @throws IllegalArgumentException if {@code stock} is {@code null}, or {@code quantity} is {@code null}, - * negative, or zero, or {@code purchasePrice} is {@code null}, negative, - * or zero - */ - - public Share(Stock stock, BigDecimal quantity, BigDecimal purchasePrice) { - if (stock == null) { - throw new IllegalArgumentException("Stock cannot be null."); - } - - if (quantity == null || quantity.signum() <= 0) { - throw new IllegalArgumentException("Quantity cannot be null, negative, or zero."); - } - - if (purchasePrice == null || purchasePrice.signum() <= 0) { - throw new IllegalArgumentException("PurchasePrice cannot be null, negative, or zero."); - } + /** + * Creates a share for a given stock. + * + * @param stock the stock associated with the share; must not be {@code null} + * @param quantity the number of shares purchased; must not be {@code null}, negative, or zero + * @param purchasePrice price per share at the time of purchase; + * must not be {@code null}, negative or zero + * @throws IllegalArgumentException if {@code stock} is {@code null}, + * or {@code quantity} is {@code null}, + * negative, or zero, or {@code purchasePrice} + * is {@code null}, negative, or zero + */ + public Share(Stock stock, BigDecimal quantity, BigDecimal purchasePrice) { + if (stock == null) { + throw new IllegalArgumentException("Stock cannot be null."); + } - this.stock = stock; - this.quantity = quantity; - this.purchasePrice = purchasePrice; + if (quantity == null || quantity.signum() <= 0) { + throw new IllegalArgumentException("Quantity cannot be null, negative, or zero."); } - /** - * Returns the stock the share is associated with. - * - * @return the stock - */ - public Stock getStock() { - return stock; + if (purchasePrice == null || purchasePrice.signum() <= 0) { + throw new IllegalArgumentException("PurchasePrice cannot be null, negative, or zero."); } - /** - * Returns the quantity of shares owned in the stock. - * - * @return the quantity of shares - */ + this.stock = stock; + this.quantity = quantity; + this.purchasePrice = purchasePrice; + } - public BigDecimal getQuantity() { - return quantity; - } + /** + * Returns the stock the share is associated with. + * + * @return the stock + */ + public Stock getStock() { + return stock; + } - /** - * Returns the purchase price per share for the stock at time of purchase. - * - * @return the purchase price of the shares. - */ - public BigDecimal getPurchasePrice() { - return purchasePrice; - } + /** + * Returns the quantity of shares owned in the stock. + * + * @return the quantity of shares + */ + + public BigDecimal getQuantity() { + return quantity; + } + + /** + * Returns the purchase price per share for the stock at time of purchase. + * + * @return the purchase price of the shares. + */ + public BigDecimal getPurchasePrice() { + return purchasePrice; + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/model/Stock.java b/millions/src/main/java/no/ntnu/gruppe53/model/Stock.java index 6fe5424..04c53c8 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/model/Stock.java +++ b/millions/src/main/java/no/ntnu/gruppe53/model/Stock.java @@ -1,162 +1,163 @@ package no.ntnu.gruppe53.model; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; /** * Represents a stock with its ticker symbol, company name, * and a list of sales prices. - *- * The list is a historical representation of price changes + * + *
The list is a historical representation of price changes * over time for the given stock. *
- *- * The most recently added price represents the current market price. - *
* - *- * A {@code Stock} instance always contains at least one price, - * instantiated at construction. + *
The most recently added price represents the current market price. *
+ * + *A {@code Stock} instance always contains at least one price, + * instantiated at construction.
*/ public class Stock { - private final String symbol; - private final String company; - private final List- * The current price is defined as the most recent price in the price history. - *
- * @return the current sale price of the stock - */ - public BigDecimal getSalesPrice() { - return salesPrice.get(); - } - - /** - * Adds a new sales price to the stock's price history. - *- * The added price becomes the new current market price. - *
- * - *- * The new price must be positive. - *
- * @param price the new market price per share of the stock; must not be {@code null}, negative or zero - * @throws IllegalArgumentException if {@code price} is {@code null}, negative, or zero - */ - public void addNewSalesPrice(BigDecimal price) { - if (price == null || price.signum() <= 0) { - throw new IllegalArgumentException("Price cannot be null, negative, or zero."); - } - this.prices.add(price); - this.salesPrice.set(price); - } - - - /** - * Returns an {@link ObjectProperty} of the sales price. - * - * @return an observable of the sales price - */ - public ObjectPropertyThe current price is defined as the most recent price + * in the price history.
+ * + * @return the current sale price of the stock + */ + public BigDecimal getSalesPrice() { + return salesPrice.get(); + } + + /** + * Adds a new sales price to the stock's price history. + * + *The added price becomes the new current market price.
+ * + *The new price must be positive.
+ * + * @param price the new market price per share of the stock; + * must not be {@code null}, negative or zero + * @throws IllegalArgumentException if {@code price} is {@code null}, negative, or zero + */ + public void addNewSalesPrice(BigDecimal price) { + if (price == null || price.signum() <= 0) { + throw new IllegalArgumentException("Price cannot be null, negative, or zero."); } - /** - * Returns the sales price increase/decrease from previous week to this week. Returns 0 if - * the price list only has 1 value. - * - * @return the net difference in sales price between the last and second last week - */ - public BigDecimal getLatestPriceChange() { - if (prices.size() >= 2) { - return prices.getLast().subtract(prices.get(prices.size() - 2)); - } else { - return BigDecimal.ZERO; - } + this.prices.add(price); + this.salesPrice.set(price); + } + + /** + * Returns an {@link ObjectProperty} of the sales price. + * + * @return an observable of the sales price + */ + public ObjectProperty- * A transaction occurs in a specific week and uses a + * + *
A transaction occurs in a specific week and uses a * {@link TransactionCalculator} to determine the monetary change. * Transactions are unique and is committed to a {@link Player}'s - * {@link Portfolio}. - *
+ * {@link Portfolio}. * - *- * Subclasses define the nature of the transaction (e.g. purchase - * or sale) by implementing the {@link #commit(Player)} - *
+ *Subclasses define the nature of the transaction (e.g. purchase + * or sale) by implementing the {@link #commit(Player)}
*/ +public abstract class Transaction { + private final Share share; + private final int week; + private final TransactionCalculator calculator; + protected boolean committed; -abstract public class Transaction { - private final Share share; - private final int week; - private final TransactionCalculator calculator; - protected boolean committed; - - /** - * Constructor for a transaction. - * - * @param share the share for the transaction; must not be {@code null} - * @param week the week the transaction takes place; must be greater than 0 - * @param calculator the transaction calculator used to - * compute the {@link Transaction} - * @throws IllegalArgumentException if {@code share} is {@code null} or {@code week} - * is less than 1 - */ - - protected Transaction(Share share, int week, TransactionCalculator calculator) { - if (week <= 0) { - throw new IllegalArgumentException("Week cannot be negative or zero"); - } + /** + * Constructor for a transaction. + * + * @param share the share for the transaction; must not be {@code null} + * @param week the week the transaction takes place; must be greater than 0 + * @param calculator the transaction calculator used to + * compute the {@link Transaction} + * @throws IllegalArgumentException if {@code share} is {@code null} or {@code week} + * is less than 1 + */ - this.share = share; - this.week = week; - this.calculator = calculator; - this.committed = false; + protected Transaction(Share share, int week, TransactionCalculator calculator) { + if (week <= 0) { + throw new IllegalArgumentException("Week cannot be negative or zero"); } - /** - * Returns the share for the current transaction. - * - * @return the share belonging to the transaction - */ - public Share getShare() { - return this.share; - } + this.share = share; + this.week = week; + this.calculator = calculator; + this.committed = false; + } - /** - * Returns the week the transaction took place. - * - * @return the week for the transaction - */ - public int getWeek() { - return this.week; - } + /** + * Returns the share for the current transaction. + * + * @return the share belonging to the transaction + */ + public Share getShare() { + return this.share; + } - /** - * Returns the transaction calculator used to calculate - * the transaction. - * - * @return the transaction calculator used for the transaction - */ + /** + * Returns the week the transaction took place. + * + * @return the week for the transaction + */ + public int getWeek() { + return this.week; + } - public TransactionCalculator getCalculator() { - return this.calculator; - } + /** + * Returns the transaction calculator used to calculate + * the transaction. + * + * @return the transaction calculator used for the transaction + */ - /** - * Returns whether the transaction has been committed to a player. - * - * @return {@code true} if committed, {@code false} otherwise - */ + public TransactionCalculator getCalculator() { + return this.calculator; + } - public boolean isCommitted() { - return this.committed; - } + /** + * Returns whether the transaction has been committed to a player. + * + * @return {@code true} if committed, {@code false} otherwise + */ - /** - * Commits the transaction to a player, making it unique. - * - *- * Subclasses should define the business logic required before - * committing. Then {@code super.commit(player)} should be called - * once the transaction has been successfully applied. - *
- * @param player the player performing the transaction; must not be {@code null} - */ + public boolean isCommitted() { + return this.committed; + } - public void commit(Player player) { - this.committed = true; - } + /** + * Commits the transaction to a player, making it unique. + * + *Subclasses should define the business logic required before + * committing. Then {@code super.commit(player)} should be called + * once the transaction has been successfully applied.
+ * + * @param player the player performing the transaction; must not be {@code null} + */ + + public void commit(Player player) { + this.committed = true; + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/model/TransactionArchive.java b/millions/src/main/java/no/ntnu/gruppe53/model/TransactionArchive.java index 70bba67..88e5f7b 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/model/TransactionArchive.java +++ b/millions/src/main/java/no/ntnu/gruppe53/model/TransactionArchive.java @@ -1,143 +1,145 @@ package no.ntnu.gruppe53.model; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - import java.util.ArrayList; import java.util.HashSet; import java.util.List; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; /** * Maintains a history of all completed {@link Transaction}s. - *- * A {@code TransactionArchive} stores transactions in the order + * + *
A {@code TransactionArchive} stores transactions in the order * they are added and provides methods to retrieve transactions - * filtered by type and week. - *
+ * filtered by type and week. */ public class TransactionArchive { - private final ObservableListA week is considered distinct if at least one transaction has + * occurred within that week. Multiple transactions in the span of the + * same week will only be counted as one distinct week.
+ * + * @return the number of unique week values in the archive; + * {@code 0} if the archive contains no transactions + */ + + public int countDistinctWeeks() { + var distinctWeeks = new HashSet- * A week is considered distinct if at least one transaction has - * occurred within that week. Multiple transactions in the span of the - * same week will only be counted as one distinct week. - *
- * - * @return the number of unique week values in the archive; - * {@code 0} if the archive contains no transactions - */ - - public int countDistinctWeeks() { - var distinctWeeks = new HashSet{@link Purchase} and {@link Sale} are examples of implementations of a transaction.
*/ public interface TransactionCalculator { - BigDecimal calculateGross(); - BigDecimal calculateCommission(); - BigDecimal calculateTax(); - BigDecimal calculateTotal(); + /** + * Calculates the gross value of a transaction. + * + * @return the gross value of a transaction + */ + BigDecimal calculateGross(); + + /** + * Calculates the commission for the exchange of a transaction. + * + * @return the commission of a transaction + */ + BigDecimal calculateCommission(); + + /** + * Calculates the tax of a transaction. + * + * @return the tax of a transaction + */ + BigDecimal calculateTax(); + + /** + * Returns the total value of a transaction. + * + * @return the total value of a transaction + */ + BigDecimal calculateTotal(); } diff --git a/millions/src/main/java/no/ntnu/gruppe53/model/TransactionFactory.java b/millions/src/main/java/no/ntnu/gruppe53/model/TransactionFactory.java index 9ddb766..cb27b9f 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/model/TransactionFactory.java +++ b/millions/src/main/java/no/ntnu/gruppe53/model/TransactionFactory.java @@ -2,31 +2,38 @@ /** * Factory for creating a {@link Transaction} for a {@link Share} in an {@link Exchange}. + * *Subclasses implement the specific type of transaction to be used.
*/ public abstract class TransactionFactory { - /** - * Creates a transaction. - * - * @param share the share involved - * @param week the transaction week - * @return a transaction - */ - public Transaction create(Share share, int week) { - - if (share == null) { - throw new IllegalArgumentException("Share cannot be null."); - } - - if (week <= 0) { - throw new IllegalArgumentException("Week must be positive whole number."); - } + /** + * Creates a transaction. + * + * @param share the share involved + * @param week the transaction week + * @return a transaction + */ + public Transaction create(Share share, int week) { + if (share == null) { + throw new IllegalArgumentException("Share cannot be null."); + } - return createTransaction(share, week); + if (week <= 0) { + throw new IllegalArgumentException("Week must be positive whole number."); } - protected abstract Transaction createTransaction( + return createTransaction(share, week); + } + + /** + * Creates a transaction from a share and week. + * + * @param share the share for the transaction + * @param week the week of the transaction + * @return a transaction for the share and week + */ + protected abstract Transaction createTransaction( Share share, int week ); diff --git a/millions/src/main/java/no/ntnu/gruppe53/service/FileHandler.java b/millions/src/main/java/no/ntnu/gruppe53/service/FileHandler.java index 8ed2b0d..a587c09 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/service/FileHandler.java +++ b/millions/src/main/java/no/ntnu/gruppe53/service/FileHandler.java @@ -1,8 +1,5 @@ package no.ntnu.gruppe53.service; -import no.ntnu.gruppe53.model.Stock; - - import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -13,131 +10,146 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import no.ntnu.gruppe53.model.Stock; /** * Handles reading and writing of .csv files for stocks. */ public class FileHandler { + /** + * Writes a list of {@link Stock}s to a CSV file in UTF-8 encoding. + * + * @param stockList the list of stocks to be written + * @param path directory path for the file + * @param filename name of the file (without or with .csv extension) + * @throws IllegalArgumentException if stockList, path, + * or filename is null, or if stockList is empty + */ + public static void writeStocksToFile(ListReturns "0.00" if the BigDecimal is null.
- * - * @param number the BigDecimal to be formated - * @return the string representation of the BigDecimal with 2 decimals accuracy. - */ - public static String formatNumber(BigDecimal number) { - return number == null ? "0.00" : number.setScale(2, RoundingMode.HALF_UP).toPlainString(); - } + /** + * Static method used to format a Big Decimal to a string representation with 2 decimals accuracy. + * + *Returns "0.00" if the BigDecimal is null.
+ * + * @param number the BigDecimal to be formated + * @return the string representation of the BigDecimal with 2 decimals accuracy. + */ + public static String formatNumber(BigDecimal number) { + return number == null ? "0.00" : number.setScale(2, RoundingMode.HALF_UP).toPlainString(); + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/service/LanguageManager.java b/millions/src/main/java/no/ntnu/gruppe53/service/LanguageManager.java index 776f15a..6d6356d 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/service/LanguageManager.java +++ b/millions/src/main/java/no/ntnu/gruppe53/service/LanguageManager.java @@ -1,97 +1,101 @@ package no.ntnu.gruppe53.service; +import java.util.Locale; +import java.util.ResourceBundle; import javafx.beans.binding.Bindings; import javafx.beans.binding.StringBinding; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; -import java.util.Locale; -import java.util.ResourceBundle; - /** * Manages the language used in the user-interface. + * *The possible languages to be used are set by {@link LanguageRegistry}.
*/ public class LanguageManager { - /** - * Sets a default language and creates an observable {@link ResourceBundle}. - */ - private final ObjectPropertySearches through the registry to find english and sets it as default.
- */ - private static final LanguageOption defaultLang = languages.stream() - .filter(lang -> lang.locale().getLanguage().equals("en")) - .findFirst() - .orElse(languages.getFirst()); + /** + * Sets the default language to be used. + * + *Searches through the registry to find english and sets it as default.
+ */ + private static final LanguageOption defaultLang = + languages.stream() + .filter(lang -> lang.locale().getLanguage().equals("en")) + .findFirst() + .orElse(languages.getFirst()); - /** - * Returns all registered languages - * - * @return a list of registered languages - */ - public static ListReturns the {@code XYChart.Series}.
- * - * @param stock the stock whose price values will be shown in the LineChart - * @param exchange the exchange containing the stock whose week number will be shown in the LineChart - * @return the {@code XYChart.SeriesReturns the {@code XYChart.Series}.
+ * + * @param stock the stock whose price values will be shown in the LineChart + * @param exchange the exchange containing the stock whose + * week number will be shown in the LineChart + * @return the {@code XYChart.SeriesReturns a list of the {@code XYChart.Series} for each stock.
- * - * @param stocks the list of stocks whose price values will be shown in the LineChart - * @param exchange the exchange containing the stock whose week number will be shown in the LineChart - * @return the list of {@code XYChart.SeriesReturns a list of the {@code XYChart.Series} for each stock.
+ * + * @param stocks the list of stocks whose price values will be shown + * in the LineChart + * @param exchange the exchange containing the stock whose week number + * will be shown in the LineChart + * @return the list of {@code XYChart.SeriesUses a {@link LanguageManager} to insert set text to target language.
- */ -public class CSVChooserView { - private final FileChooser fileChooser = new FileChooser(); - Alert newGameAlert = new Alert(Alert.AlertType.INFORMATION); - private final LanguageManager lm = LanguageManager.getInstance(); - - /** - * Returns the dialog for the alert and file chooser and exposes it to controllers. - * - * @param stage the stage for the dialog to be shown - * @return the dialog for the alert and file chooser - */ - public File getDialog(Stage stage) { - // Notifies the user about .csv selection - newGameAlert.setTitle(null); - newGameAlert.headerTextProperty().bind(lm.bindString("csvHeader")); - newGameAlert.contentTextProperty().bind(lm.bindString("csvContent")); - - // Sets the dimensions of the alert to show all text, and as a band-aid, be resizable - newGameAlert.setResizable(true); - - newGameAlert.getDialogPane().setPrefWidth(450); - newGameAlert.getDialogPane().setPrefHeight(350); - - newGameAlert.showAndWait(); - - // File chooser to choose .csv file - fileChooser.setTitle(lm.getString("csvFileChooserTitle")); - - // Limits to .csv file only - fileChooser.getExtensionFilters().clear(); - fileChooser.getExtensionFilters().add( - new FileChooser.ExtensionFilter(lm.getString("csvFileFilterLabel"), "*.csv") - ); - - return fileChooser.showOpenDialog(stage); } -} \ No newline at end of file diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/CsvChooserView.java b/millions/src/main/java/no/ntnu/gruppe53/view/CsvChooserView.java new file mode 100644 index 0000000..4264887 --- /dev/null +++ b/millions/src/main/java/no/ntnu/gruppe53/view/CsvChooserView.java @@ -0,0 +1,51 @@ +package no.ntnu.gruppe53.view; + +import java.io.File; +import javafx.scene.control.Alert; +import javafx.stage.FileChooser; +import javafx.stage.Stage; +import no.ntnu.gruppe53.service.LanguageManager; + +/** + * Represents an {@link Alert} and {@link FileChooser} for + * informing user of .csv requirement and picking said file. + * + *Uses a {@link LanguageManager} to insert set text to target language.
+ */ +public class CsvChooserView { + private final FileChooser fileChooser = new FileChooser(); + Alert newGameAlert = new Alert(Alert.AlertType.INFORMATION); + private final LanguageManager lm = LanguageManager.getInstance(); + + /** + * Returns the dialog for the alert and file chooser and exposes it to controllers. + * + * @param stage the stage for the dialog to be shown + * @return the dialog for the alert and file chooser + */ + public File getDialog(Stage stage) { + // Notifies the user about .csv selection + newGameAlert.setTitle(null); + newGameAlert.headerTextProperty().bind(lm.bindString("csvHeader")); + newGameAlert.contentTextProperty().bind(lm.bindString("csvContent")); + + // Sets the dimensions of the alert to show all text, and as a band-aid, be resizable + newGameAlert.setResizable(true); + + newGameAlert.getDialogPane().setPrefWidth(450); + newGameAlert.getDialogPane().setPrefHeight(350); + + newGameAlert.showAndWait(); + + // File chooser to choose .csv file + fileChooser.setTitle(lm.getString("csvFileChooserTitle")); + + // Limits to .csv file only + fileChooser.getExtensionFilters().clear(); + fileChooser.getExtensionFilters().add( + new FileChooser.ExtensionFilter(lm.getString("csvFileFilterLabel"), "*.csv") + ); + + return fileChooser.showOpenDialog(stage); + } +} \ No newline at end of file diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/EndView.java b/millions/src/main/java/no/ntnu/gruppe53/view/EndView.java index 9ac97de..611e997 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/EndView.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/EndView.java @@ -4,200 +4,210 @@ import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.control.Label; -import javafx.scene.layout.*; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; import no.ntnu.gruppe53.service.LanguageManager; - /** * Represents the End Game screen, showing the Level the Player reached, * money earned in total after selling portfolio and gives the option * to quit the program or start a new game. */ public class EndView extends BorderPane { - - - private Button newGameButton; - private Button quitButton; - - private Label statusLabel; - private Label moneyLabel; - - - private final LanguageManager lm = LanguageManager.getInstance(); - - public EndView() { - this.setCenter(centerPane()); - } - - private BorderPane centerPane() { - BorderPane pane = new BorderPane(); - pane.setPadding(new Insets(15, 12, 15, 12)); - //pane.setSpacing(10); - //Blue Background color - pane.setStyle("-fx-background-color: #00bcf0;"); - - VBox centerPane = new VBox(); - - HBox congratsBox = new HBox(); - Label congratsLabel = new Label(); - congratsLabel.textProperty().bind(lm.bindString("congratsLabel")); - congratsLabel.setStyle("-fx-font-size: 18"); - congratsLabel.setTextAlignment(TextAlignment.CENTER); - - congratsBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - congratsBox.setPadding(new Insets(8, 14, 8, 14)); - congratsBox.setAlignment(Pos.CENTER); - congratsBox.setMinHeight(65); - - congratsBox.getChildren().add(congratsLabel); - - HBox statusLabelBox = new HBox(); - Label statusLabelText = new Label(); - statusLabelText.textProperty().bind(lm.bindString("statusLabelText")); - statusLabelText.setStyle("-fx-font-size: 18"); - statusLabel = new Label(); - statusLabel.setStyle("-fx-font-size: 18"); - - statusLabelBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - statusLabelBox.setPadding(new Insets(8, 14, 8, 14)); - statusLabelBox.setAlignment(Pos.CENTER); - statusLabelBox.setMinHeight(65); - - statusLabelBox.getChildren().addAll(statusLabelText, statusLabel); - - HBox moneyLabelBox = new HBox(); - Label moneyLabelText = new Label(); - moneyLabelText.textProperty().bind(lm.bindString("navMoneyLabelText")); - moneyLabelText.setStyle("-fx-font-size: 18"); - moneyLabel = new Label(); - moneyLabel.setStyle("-fx-font-size: 18"); - - moneyLabelBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - moneyLabelBox.setPadding(new Insets(8, 14, 8, 14)); - moneyLabelBox.setAlignment(Pos.CENTER); - moneyLabelBox.setMinHeight(65); - - moneyLabelBox.getChildren().addAll(moneyLabelText, moneyLabel); - - centerPane.setPadding(new Insets(15, 12, 15, 12)); - centerPane.setAlignment(Pos.CENTER); - centerPane.setSpacing(10); - centerPane.setMaxWidth(700); - - - centerPane.getChildren().addAll(congratsBox, statusLabelBox, moneyLabelBox); - - HBox quitButtonBox = new HBox(); - quitButton = new Button(); - quitButton.textProperty().bind(lm.bindString("quitGame")); - quitButton.setPrefSize(200, 50); - quitButton.setStyle("-fx-text-fill: #303539;" + - "-fx-font-size: 18px;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" + - "-fx-background-radius: 8;" - ); - - - quitButtonBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - quitButtonBox.setPadding(new Insets(8, 14, 8, 14)); - quitButtonBox.setAlignment(Pos.CENTER); - - - quitButtonBox.getChildren().addAll(quitButton); - - HBox newGameButtonBox = new HBox(); - newGameButton = new Button(); - newGameButton.textProperty().bind(lm.bindString("newGame")); - newGameButton.setPrefSize(200, 50); - newGameButton.setStyle("-fx-text-fill: #303539;" + - "-fx-font-size: 18px;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" + - "-fx-background-radius: 8;" - ); - newGameButtonBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - newGameButtonBox.setPadding(new Insets(8, 14, 8, 14)); - newGameButtonBox.setAlignment(Pos.CENTER); - newGameButtonBox.getChildren().add(newGameButton); - - HBox buttons = new HBox(quitButtonBox, newGameButtonBox); - - - - Region spacerBottomLeft = new Region(); - Region spacerBottomRight = new Region(); - - HBox.setHgrow(spacerBottomLeft, Priority.ALWAYS); - HBox.setHgrow(spacerBottomRight, Priority.ALWAYS); - - HBox bottomPane = new HBox(spacerBottomLeft, buttons, spacerBottomRight); - - pane.setCenter(centerPane); - pane.setBottom(bottomPane); - - return pane; - } - - /** - * Sets the action to be run when clicking the quit button - * - * @param action the action to run when clicking the quit button - */ - public void onQuitButton(Runnable action) { - quitButton.setOnAction(e -> action.run()); - } - - /** - * Sets the action to be run when clicking the New Game button - * - * @param action the action to run when clicking the New Game button - */ - public void onNewGameButton(Runnable action) { - newGameButton.setOnAction(e -> action.run()); - } - - /** - * Returns the statusLabel. - * - * @return the statusLabel - */ - public Label getStatusLabel() { - return statusLabel; - } - - /** - * Returns the moneyLabel. - * - * @return the moneyLabel - */ - public Label getMoneyLabel() { - return moneyLabel; - } + private Button newGameButton; + private Button quitButton; + + private Label statusLabel; + private Label moneyLabel; + + private final LanguageManager lm = LanguageManager.getInstance(); + + /** + * Sets the centerPane to the constructed centerPane. + */ + public EndView() { + this.setCenter(centerPane()); + } + + /** + * Constructs the centerPane using a {@link BorderPane}. + * + * @return a constructed borderpane + */ + private BorderPane centerPane() { + BorderPane pane = new BorderPane(); + pane.setPadding(new Insets(15, 12, 15, 12)); + // pane.setSpacing(10); + // Blue Background color + pane.setStyle("-fx-background-color: #00bcf0;"); + + Label congratsLabel = new Label(); + congratsLabel.textProperty().bind(lm.bindString("congratsLabel")); + congratsLabel.setStyle("-fx-font-size: 18"); + congratsLabel.setTextAlignment(TextAlignment.CENTER); + + HBox congratsBox = new HBox(); + congratsBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + congratsBox.setPadding(new Insets(8, 14, 8, 14)); + congratsBox.setAlignment(Pos.CENTER); + congratsBox.setMinHeight(65); + + congratsBox.getChildren().add(congratsLabel); + + Label statusLabelText = new Label(); + statusLabelText.textProperty().bind(lm.bindString("statusLabelText")); + statusLabelText.setStyle("-fx-font-size: 18"); + statusLabel = new Label(); + statusLabel.setStyle("-fx-font-size: 18"); + + HBox statusLabelBox = new HBox(); + statusLabelBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + statusLabelBox.setPadding(new Insets(8, 14, 8, 14)); + statusLabelBox.setAlignment(Pos.CENTER); + statusLabelBox.setMinHeight(65); + + statusLabelBox.getChildren().addAll(statusLabelText, statusLabel); + + Label moneyLabelText = new Label(); + moneyLabelText.textProperty().bind(lm.bindString("navMoneyLabelText")); + moneyLabelText.setStyle("-fx-font-size: 18"); + moneyLabel = new Label(); + moneyLabel.setStyle("-fx-font-size: 18"); + + HBox moneyLabelBox = new HBox(); + moneyLabelBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + moneyLabelBox.setPadding(new Insets(8, 14, 8, 14)); + moneyLabelBox.setAlignment(Pos.CENTER); + moneyLabelBox.setMinHeight(65); + + moneyLabelBox.getChildren().addAll(moneyLabelText, moneyLabel); + + VBox centerPane = new VBox(); + centerPane.setPadding(new Insets(15, 12, 15, 12)); + centerPane.setAlignment(Pos.CENTER); + centerPane.setSpacing(10); + centerPane.setMaxWidth(700); + + + centerPane.getChildren().addAll(congratsBox, statusLabelBox, moneyLabelBox); + + quitButton = new Button(); + quitButton.textProperty().bind(lm.bindString("quitGame")); + quitButton.setPrefSize(200, 50); + quitButton.setStyle("-fx-text-fill: #303539;" + + "-fx-font-size: 18px;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + + "-fx-background-radius: 8;" + ); + + HBox quitButtonBox = new HBox(); + quitButtonBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + quitButtonBox.setPadding(new Insets(8, 14, 8, 14)); + quitButtonBox.setAlignment(Pos.CENTER); + + + quitButtonBox.getChildren().addAll(quitButton); + + newGameButton = new Button(); + newGameButton.textProperty().bind(lm.bindString("newGame")); + newGameButton.setPrefSize(200, 50); + newGameButton.setStyle("-fx-text-fill: #303539;" + + "-fx-font-size: 18px;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + + "-fx-background-radius: 8;" + ); + + HBox newGameButtonBox = new HBox(); + newGameButtonBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + newGameButtonBox.setPadding(new Insets(8, 14, 8, 14)); + newGameButtonBox.setAlignment(Pos.CENTER); + newGameButtonBox.getChildren().add(newGameButton); + + HBox buttons = new HBox(quitButtonBox, newGameButtonBox); + + Region spacerBottomLeft = new Region(); + Region spacerBottomRight = new Region(); + + HBox.setHgrow(spacerBottomLeft, Priority.ALWAYS); + HBox.setHgrow(spacerBottomRight, Priority.ALWAYS); + + HBox bottomPane = new HBox(spacerBottomLeft, buttons, spacerBottomRight); + + pane.setCenter(centerPane); + pane.setBottom(bottomPane); + + return pane; + } + + /** + * Sets the action to be run when clicking the quit button. + * + * @param action the action to run when clicking the quit button + */ + public void onQuitButton(Runnable action) { + quitButton.setOnAction(e -> action.run()); + } + + /** + * Sets the action to be run when clicking the New Game button. + * + * @param action the action to run when clicking the New Game button + */ + public void onNewGameButton(Runnable action) { + newGameButton.setOnAction(e -> action.run()); + } + + /** + * Returns the statusLabel. + * + * @return the statusLabel + */ + public Label getStatusLabel() { + return statusLabel; + } + + /** + * Returns the moneyLabel. + * + * @return the moneyLabel + */ + public Label getMoneyLabel() { + return moneyLabel; + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/FooterBar.java b/millions/src/main/java/no/ntnu/gruppe53/view/FooterBar.java index 8785d28..dd9857b 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/FooterBar.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/FooterBar.java @@ -2,7 +2,6 @@ import java.util.Locale; import java.util.function.Consumer; - import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button; @@ -14,13 +13,12 @@ import javafx.scene.layout.Priority; import javafx.scene.layout.Region; import javafx.util.Subscription; - import no.ntnu.gruppe53.controller.GameController; import no.ntnu.gruppe53.model.Exchange; +import no.ntnu.gruppe53.model.Stock; import no.ntnu.gruppe53.service.LanguageManager; import no.ntnu.gruppe53.service.LanguageOption; import no.ntnu.gruppe53.service.LanguageRegistry; -import no.ntnu.gruppe53.model.Stock; /* Yellow Color, Hex: #ffe556 RGB(255, 229, 86) @@ -28,208 +26,208 @@ Black Color, Hex: #303539 RGB(48, 53, 57) */ - /** * A {@link HBox} view representing the footer/bottom to be used in a {@link BorderPane} layout. + * *Uses a {@link LanguageManager} to change text to target language dynamically.
*/ public class FooterBar extends HBox { - - private final Button advanceWeekButton; - private Label currentWeekLabel; - private Label biggestLoserLabel; - private Label biggestLoserPriceLabel; - private Label biggestWinnerLabel; - private Label biggestWinnerPriceLabel; - private Subscription currentWeekSubscription; - private Subscription biggestLoserSubscription; - private Subscription biggestWinnerSubscription; - - private Exchange exchange; - private final LanguageManager lm = LanguageManager.getInstance(); - - private final ComboBoxConstructs a {@link ComboBox} to let the user switch language on the fly.
- *Sets the text of the UI elements dynamically.
- */ - public FooterBar() { - this.setSpacing(10); - this.setPadding(new Insets(15, 12, 15, 12)); - this.setStyle("-fx-background-color: #00bcf0;" + - "-fx-border-color: #303539 transparent transparent transparent;" + - "-fx-border-width: 5 0 0 0;"); - - languageBox = new ComboBox<>(); - languageBox.getItems().addAll(LanguageRegistry.getLanguages()); - - Locale activeLocale = lm.getLocale(); - LanguageOption activeOption = LanguageRegistry.getLanguages().stream() + private final Button advanceWeekButton; + private final Label currentWeekLabel; + private final Label biggestLoserLabel; + private final Label biggestLoserPriceLabel; + private final Label biggestWinnerLabel; + private final Label biggestWinnerPriceLabel; + private Subscription biggestLoserSubscription; + private Subscription biggestWinnerSubscription; + + private final LanguageManager lm = LanguageManager.getInstance(); + + private final ComboBoxConstructs a {@link ComboBox} to let the user switch language on the fly.
+ * + *Sets the text of the UI elements dynamically.
+ */ + public FooterBar() { + this.setSpacing(10); + this.setPadding(new Insets(15, 12, 15, 12)); + this.setStyle("-fx-background-color: #00bcf0;" + + "-fx-border-color: #303539 transparent transparent transparent;" + + "-fx-border-width: 5 0 0 0;"); + + languageBox = new ComboBox<>(); + languageBox.getItems().addAll(LanguageRegistry.getLanguages()); + + Locale activeLocale = lm.getLocale(); + LanguageOption activeOption = LanguageRegistry.getLanguages().stream() .filter(lang -> lang.locale().equals(activeLocale)) .findFirst() .orElse(LanguageRegistry.getDefaultLanguage()); - languageBox.setValue(activeOption); + languageBox.setValue(activeOption); - // Listens for changes in language from other sources (e.g. startView) - lm.getBundleProperty().subscribe(bundle -> { - java.util.Locale currentLocale = lm.getLocale(); + // Listens for changes in language from other sources (e.g. startView) + lm.getBundleProperty().subscribe(bundle -> { + java.util.Locale currentLocale = lm.getLocale(); - LanguageOption matchingOption = LanguageRegistry.getLanguages().stream() + LanguageOption matchingOption = LanguageRegistry.getLanguages().stream() .filter(lang -> lang.locale().equals(currentLocale)) .findFirst() .orElse(null); - if (matchingOption != null && !matchingOption.equals(languageBox.getValue())) { - languageBox.setValue(matchingOption); + if (matchingOption != null && !matchingOption.equals(languageBox.getValue())) { + languageBox.setValue(matchingOption); + } + }); + + languageBox.setCellFactory(list -> new ListCell<>() { + private Subscription cellSub; + @Override + protected void updateItem(LanguageOption item, boolean empty) { + super.updateItem(item, empty); + if (cellSub != null) { + cellSub.unsubscribe(); } - }); - - languageBox.setCellFactory(list -> new ListCell<>() { - private Subscription cellSub; - @Override - protected void updateItem(LanguageOption item, boolean empty) { - super.updateItem(item, empty); - if (cellSub != null) cellSub.unsubscribe(); - - if (empty || item == null) { - setText(null); - } else { - cellSub = lm.getBundleProperty().subscribe(bundle -> setText(item.name())); - } - } - }); - - languageBox.setButtonCell(languageBox.getCellFactory().call(null)); - - HBox loserBox = new HBox(); - - Label biggestLoserLabelText = new Label(); - biggestLoserLabelText.textProperty().bind(lm.bindString("biggestLoserLabelText")); - biggestLoserLabel = new Label(); - biggestLoserPriceLabel = new Label(); - biggestLoserPriceLabel.setStyle("-fx-text-fill: red;"); - - loserBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - loserBox.setPadding(new Insets(8, 14, 8, 14)); - loserBox.setAlignment(Pos.CENTER); - - loserBox.getChildren().addAll(biggestLoserLabelText, biggestLoserLabel, biggestLoserPriceLabel); - - HBox winnerBox = new HBox(); - - Label biggestWinnerLabelText = new Label(); - biggestWinnerLabelText.textProperty().bind(lm.bindString("biggestWinnerLabelText")); - biggestWinnerLabel = new Label(); - biggestWinnerPriceLabel = new Label(); - biggestWinnerPriceLabel.setStyle("-fx-text-fill: green;"); - winnerBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - winnerBox.setPadding(new Insets(8, 14, 8, 14)); - winnerBox.setAlignment(Pos.CENTER); - - winnerBox.getChildren().addAll(biggestWinnerLabelText, biggestWinnerLabel, biggestWinnerPriceLabel); - - - Region spacer = new Region(); - HBox.setHgrow(spacer, Priority.ALWAYS); - - HBox currentWeekBox = new HBox(); - currentWeekBox.setSpacing(10); - - currentWeekBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - currentWeekBox.setPadding(new Insets(8, 14, 8, 14)); - currentWeekBox.setAlignment(Pos.CENTER); - - Label currentWeekLabelText = new Label(); - currentWeekLabelText.textProperty().bind(lm.bindString("currentWeekLabelText")); - currentWeekLabel = new Label(); - currentWeekBox.getChildren().addAll(currentWeekLabelText, currentWeekLabel); - - advanceWeekButton = new Button(); - advanceWeekButton.textProperty().bind(lm.bindString("advanceWeekButton")); - advanceWeekButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - - this.getChildren().addAll(languageBox, loserBox, winnerBox, spacer, currentWeekBox, advanceWeekButton); - } - - /** - * Sets the exchange and subscribes to week updates. - * - * @param exchange the {@link Exchange} used in the game - */ - public void setExchange(Exchange exchange) { - this.exchange = exchange; - currentWeekSubscription = exchange.getCurrentWeekProperty().subscribe(newVal -> { - if (exchange != null) { - currentWeekLabel.setText(newVal.toString()); + if (empty || item == null) { + setText(null); } else { - currentWeekLabel.setText("None"); + cellSub = lm.getBundleProperty().subscribe(bundle -> setText(item.name())); } - }); - - if (biggestLoserSubscription != null) { - biggestLoserSubscription.unsubscribe(); - } - - biggestLoserSubscription = exchange.getCurrentWeekProperty().subscribe(newWeek -> { - Stock loser = exchange.getLosers(1).getFirst(); - biggestLoserLabel.setText(loser.getSymbol() + " - " + loser.getCompany()); - biggestLoserPriceLabel.setText(" $" + loser.getLatestPriceChange()); - }); - - if (biggestWinnerSubscription != null) { - biggestWinnerSubscription.unsubscribe(); - } - - biggestWinnerSubscription = exchange.getCurrentWeekProperty().subscribe(newWeek -> { - Stock winner = exchange.getGainers(1).getFirst(); - biggestWinnerLabel.setText(winner.getSymbol() + " - " + winner.getCompany()); - biggestWinnerPriceLabel.setText(" $" + winner.getLatestPriceChange()); - }); + } + }); + + languageBox.setButtonCell(languageBox.getCellFactory().call(null)); + + Label biggestLoserLabelText = new Label(); + biggestLoserLabelText.textProperty().bind(lm.bindString("biggestLoserLabelText")); + biggestLoserLabel = new Label(); + biggestLoserPriceLabel = new Label(); + biggestLoserPriceLabel.setStyle("-fx-text-fill: red;"); + + HBox loserBox = new HBox(); + loserBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + loserBox.setPadding(new Insets(8, 14, 8, 14)); + loserBox.setAlignment(Pos.CENTER); + + loserBox.getChildren().addAll(biggestLoserLabelText, biggestLoserLabel, biggestLoserPriceLabel); + + Label biggestWinnerLabelText = new Label(); + biggestWinnerLabelText.textProperty().bind(lm.bindString("biggestWinnerLabelText")); + biggestWinnerLabel = new Label(); + biggestWinnerPriceLabel = new Label(); + biggestWinnerPriceLabel.setStyle("-fx-text-fill: green;"); + + HBox winnerBox = new HBox(); + winnerBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + winnerBox.setPadding(new Insets(8, 14, 8, 14)); + winnerBox.setAlignment(Pos.CENTER); + + winnerBox.getChildren().addAll( + biggestWinnerLabelText, biggestWinnerLabel, biggestWinnerPriceLabel); + + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + HBox currentWeekBox = new HBox(); + currentWeekBox.setSpacing(10); + + currentWeekBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + currentWeekBox.setPadding(new Insets(8, 14, 8, 14)); + currentWeekBox.setAlignment(Pos.CENTER); + + Label currentWeekLabelText = new Label(); + currentWeekLabelText.textProperty().bind(lm.bindString("currentWeekLabelText")); + currentWeekLabel = new Label(); + currentWeekBox.getChildren().addAll(currentWeekLabelText, currentWeekLabel); + + advanceWeekButton = new Button(); + advanceWeekButton.textProperty().bind(lm.bindString("advanceWeekButton")); + advanceWeekButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + + this.getChildren().addAll( + languageBox, loserBox, winnerBox, spacer, currentWeekBox, advanceWeekButton); + } + + /** + * Sets the exchange and subscribes to week updates. + * + * @param exchange the {@link Exchange} used in the game + */ + public void setExchange(Exchange exchange) { + Subscription currentWeekSubscription = exchange.getCurrentWeekProperty().subscribe(newVal -> { + if (exchange != null) { + currentWeekLabel.setText(newVal.toString()); + } else { + currentWeekLabel.setText("None"); + } + }); + + if (biggestLoserSubscription != null) { + biggestLoserSubscription.unsubscribe(); } - /** - * Exposes the advanceWeekButton to {@link GameController} so it can - * advance the week of the {@link Exchange}. - * - * @param action the action to be performed when clicking the button - */ - public void onAdvanceButtonClick(Runnable action) { - advanceWeekButton.setOnAction(e -> action.run()); - } + biggestLoserSubscription = exchange.getCurrentWeekProperty().subscribe(newWeek -> { + Stock loser = exchange.getLosers(1).getFirst(); + biggestLoserLabel.setText(loser.getSymbol() + " - " + loser.getCompany()); + biggestLoserPriceLabel.setText(" $" + loser.getLatestPriceChange()); + }); - - /** - * Exoposes the LanguageOption ComboButton to the controller. - * - * @param action the action to be performed when selecting the language - */ - public void onLanguageChange(ConsumerExtends borderpane to allow easy organizing of the internal layout.
+ * *Uses a {@link LanguageManager} to set text to the targer language dynamically.
*/ public class MarketView extends BorderPane { - private final LanguageManager lm = LanguageManager.getInstance(); - - private Button purchaseButton; - private Label selectedStock; - - //Dynamic Labels/Text - public TextField gross; - public TextField commission; - public TextField total; - private TextField searchField; - - //StockListView - private ListViewSubscribes to a stock's sales price to update the value immediately.
+ * + *Subscribes to the current language to change text immediately.
+ * + *Uses a cell factory to format the string found in the stocksListView.
+ * + * @return the constructed MarketView + */ + private VBox centerPane() { + VBox vbox = new VBox(); + + vbox.setPadding(new Insets(15, 12, 15, 12)); + vbox.setSpacing(10); + + // Blue Background color + vbox.setStyle("-fx-background-color: #00bcf0;"); + + Label titleLabel = new Label(); + titleLabel.textProperty().bind(lm.bindString("marketTitle")); + titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; "); + + VBox titleBox = new VBox(titleLabel); + titleBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + titleBox.setAlignment(Pos.CENTER); + titleBox.setPadding(new Insets(4)); + titleBox.setMaxWidth(200); + + // Stock Graph + stockLineChartView.getChart().setMinHeight(0); + stockLineChartView.getChart().setMaxHeight(Double.MAX_VALUE); + stockLineChartView.getChart().setMinWidth(0); + stockLineChartView.getChart().setMaxWidth(Double.MAX_VALUE); + stockLineChartView.getChart().getXAxis().labelProperty().bind(lm.bindString("xAxisLabel")); + stockLineChartView.getChart().getYAxis().labelProperty().bind(lm.bindString("yAxisLabel")); + + // List of stocks + stocksListView = new ListView<>(); + stocksListView.setMinHeight(0); + stocksListView.setMaxHeight(Double.MAX_VALUE); + stocksListView.setMinWidth(0); + stocksListView.setMaxWidth(Double.MAX_VALUE); + stocksListView.setStyle("-fx-background-color: transparent;"); + + stocksListView.setCellFactory(list -> new ListCell<>() { + private Subscription cellSubscription; + private Subscription langSubscription; + + @Override + protected void updateItem(Stock stock, boolean empty) { + super.updateItem(stock, empty); + + if (cellSubscription != null) { + cellSubscription.unsubscribe(); + cellSubscription = null; + } + + if (langSubscription != null) { + langSubscription.unsubscribe(); + langSubscription = null; + } - /** - * Constructs the view and its components. - *Subscribes to a stock's sales price to update the value immediately.
- *Subscribes to the current language to change text immediately.
- *Uses a cell factory to format the string found in the stocksListView.
- * - * @return the constructed MarketView - */ - private VBox centerPane() { - VBox vBox = new VBox(); - - vBox.setPadding(new Insets(15, 12, 15, 12)); - vBox.setSpacing(10); - //Blue Background color - vBox.setStyle("-fx-background-color: #00bcf0;"); - - Label titleLabel = new Label(); - titleLabel.textProperty().bind(lm.bindString("marketTitle")); - titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; "); - - VBox titleBox = new VBox(titleLabel); - titleBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - titleBox.setAlignment(Pos.CENTER); - titleBox.setPadding(new Insets(4)); - titleBox.setMaxWidth(200); - - // Stock Graph - stockLineChartView.getChart().setMinHeight(0); - stockLineChartView.getChart().setMaxHeight(Double.MAX_VALUE); - stockLineChartView.getChart().setMinWidth(0); - stockLineChartView.getChart().setMaxWidth(Double.MAX_VALUE); - stockLineChartView.getChart().getXAxis().labelProperty().bind(lm.bindString("xAxisLabel")); - stockLineChartView.getChart().getYAxis().labelProperty().bind(lm.bindString("yAxisLabel")); - - // List of stocks - stocksListView = new ListView<>(); - stocksListView.setMinHeight(0); - stocksListView.setMaxHeight(Double.MAX_VALUE); - stocksListView.setMinWidth(0); - stocksListView.setMaxWidth(Double.MAX_VALUE); - stocksListView.setStyle("-fx-background-color: transparent;"); - - stocksListView.setCellFactory(list -> new ListCell<>() { - private Subscription cellSubscription; - private Subscription langSubscription; - - @Override - protected void updateItem(Stock stock, boolean empty) { - super.updateItem(stock, empty); - - if (cellSubscription != null) { - cellSubscription.unsubscribe(); - cellSubscription = null; - } - if (langSubscription != null) { - langSubscription.unsubscribe(); - langSubscription = null; - } - - if (empty || stock == null) { - setText(null); - } else { - Runnable updateTextAction = () -> { - String template = lm.getString("stockCellFormat"); - setText(String.format(template, + if (empty || stock == null) { + setText(null); + } else { + Runnable updateTextAction = () -> { + String template = lm.getString("stockCellFormat"); + setText(String.format(template, stock.getSymbol(), stock.getCompany(), FormatBigDecimal.formatNumber(stock.salesPriceProperty().get()), FormatBigDecimal.formatNumber(stock.getLatestPriceChange()), FormatBigDecimal.formatNumber(stock.getHighestPrice()), FormatBigDecimal.formatNumber(stock.getLowestPrice()) - )); - }; - - cellSubscription = stock.salesPriceProperty().subscribe(newPrice -> updateTextAction.run()); - langSubscription = lm.getBundleProperty().subscribe(bundle -> updateTextAction.run()); - - updateTextAction.run(); - } - } - }); - - HBox searchBox = new HBox(); - searchField = new TextField(); - searchField.promptTextProperty().bind(lm.bindString("search")); - searchBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - searchBox.setPadding(new Insets(8, 14, 8, 14)); - searchBox.setAlignment(Pos.CENTER_LEFT); - searchBox.setMaxWidth(Region.USE_PREF_SIZE); - searchBox.getChildren().addAll(searchField); - - - // Container for list of stocks - HBox stockListBox = new HBox(stocksListView); - stockListBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - // Container for graph of stocks - HBox stockChartBox = new HBox(stockLineChartView.getChart()); - stockChartBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - HBox stockBox = new HBox(stockListBox, stockChartBox); - stockBox.setSpacing(10); - - stockListBox.setPadding(new Insets(4)); - stockListBox.setMinHeight(0); - stockListBox.setMaxHeight(Double.MAX_VALUE); - stockListBox.setMinWidth(0); - stockListBox.setMaxWidth(Double.MAX_VALUE); - - VBox.setVgrow(stocksListView, Priority.ALWAYS); - HBox.setHgrow(stocksListView, Priority.ALWAYS); - VBox.setVgrow(stockLineChartView.getChart(), Priority.ALWAYS); - HBox.setHgrow(stockLineChartView.getChart(), Priority.ALWAYS); - VBox.setVgrow(stockListBox, Priority.ALWAYS); - HBox.setHgrow(stockListBox, Priority.ALWAYS); - VBox.setVgrow(stockChartBox, Priority.ALWAYS); - HBox.setHgrow(stockChartBox, Priority.ALWAYS); - VBox.setVgrow(stockBox, Priority.ALWAYS); - HBox.setHgrow(stockBox, Priority.ALWAYS); - - HBox selectedStockBox = new HBox(); - - Label selectedStockLabel = new Label(); - selectedStockLabel.textProperty().bind(lm.bindString("selectedStock")); - selectedStock = new Label(""); - - selectedStockBox.getChildren().addAll(selectedStockLabel, selectedStock); - - HBox quantityBox = new HBox(); + )); + }; - Label quantityLabel = new Label(); - quantityLabel.textProperty().bind(lm.bindString("purchaseQuantity")); - quantitySpinner = new Spinner<>(1, 1_000_000, 1); - quantitySpinner.setEditable(true); + cellSubscription = stock.salesPriceProperty() + .subscribe(newPrice -> updateTextAction.run()); + langSubscription = lm.getBundleProperty() + .subscribe(bundle -> updateTextAction.run()); - quantityBox.getChildren().addAll(quantityLabel, quantitySpinner); - - HBox calculationBox = new HBox(); - - Label grossLabel = new Label(); - grossLabel.textProperty().bind(lm.bindString("purchaseGross")); - gross = new TextField(); - gross.setEditable(false); - gross.setMaxWidth(200); - Label commissionLabel = new Label(); - commissionLabel.textProperty().bind(lm.bindString("purchaseCommission")); - commission = new TextField(); - commission.setEditable(false); - commission.setMaxWidth(200); - - calculationBox.getChildren().addAll(grossLabel, gross, commissionLabel, commission); - - HBox totalBox = new HBox(); - - Label totalLabel = new Label(); - totalLabel.textProperty().bind(lm.bindString("purchaseTotal")); - total = new TextField(""); - total.setEditable(false); - total.setMaxWidth(200); - - totalBox.getChildren().addAll(totalLabel, total); - - purchaseButton = new Button(); - purchaseButton.textProperty().bind(lm.bindString("purchaseButton")); - - VBox purchaseBox = new VBox(5); - - purchaseBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - purchaseBox.setPadding(new Insets(8, 14, 8, 14)); - purchaseBox.setAlignment(Pos.CENTER_LEFT); - - purchaseBox.getChildren().addAll(selectedStockBox, quantityBox, calculationBox, totalBox, purchaseButton); - - - - vBox.getChildren().addAll(titleBox, searchBox, + updateTextAction.run(); + } + } + }); + + HBox searchBox = new HBox(); + searchField = new TextField(); + searchField.promptTextProperty().bind(lm.bindString("search")); + searchBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + searchBox.setPadding(new Insets(8, 14, 8, 14)); + searchBox.setAlignment(Pos.CENTER_LEFT); + searchBox.setMaxWidth(Region.USE_PREF_SIZE); + searchBox.getChildren().addAll(searchField); + + + // Container for list of stocks + HBox stockListBox = new HBox(stocksListView); + stockListBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + // Container for graph of stocks + HBox stockChartBox = new HBox(stockLineChartView.getChart()); + stockChartBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + HBox stockBox = new HBox(stockListBox, stockChartBox); + stockBox.setSpacing(10); + + stockListBox.setPadding(new Insets(4)); + stockListBox.setMinHeight(0); + stockListBox.setMaxHeight(Double.MAX_VALUE); + stockListBox.setMinWidth(0); + stockListBox.setMaxWidth(Double.MAX_VALUE); + + VBox.setVgrow(stocksListView, Priority.ALWAYS); + HBox.setHgrow(stocksListView, Priority.ALWAYS); + VBox.setVgrow(stockLineChartView.getChart(), Priority.ALWAYS); + HBox.setHgrow(stockLineChartView.getChart(), Priority.ALWAYS); + VBox.setVgrow(stockListBox, Priority.ALWAYS); + HBox.setHgrow(stockListBox, Priority.ALWAYS); + VBox.setVgrow(stockChartBox, Priority.ALWAYS); + HBox.setHgrow(stockChartBox, Priority.ALWAYS); + VBox.setVgrow(stockBox, Priority.ALWAYS); + HBox.setHgrow(stockBox, Priority.ALWAYS); + + HBox selectedStockBox = new HBox(); + + Label selectedStockLabel = new Label(); + selectedStockLabel.textProperty().bind(lm.bindString("selectedStock")); + selectedStock = new Label(""); + + selectedStockBox.getChildren().addAll(selectedStockLabel, selectedStock); + + Label quantityLabel = new Label(); + quantityLabel.textProperty().bind(lm.bindString("purchaseQuantity")); + quantitySpinner = new Spinner<>(1, 1_000_000, 1); + quantitySpinner.setEditable(true); + + HBox quantityBox = new HBox(); + quantityBox.getChildren().addAll(quantityLabel, quantitySpinner); + + Label grossLabel = new Label(); + grossLabel.textProperty().bind(lm.bindString("purchaseGross")); + gross = new TextField(); + gross.setEditable(false); + gross.setMaxWidth(200); + Label commissionLabel = new Label(); + commissionLabel.textProperty().bind(lm.bindString("purchaseCommission")); + commission = new TextField(); + commission.setEditable(false); + commission.setMaxWidth(200); + + HBox calculationBox = new HBox(); + calculationBox.getChildren().addAll(grossLabel, gross, commissionLabel, commission); + + Label totalLabel = new Label(); + totalLabel.textProperty().bind(lm.bindString("purchaseTotal")); + total = new TextField(""); + total.setEditable(false); + total.setMaxWidth(200); + + HBox totalBox = new HBox(); + totalBox.getChildren().addAll(totalLabel, total); + + purchaseButton = new Button(); + purchaseButton.textProperty().bind(lm.bindString("purchaseButton")); + + VBox purchaseBox = new VBox(5); + + purchaseBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + purchaseBox.setPadding(new Insets(8, 14, 8, 14)); + purchaseBox.setAlignment(Pos.CENTER_LEFT); + + purchaseBox.getChildren().addAll( + selectedStockBox, quantityBox, calculationBox, totalBox, purchaseButton); + + + + vbox.getChildren().addAll(titleBox, searchBox, stockBox, purchaseBox); - return vBox; - } - - /** - * Sets and updates subscription to the selected stock's sales price. - * @param stock the selected stock - * @param priceChangeAction the action to run on price change (updates the sales price) - */ - public void setupPriceSubscription(Stock stock, ConsumerUses first a {@link FilteredList} to account for what the user has searched for.
- *Then utilises a {@link SortedList} to sort the stocks in the exchange alphabetically - * on their symbol/ticker.
- * - * @param exchange the exchange to be used for the view - */ - public void setExchange(Exchange exchange) { - this.exchange = exchange; - - - if (exchange != null) { - filteredStocksList = new FilteredList<>(exchange.getObservableStocks()); - - SortedListUses first a {@link FilteredList} to account for what the user has searched for.
+ * + *Then utilises a {@link SortedList} to sort the stocks in the exchange alphabetically + * on their symbol/ticker.
+ * + * @param exchange the exchange to be used for the view + */ + public void setExchange(Exchange exchange) { + if (exchange != null) { + filteredStocksList = new FilteredList<>(exchange.getObservableStocks()); + + SortedListUses a {@link Subscription} to observe the calculations made by the current - * Stock and Quantity selected.
- * - * @param purchaseCalculator the purchaseCalculator to be used for the view - */ - public void setPurchaseCalculator(PurchaseCalculator purchaseCalculator) { - this.purchaseCalculator = purchaseCalculator; - grossSubscription = purchaseCalculator.getGrossProperty().subscribe(newVal -> { - if (newVal != null) { - gross.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - gross.setText(""); - } - }); - commissionSubscription = purchaseCalculator.getCommissionProperty().subscribe(newVal -> { - if (newVal != null) { + } + + /** + * Sets the PurchaseCalculator to use for the view. + * + *Uses a {@link Subscription} to observe the calculations made by the current + * Stock and Quantity selected.
+ * + * @param purchaseCalculator the purchaseCalculator to be used for the view + */ + public void setPurchaseCalculator(PurchaseCalculator purchaseCalculator) { + Subscription grossSubscription = purchaseCalculator.getGrossProperty().subscribe(newVal -> { + if (newVal != null) { + gross.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + gross.setText(""); + } + }); + + Subscription commissionSubscription = + purchaseCalculator.getCommissionProperty().subscribe(newVal -> { + if (newVal != null) { commission.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { + } else { commission.setText(""); - } - }); - totalSubscription = purchaseCalculator.getTotalProperty().subscribe(newVal -> { - if (newVal != null) { - total.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - total.setText(""); - } - }); - } - - /** - * Returns the selected stock in the stocksListView. - * - * @return the selected stock in the stocksListView - */ - public Stock getSelectedStock() { - return stocksListView.getSelectionModel().getSelectedItem(); - } - - /** - * Returns the numeric value of the quantitySpinner for purchasing {@link Share}s in a stock. - * - * @return an integer of the amount of shares to buy - */ - public int getQuantityPurchase() { - return quantitySpinner.getValue(); - } - - /** - * Sets the company name of the selected stock in the stocksListView. - * - * @param selectedStockString the company name of the selected stock - */ - public void setSelectedStockLabel(String selectedStockString) { - selectedStock.setText(selectedStockString); - } - + } + }); + Subscription totalSubscription = purchaseCalculator.getTotalProperty().subscribe(newVal -> { + if (newVal != null) { + total.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + total.setText(""); + } + }); + } + + /** + * Returns the selected stock in the stocksListView. + * + * @return the selected stock in the stocksListView + */ + public Stock getSelectedStock() { + return stocksListView.getSelectionModel().getSelectedItem(); + } + + /** + * Returns the numeric value of the quantitySpinner for purchasing {@link Share}s in a stock. + * + * @return an integer of the amount of shares to buy + */ + public int getQuantityPurchase() { + return quantitySpinner.getValue(); + } + + /** + * Sets the company name of the selected stock in the stocksListView. + * + * @param selectedStockString the company name of the selected stock + */ + public void setSelectedStockLabel(String selectedStockString) { + selectedStock.setText(selectedStockString); + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/NavigationBar.java b/millions/src/main/java/no/ntnu/gruppe53/view/NavigationBar.java index 2360452..838e521 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/NavigationBar.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/NavigationBar.java @@ -1,5 +1,6 @@ package no.ntnu.gruppe53.view; +import java.math.RoundingMode; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button; @@ -12,235 +13,228 @@ import no.ntnu.gruppe53.model.Player; import no.ntnu.gruppe53.service.LanguageManager; -import java.math.RoundingMode; - - /* Yellow Color, Hex: #ffe556 RGB(255, 229, 86) Blue Color, Hex: #00bcf0 RGB(0, 188, 240) Black Color, Hex: #303539 RGB(48, 53, 57) */ - /** * Represents the top bar of the views. + * *Provides the user with the ability to switch between views on the fly by * clicking on the buttons representing the desired view.
+ * *The {@link no.ntnu.gruppe53.controller.GameController} handles * the actions for the buttons.
+ * *Uses a {@link LanguageManager} to set text of UI elements dynamically.
*/ public class NavigationBar extends HBox { - private final LanguageManager lm = LanguageManager.getInstance(); - - private final Button marketButton; - private final Button portfolioButton; - private final Button historyButton; - private final Button endGameButton; - private Subscription netWorthSubscription; - private Subscription moneySubscription; - private Subscription currentWeekSubscription; - - - - private Player player; - private Exchange exchange; - - //Navigation Buttons - - - //Dynamic Labels - private Label playerLabel; - private Label statusLabel; - private Label netWorthLabel; - private Label moneyLabel; - - /** - * Constructs the UI elements of the navigationBar. - *Binds the language manager to the textProperty of the UI elements to dynamically change the text.
- */ - public NavigationBar() { - - this.setPadding(new Insets(15, 12, 15, 12)); - this.setSpacing(10); - //Blue Background color - this.setStyle("-fx-background-color: #00bcf0;" + - "-fx-border-color: transparent transparent #303539 transparent;" + - "-fx-border-width: 0 0 5 0;"); - - - marketButton = new Button(); - marketButton.textProperty().bind(lm.bindString("marketButton")); - marketButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - portfolioButton = new Button(); - portfolioButton.textProperty().bind(lm.bindString("portfolioButton")); - portfolioButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - historyButton = new Button(); - historyButton.textProperty().bind(lm.bindString("historyButton")); - historyButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - - Region spacer = new Region(); - HBox.setHgrow(spacer, Priority.ALWAYS); - - - - HBox playerBox = new HBox(); - - Label playerLabelText = new Label(); - playerLabelText.textProperty().bind(lm.bindString("navPlayerLabelText")); - playerLabel = new Label("Player"); - - playerBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - playerBox.setPadding(new Insets(8, 14, 8, 14)); - playerBox.setAlignment(Pos.CENTER); - - playerBox.getChildren().addAll(playerLabelText, playerLabel); - - HBox statusBox = new HBox(); - - Label statusLabelText = new Label(); - statusLabelText.textProperty().bind(lm.bindString("statusLabelText")); - statusLabel = new Label(); - - statusBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - statusBox.setPadding(new Insets(8, 14, 8, 14)); - statusBox.setAlignment(Pos.CENTER); - - statusBox.getChildren().addAll(statusLabelText, statusLabel); - - HBox moneyBox = new HBox(); - - Label moneyLabelText = new Label(); - moneyLabelText.textProperty().bind(lm.bindString("navMoneyLabelText")); - moneyLabel = new Label(); - - moneyBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - moneyBox.setPadding(new Insets(8, 14, 8, 14)); - moneyBox.setAlignment(Pos.CENTER); - moneyBox.getChildren().addAll(moneyLabelText, moneyLabel); - - HBox networthBox = new HBox(); - - Label networthLabelText = new Label(); - networthLabelText.textProperty().bind(lm.bindString("navNetWorthLabelText")); - netWorthLabel = new Label(); - - networthBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - networthBox.setPadding(new Insets(8, 14, 8, 14)); - networthBox.setAlignment(Pos.CENTER); - networthBox.getChildren().addAll(networthLabelText, netWorthLabel); - - endGameButton = new Button(); - endGameButton.textProperty().bind(lm.bindString("endGameButton")); - endGameButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - - this.getChildren().addAll(marketButton, portfolioButton, historyButton, spacer, playerBox, statusBox, moneyBox, networthBox, endGameButton); - } - /** - * Exposes the marketButton to the GameController. - * - * @param action the action to be run when clicking the button - */ - public void onMarketButtonClick(Runnable action) { - marketButton.setOnAction(e -> action.run()); + private final Button marketButton; + private final Button portfolioButton; + private final Button historyButton; + private final Button endGameButton; + private Subscription netWorthSubscription; + + private Player player; + + // Dynamic Labels + private final Label playerLabel; + private final Label statusLabel; + private final Label netWorthLabel; + private final Label moneyLabel; + + /** + * Constructs the UI elements of the navigationBar. + * + *Binds the language manager to the textProperty of the + * UI elements to dynamically change the text.
+ */ + public NavigationBar() { + this.setPadding(new Insets(15, 12, 15, 12)); + this.setSpacing(10); + // Blue Background color + this.setStyle("-fx-background-color: #00bcf0;" + + "-fx-border-color: transparent transparent #303539 transparent;" + + "-fx-border-width: 0 0 5 0;"); + + marketButton = new Button(); + LanguageManager lm = LanguageManager.getInstance(); + marketButton.textProperty().bind(lm.bindString("marketButton")); + marketButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + portfolioButton = new Button(); + portfolioButton.textProperty().bind(lm.bindString("portfolioButton")); + portfolioButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + historyButton = new Button(); + historyButton.textProperty().bind(lm.bindString("historyButton")); + historyButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + + Region spacer = new Region(); + HBox.setHgrow(spacer, Priority.ALWAYS); + + HBox playerBox = new HBox(); + + Label playerLabelText = new Label(); + playerLabelText.textProperty().bind(lm.bindString("navPlayerLabelText")); + playerLabel = new Label("Player"); + + playerBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + playerBox.setPadding(new Insets(8, 14, 8, 14)); + playerBox.setAlignment(Pos.CENTER); + + playerBox.getChildren().addAll(playerLabelText, playerLabel); + + HBox statusBox = new HBox(); + + Label statusLabelText = new Label(); + statusLabelText.textProperty().bind(lm.bindString("statusLabelText")); + statusLabel = new Label(); + + statusBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + statusBox.setPadding(new Insets(8, 14, 8, 14)); + statusBox.setAlignment(Pos.CENTER); + + statusBox.getChildren().addAll(statusLabelText, statusLabel); + + HBox moneyBox = new HBox(); + + Label moneyLabelText = new Label(); + moneyLabelText.textProperty().bind(lm.bindString("navMoneyLabelText")); + moneyLabel = new Label(); + + moneyBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + moneyBox.setPadding(new Insets(8, 14, 8, 14)); + moneyBox.setAlignment(Pos.CENTER); + moneyBox.getChildren().addAll(moneyLabelText, moneyLabel); + + HBox networthBox = new HBox(); + + Label networthLabelText = new Label(); + networthLabelText.textProperty().bind(lm.bindString("navNetWorthLabelText")); + netWorthLabel = new Label(); + + networthBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + networthBox.setPadding(new Insets(8, 14, 8, 14)); + networthBox.setAlignment(Pos.CENTER); + networthBox.getChildren().addAll(networthLabelText, netWorthLabel); + + endGameButton = new Button(); + endGameButton.textProperty().bind(lm.bindString("endGameButton")); + endGameButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + + this.getChildren().addAll( + marketButton, portfolioButton, historyButton, + spacer, playerBox, statusBox, moneyBox, networthBox, endGameButton); + } + + /** + * Exposes the marketButton to the GameController. + * + * @param action the action to be run when clicking the button + */ + public void onMarketButtonClick(Runnable action) { + marketButton.setOnAction(e -> action.run()); + } + + /** + * Exposes the portfolioButton to the GameController. + * + * @param action the action to be run when clicking the button + */ + public void onPortfolioButtonClick(Runnable action) { + portfolioButton.setOnAction(e -> action.run()); + } + + /** + * Exposes the historyButton to the GameController. + * + * @param action the action to be run when clicking the button + */ + public void onHistoryButtonClick(Runnable action) { + historyButton.setOnAction(e -> action.run()); + } + + /** + * Exposes the endGameButton to the GameController. + * + * @param action the action to be run when clicking the button + */ + public void onEndGameButtonClick(Runnable action) { + endGameButton.setOnAction(e -> action.run()); + } + + /** + * Binds a subscription/observer to a {@link Player}. + * + *It specifically listens to the players money, net worth and name.
+ * + * @param player the player object to be observed + */ + public void bindPlayer(Player player) { + this.player = player; + + if (netWorthSubscription != null) { + netWorthSubscription.unsubscribe(); } - /** - * Exposes the portfolioButton to the GameController. - * - * @param action the action to be run when clicking the button - */ - public void onPortfolioButtonClick(Runnable action) { - portfolioButton.setOnAction(e -> action.run()); - } + if (player != null) { + playerLabel.setText(player.getName()); + netWorthSubscription = player.getNetWorthProperty().subscribe(newVal -> { + + if (newVal != null) { + netWorthLabel.setText("$" + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + netWorthLabel.setText("$0.00"); + } + }); + + Subscription moneySubscription = player.getMoneyProperty().subscribe(newVal -> { + if (newVal != null) { + moneyLabel.setText("$" + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + moneyLabel.setText("$0.00"); + } + }); - /** - * Exposes the historyButton to the GameController. - * - * @param action the action to be run when clicking the button - */ - public void onHistoryButtonClick(Runnable action) { - historyButton.setOnAction(e -> action.run()); } - - /** - * Exposes the endGameButton to the GameController. - * - * @param action the action to be run when clicking the button - */ - public void onEndGameButtonClick(Runnable action) { - endGameButton.setOnAction(e -> action.run()); - } - - - /** - * Binds a subscription/observer to a {@link Player}. - *It specifically listens to the players money, net worth and name.
- * - * @param player the player object to be observed - */ - public void bindPlayer(Player player) { - this.player = player; - - if (netWorthSubscription != null) { - netWorthSubscription.unsubscribe(); - } - - if (player != null) { - playerLabel.setText(player.getName()); - netWorthSubscription = player.getNetWorthProperty().subscribe(newVal -> { - if (newVal != null) { - netWorthLabel.setText("$" + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - netWorthLabel.setText("$0.00"); - } - }); - moneySubscription = player.getMoneyProperty().subscribe(newVal -> { - if (newVal != null) { - moneyLabel.setText("$" + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - moneyLabel.setText("$0.00"); - } - }); - - } - } - - /** - * Binds a subscription/observer to a {@link Exchange}. - *It specifically listens to week changes so that it can update the player status.
- * - * @param exchange the exchange object to be observed - */ - public void bindExchange(Exchange exchange) { - this.exchange = exchange; - - currentWeekSubscription = exchange.getCurrentWeekProperty().subscribe(newVal -> { - statusLabel.setText(player.getStatus(exchange)); - }); - } - - + } + + /** + * Binds a subscription/observer to a {@link Exchange}. + * + *It specifically listens to week changes so that it can update the player status.
+ * + * @param exchange the exchange object to be observed + */ + public void bindExchange(Exchange exchange) { + Subscription currentWeekSubscription = exchange.getCurrentWeekProperty().subscribe(newVal -> { + statusLabel.setText(player.getStatus(exchange)); + }); + } } diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/PlayerNameChooserView.java b/millions/src/main/java/no/ntnu/gruppe53/view/PlayerNameChooserView.java index 0711ae2..046fcb1 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/PlayerNameChooserView.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/PlayerNameChooserView.java @@ -1,15 +1,19 @@ package no.ntnu.gruppe53.view; -import no.ntnu.gruppe53.model.Player; - +import java.util.Optional; import javafx.geometry.Insets; -import javafx.scene.control.*; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonBar; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Dialog; +import javafx.scene.control.Label; +import javafx.scene.control.TextField; +import javafx.scene.control.TextFormatter; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; +import no.ntnu.gruppe53.model.Player; import no.ntnu.gruppe53.service.LanguageManager; -import java.util.Optional; - /* Yellow Color, Hex: #ffe556 RGB(255, 229, 86) Blue Color, Hex: #00bcf0 RGB(0, 188, 240) @@ -17,93 +21,94 @@ */ /** - * Represents a prompt for the {@link Player}'s name + * Represents a prompt for the {@link Player}'s name. */ public class PlayerNameChooserView { - private final LanguageManager lm = LanguageManager.getInstance(); - DialogA {@link TextFormatter} is used to set the maximum amount - * of characters for the player name.
- *Uses a {@link LanguageManager} to determine text language.
- * - * @return the dialog for player name input - */ - public OptionalA {@link TextFormatter} is used to set the maximum amount + * of characters for the player name.
+ * + *Uses a {@link LanguageManager} to determine text language.
+ * + * @return the dialog for player name input + */ + public OptionalUses a {@link LanguageManager} to set text to target language.
*/ public class PlayerStartingMoneyChooserView { - DialogUses a {@link TextFormatter} and listener for value integrity.
- *Uses a {@link SpinnerValueFactory} to set min, max, default, - * and step size values for the spinner.
- * @return the dialog for player's starting money - */ - public OptionalUses a {@link TextFormatter} and listener for value integrity.
+ * + *Uses a {@link SpinnerValueFactory} to set min, max, default, + * and step size values for the spinner.
+ * + * @return the dialog for player's starting money + */ + public OptionalLets the player view their current {@link Share} assets, see their * current sale value, whether the value has gone up or down since they purchased, * and the ability to sell the share for money.
+ * *Extends the {@link BorderPane}
for easy layout setup. + * *Events are handled by the {@link no.ntnu.gruppe53.controller.GameController}.
+ * *Uses a {@link LanguageManager} to dynamically set text based on target language.
*/ public class PortfolioView extends BorderPane { - private final LanguageManager lm = LanguageManager.getInstance(); - - private Button sellButton; - - //Static Labels - private Label titleLabel; - - //Dynamic Labels - private Label selectedShare; - private TextField gross; - private TextField commission; - private TextField tax; - private TextField total; - private TextField profit; - private TextField searchField; - - //PortfolioListView - private ListViewSubscribes to shares for sales price updates.
- *Uses a cell factory to format the displayed string representing each share. - * The sell factory has the text dynamically set by the language manager.
- * - * @return a VBox of the portfolio view - */ - private VBox centerPane() { - VBox vBox = new VBox(); - vBox.setPadding(new Insets(15, 12, 15, 12)); - vBox.setSpacing(10); - //Blue Background color - vBox.setStyle("-fx-background-color: #00bcf0; "); - - titleLabel = new Label(); - titleLabel.textProperty().bind(lm.bindString("portfolioTitle")); - titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; -fx-text-fill: #303539;"); - - VBox titleBox = new VBox(titleLabel); - titleBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - titleBox.setAlignment(Pos.CENTER); - titleBox.setPadding(new Insets(4)); - titleBox.setMaxWidth(200); - - portfolioListView = new ListView<>(); - portfolioListView.setMinHeight(0); - portfolioListView.setMaxHeight(Double.MAX_VALUE); - - portfolioListView.setCellFactory(list -> new ListCell<>() { - private Subscription cellSubscription; - private Subscription langSubscription; - - @Override - protected void updateItem(Share item, boolean empty) { - super.updateItem(item, empty); - - if (cellSubscription != null) { - cellSubscription.unsubscribe(); - cellSubscription = null; - } - if (langSubscription != null) { - langSubscription.unsubscribe(); - langSubscription = null; - } - - if (empty || item == null || item.getStock() == null) { - setText(null); - setGraphic(null); - } else { - setText(null); - - - Runnable updateGraphicAction = () -> { - BigDecimal currentPrice = item.getStock().salesPriceProperty().get(); - setGraphic(createColoredShareText(item, currentPrice)); - }; - - cellSubscription = item.getStock().salesPriceProperty().subscribe(currentPrice -> { - updateGraphicAction.run(); - }); - - langSubscription = lm.getBundleProperty().subscribe(bundle -> { - updateGraphicAction.run(); - }); - - updateGraphicAction.run(); - } + private final LanguageManager lm = LanguageManager.getInstance(); + + private Button sellButton; + + // Dynamic Labels + private Label selectedShare; + private TextField gross; + private TextField commission; + private TextField tax; + private TextField total; + private TextField profit; + private TextField searchField; + + // PortfolioListView + private ListViewSubscribes to shares for sales price updates.
+ * + *Uses a cell factory to format the displayed string representing each share. + * The sell factory has the text dynamically set by the language manager.
+ * + * @return a VBox of the portfolio view + */ + private VBox centerPane() { + VBox vbox = new VBox(); + vbox.setPadding(new Insets(15, 12, 15, 12)); + vbox.setSpacing(10); + // Blue Background color + vbox.setStyle("-fx-background-color: #00bcf0; "); + + Label titleLabel = new Label(); + titleLabel.textProperty().bind(lm.bindString("portfolioTitle")); + titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; -fx-text-fill: #303539;"); + + VBox titleBox = new VBox(titleLabel); + titleBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + titleBox.setAlignment(Pos.CENTER); + titleBox.setPadding(new Insets(4)); + titleBox.setMaxWidth(200); + + portfolioListView = new ListView<>(); + portfolioListView.setMinHeight(0); + portfolioListView.setMaxHeight(Double.MAX_VALUE); + + portfolioListView.setCellFactory(list -> new ListCell<>() { + private Subscription cellSubscription; + private Subscription langSubscription; + + @Override + protected void updateItem(Share item, boolean empty) { + super.updateItem(item, empty); + + if (cellSubscription != null) { + cellSubscription.unsubscribe(); + cellSubscription = null; } - }); - - HBox searchBox = new HBox(); - searchField = new TextField(); - searchField.promptTextProperty().bind(lm.bindString("search")); - searchBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - - searchBox.setPadding(new Insets(8, 14, 8, 14)); - searchBox.setAlignment(Pos.CENTER_LEFT); - searchBox.setMaxWidth(Region.USE_PREF_SIZE); - searchBox.getChildren().addAll(searchField); - - VBox portfolioListBox = new VBox(portfolioListView); - portfolioListBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - portfolioListBox.setPadding(new Insets(4)); - portfolioListBox.setMinHeight(0); - portfolioListBox.setMaxHeight(Double.MAX_VALUE); - - // Ensures the portfoliolist grows to fit the available screenspace - VBox.setVgrow(portfolioListView, Priority.ALWAYS); - VBox.setVgrow(portfolioListBox, Priority.ALWAYS); - - - HBox selectedShareBox = new HBox(); - - Label selectedShareLabel = new Label(); - selectedShareLabel.textProperty().bind(lm.bindString("selectedShare")); - selectedShare = new Label(); - - selectedShareBox.getChildren().addAll(selectedShareLabel, selectedShare); - - HBox calculationBox = new HBox(); - Label grossLabel = new Label(); - grossLabel.textProperty().bind(lm.bindString("portfolioGross")); - gross = new TextField(); - gross.setEditable(false); - gross.setMaxWidth(200); - Label commissionLabel = new Label(); - commissionLabel.textProperty().bind(lm.bindString("portfolioCommission")); - commission = new TextField(); - commission.setEditable(false); - commission.setMaxWidth(200); - Label taxLabel = new Label(); - taxLabel.textProperty().bind(lm.bindString("portfolioTax")); - tax = new TextField(); - tax.setEditable(false); - tax.setMaxWidth(200); - - calculationBox.getChildren().addAll(grossLabel, gross, commissionLabel, commission, taxLabel, tax); - - - - HBox totalBox = new HBox(); - - Label totalLabel = new Label(); - totalLabel.textProperty().bind(lm.bindString("portfolioTotal")); - total = new TextField(); - total.setEditable(false); - total.setMaxWidth(200); - - Label profitLabel = new Label(); - profitLabel.textProperty().bind(lm.bindString("portfolioProfit")); - profit = new TextField(); - profit.setEditable(false); - profit.setMaxWidth(200); - - totalBox.getChildren().addAll(totalLabel, total, profitLabel, profit); - - sellButton = new Button(); - sellButton.textProperty().bind(lm.bindString("sellButton")); + if (langSubscription != null) { + langSubscription.unsubscribe(); + langSubscription = null; + } - VBox saleBox = new VBox(5); + if (empty || item == null || item.getStock() == null) { + setText(null); + setGraphic(null); + } else { + setText(null); - saleBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - saleBox.setPadding(new Insets(8, 14, 8, 14)); - saleBox.setAlignment(Pos.CENTER_LEFT); + Runnable updateGraphicAction = () -> { + BigDecimal currentPrice = item.getStock().salesPriceProperty().get(); + setGraphic(createColoredShareText(item, currentPrice)); + }; - saleBox.getChildren().addAll(selectedShareBox, calculationBox, totalBox, sellButton); + cellSubscription = item.getStock().salesPriceProperty().subscribe(currentPrice -> { + updateGraphicAction.run(); + }); + langSubscription = lm.getBundleProperty().subscribe(bundle -> { + updateGraphicAction.run(); + }); - vBox.getChildren().addAll(titleBox, searchBox, + updateGraphicAction.run(); + } + } + }); + + HBox searchBox = new HBox(); + searchField = new TextField(); + searchField.promptTextProperty().bind(lm.bindString("search")); + searchBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + searchBox.setPadding(new Insets(8, 14, 8, 14)); + searchBox.setAlignment(Pos.CENTER_LEFT); + searchBox.setMaxWidth(Region.USE_PREF_SIZE); + searchBox.getChildren().addAll(searchField); + + VBox portfolioListBox = new VBox(portfolioListView); + portfolioListBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + portfolioListBox.setPadding(new Insets(4)); + portfolioListBox.setMinHeight(0); + portfolioListBox.setMaxHeight(Double.MAX_VALUE); + + // Ensures the portfoliolist grows to fit the available screenspace + VBox.setVgrow(portfolioListView, Priority.ALWAYS); + VBox.setVgrow(portfolioListBox, Priority.ALWAYS); + + HBox selectedShareBox = new HBox(); + + Label selectedShareLabel = new Label(); + selectedShareLabel.textProperty().bind(lm.bindString("selectedShare")); + selectedShare = new Label(); + + selectedShareBox.getChildren().addAll(selectedShareLabel, selectedShare); + + Label grossLabel = new Label(); + grossLabel.textProperty().bind(lm.bindString("portfolioGross")); + gross = new TextField(); + gross.setEditable(false); + gross.setMaxWidth(200); + Label commissionLabel = new Label(); + commissionLabel.textProperty().bind(lm.bindString("portfolioCommission")); + commission = new TextField(); + commission.setEditable(false); + commission.setMaxWidth(200); + Label taxLabel = new Label(); + taxLabel.textProperty().bind(lm.bindString("portfolioTax")); + tax = new TextField(); + tax.setEditable(false); + tax.setMaxWidth(200); + + HBox calculationBox = new HBox(); + calculationBox.getChildren().addAll( + grossLabel, gross, commissionLabel, commission, taxLabel, tax); + + Label totalLabel = new Label(); + totalLabel.textProperty().bind(lm.bindString("portfolioTotal")); + total = new TextField(); + total.setEditable(false); + total.setMaxWidth(200); + + Label profitLabel = new Label(); + profitLabel.textProperty().bind(lm.bindString("portfolioProfit")); + profit = new TextField(); + profit.setEditable(false); + profit.setMaxWidth(200); + + HBox totalBox = new HBox(); + totalBox.getChildren().addAll(totalLabel, total, profitLabel, profit); + + sellButton = new Button(); + sellButton.textProperty().bind(lm.bindString("sellButton")); + + VBox saleBox = new VBox(5); + + saleBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + saleBox.setPadding(new Insets(8, 14, 8, 14)); + saleBox.setAlignment(Pos.CENTER_LEFT); + + saleBox.getChildren().addAll(selectedShareBox, calculationBox, totalBox, sellButton); + + + vbox.getChildren().addAll(titleBox, searchBox, portfolioListBox, saleBox); - return vBox; - } - - /** - * Exposes the sell button to the GameController. - * @param action the action to be run when pressing the sell button - */ - public void onSellButton(Runnable action) { - sellButton.setOnAction(e -> action.run()); - } - - /** - * Sets the action to be run on selecting a share in portfolioListView. - * @param action the action to run when selecting a share - */ - public void onShareSelection(ConsumerThe values observed are the players portfolio and name.
- *Uses a {@link FilteredList} to get and filter the shares and - * binds it to the portfolioListView.
- * - * @param player the player to be observed - */ - public void setPlayer(Player player) { - this.player = player; - - if (player != null && player.getPortfolio() != null) { - - filteredPortfolioList = new FilteredList<>(player.getPortfolio().getShares()); - - portfolioListView.setItems(filteredPortfolioList); - - searchField.textProperty().addListener((observable, oldText, newText) -> { - String search = newText == null ? "" : newText.toLowerCase(); - - filteredPortfolioList.setPredicate(share -> search.isBlank() + return vbox; + } + + /** + * Exposes the sell button to the GameController. + * + * @param action the action to be run when pressing the sell button + */ + public void onSellButton(Runnable action) { + sellButton.setOnAction(e -> action.run()); + } + + /** + * Sets the action to be run on selecting a share in portfolioListView. + * + * @param action the action to run when selecting a share + */ + public void onShareSelection(ConsumerThe values observed are the players portfolio and name.
+ * + *Uses a {@link FilteredList} to get and filter the shares and + * binds it to the portfolioListView.
+ * + * @param player the player to be observed + */ + public void setPlayer(Player player) { + if (player != null && player.getPortfolio() != null) { + filteredPortfolioList = new FilteredList<>(player.getPortfolio().getShares()); + + portfolioListView.setItems(filteredPortfolioList); + + searchField.textProperty().addListener((observable, oldText, newText) -> { + String search = newText == null ? "" : newText.toLowerCase(); + + filteredPortfolioList.setPredicate(share -> search.isBlank() || share.getStock().getSymbol().toLowerCase().contains(search) || share.getStock().getCompany().toLowerCase().contains(search) - ); - }); - - } else { + ); + }); - portfolioListView.setItems(null); - } - } + } else { - /** - * Sets the share name of the selected share in the portfolioListView. - * - * @param selectedShareString the share name of the selected share - */ - public void setSelectedShareLabel(String selectedShareString) { - selectedShare.setText(selectedShareString); + portfolioListView.setItems(null); } - - /** - * Sets the SaleCalculator to use for the view. - *Uses a {@link Subscription} to observe the calculations made by the current - * Share selected.
- * - * @param saleCalculator the SaleCalculator to be used for the view - */ - public void setSaleCalculator(SaleCalculator saleCalculator) { - this.saleCalculator = saleCalculator; - grossSubscription = saleCalculator.getGrossProperty().subscribe(newVal -> { - if (newVal != null) { + } + + /** + * Sets the share name of the selected share in the portfolioListView. + * + * @param selectedShareString the share name of the selected share + */ + public void setSelectedShareLabel(String selectedShareString) { + selectedShare.setText(selectedShareString); + } + + /** + * Sets the SaleCalculator to use for the view. + * + *Uses a {@link Subscription} to observe the calculations made by the current + * Share selected.
+ * + * @param saleCalculator the SaleCalculator to be used for the view + */ + public void setSaleCalculator(SaleCalculator saleCalculator) { + Subscription grossSubscription = + saleCalculator.getGrossProperty().subscribe(newVal -> { + if (newVal != null) { gross.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { + } else { gross.setText(""); - } - }); - commissionSubscription = saleCalculator.getCommissionProperty().subscribe(newVal -> { - if (newVal != null) { + } + }); + + Subscription commissionSubscription = + saleCalculator.getCommissionProperty().subscribe(newVal -> { + if (newVal != null) { commission.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { + } else { commission.setText(""); - } - }); - taxSubscription = saleCalculator.getTaxProperty().subscribe(newVal -> { - if (newVal != null) { - tax.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN).abs()); - } else { - tax.setText(""); - } - }); - totalSubscription = saleCalculator.getTotalProperty().subscribe(newVal -> { - if (newVal != null) { - total.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - total.setText(""); - } - }); - profitSubscription = saleCalculator.getProfitProperty().subscribe(newVal -> { - if (newVal != null) { - profit.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); - } else { - profit.setText(""); - } - }); - } - + } + }); - /** - * Formats the text representation of the share in the portfolioListView - * and applies a color to it based on its current sales price compared - * to the buy price of the share. - * - * @param share the share to be formatted - * @param currentPrice the cusort the stocks in the exchange alphabetically - * on their symbol/tickerrrent price of the share - * @return a {@link TextFlow} representation of the share - */ - private TextFlow createColoredShareText(Share share, BigDecimal currentPrice) { - String text = share.getStock().getSymbol() + Subscription taxSubscription = saleCalculator.getTaxProperty().subscribe(newVal -> { + if (newVal != null) { + tax.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN).abs()); + } else { + tax.setText(""); + } + }); + + Subscription totalSubscription = saleCalculator.getTotalProperty().subscribe(newVal -> { + if (newVal != null) { + total.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + total.setText(""); + } + }); + + Subscription profitSubscription = saleCalculator.getProfitProperty().subscribe(newVal -> { + if (newVal != null) { + profit.setText("$ " + newVal.setScale(2, RoundingMode.HALF_EVEN)); + } else { + profit.setText(""); + } + }); + } + + /** + * Formats the text representation of the share in the portfolioListView + * and applies a color to it based on its current sales price compared + * to the buy price of the share. + * + * @param share the share to be formatted + * @param currentPrice current price of the stock the share belongs to + * @return a {@link TextFlow} representation of the share + */ + private TextFlow createColoredShareText(Share share, BigDecimal currentPrice) { + String text = share.getStock().getSymbol() + " - " + share.getStock().getCompany() + " | " @@ -390,17 +389,22 @@ private TextFlow createColoredShareText(Share share, BigDecimal currentPrice) { + lm.getString("portfolioCurrentPrice") + "$"; - Text t1 = new Text(text); - Text tValue = new Text(FormatBigDecimal.formatNumber(currentPrice)); + Text t1 = new Text(text); + Text tvalue = new Text(FormatBigDecimal.formatNumber(currentPrice)); - BigDecimal buyPrice = share.getPurchasePrice(); - if (buyPrice != null && currentPrice != null) { - int compare = currentPrice.compareTo(buyPrice); - if (compare > 0) tValue.setStyle("-fx-fill: #2ecc71; -fx-font-weight: bold;"); - else if (compare < 0) tValue.setStyle("-fx-fill: #e74c3c; -fx-font-weight: bold;"); - else tValue.setStyle("-fx-fill: #000000;"); - } + BigDecimal buyPrice = share.getPurchasePrice(); + if (buyPrice != null && currentPrice != null) { + int compare = currentPrice.compareTo(buyPrice); - return new TextFlow(t1, tValue); + if (compare > 0) { + tvalue.setStyle("-fx-fill: #2ecc71; -fx-font-weight: bold;"); + } else if (compare < 0) { + tvalue.setStyle("-fx-fill: #e74c3c; -fx-font-weight: bold;"); + } else { + tvalue.setStyle("-fx-fill: #000000;"); + } } + + return new TextFlow(t1, tvalue); + } } \ No newline at end of file diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/StartView.java b/millions/src/main/java/no/ntnu/gruppe53/view/StartView.java index a49d52b..264fa74 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/StartView.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/StartView.java @@ -5,7 +5,6 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; - import javafx.util.Subscription; import no.ntnu.gruppe53.controller.StartViewController; import no.ntnu.gruppe53.controller.ViewController; @@ -13,77 +12,77 @@ /** * Represents the first page seen by the user of the application. + * *Uses a {@link LanguageManager} for dynamically setting button and label text. * Subscribes to changes in language set by the manager.
*/ public class StartView extends VBox { - private final Button newGameButton; - private final Button languageButton; - private final Button quitButton; - private final Image logo; - private Subscription languageSubscription; - - /** - * Constructs the view and sets parameters to be exposed for the {@link StartViewController}. - * - * @param vm the {@link ViewController} for the view - */ - public StartView(ViewController vm) { - LanguageManager lm = LanguageManager.getInstance(); + private final Button newGameButton; + private final Button languageButton; + private final Button quitButton; - this.setAlignment(Pos.CENTER); - this.setSpacing(20); + /** + * Constructs the view and sets parameters to be exposed for the {@link StartViewController}. + * + * @param vm the {@link ViewController} for the view + */ + public StartView(ViewController vm) { + this.setAlignment(Pos.CENTER); + this.setSpacing(20); - this.setStyle("-fx-background-color: #00bcf0;"); + this.setStyle("-fx-background-color: #00bcf0;"); - logo = new Image(getClass().getClassLoader().getResourceAsStream("Millions-logo.png")); - ImageView logoView = new ImageView(logo); - logoView.setFitWidth(300); - logoView.setPreserveRatio(true); + Image logo = new Image(getClass().getClassLoader().getResourceAsStream("Millions-logo.png")); + ImageView logoView = new ImageView(logo); + logoView.setFitWidth(300); + logoView.setPreserveRatio(true); - newGameButton = new Button(); - newGameButton.textProperty().bind(lm.bindString("newGame")); + LanguageManager lm = LanguageManager.getInstance(); + newGameButton = new Button(); + newGameButton.textProperty().bind(lm.bindString("newGame")); - languageButton = new Button(); - languageButton.setPrefWidth(200); - languageButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - languageSubscription = lm.getBundleProperty().subscribe(bundle -> { - languageButton.setText(lm.getString("languageButtonLabel")); - }); + languageButton = new Button(); + languageButton.setPrefWidth(200); + languageButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + Subscription languageSubscription = lm.getBundleProperty().subscribe(bundle -> { + languageButton.setText(lm.getString("languageButtonLabel")); + }); - quitButton = new Button(); - quitButton.textProperty().bind(lm.bindString("quitGame")); + quitButton = new Button(); + quitButton.textProperty().bind(lm.bindString("quitGame")); - newGameButton.setPrefWidth(200); - newGameButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - quitButton.setPrefWidth(200); - quitButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + newGameButton.setPrefWidth(200); + newGameButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); + quitButton.setPrefWidth(200); + quitButton.setStyle("-fx-background-color: #ffe556; -fx-text-fill: #303539;"); - this.getChildren().addAll(logoView, newGameButton, languageButton, quitButton); - } + this.getChildren().addAll(logoView, newGameButton, languageButton, quitButton); + } - /** - * Sets the method to be run when the new game button is pressed - * - * @param action the method to execute on button press - */ - public void setOnNewGame(Runnable action) { - newGameButton.setOnAction(e -> action.run()); - } + /** + * Sets the method to be run when the new game button is pressed. + * + * @param action the method to execute on button press + */ + public void setOnNewGame(Runnable action) { + newGameButton.setOnAction(e -> action.run()); + } - /** - * Sets the method to be run when the languageButton is pressed - * - * @param action the method to execute on button press - */ - public void setOnLanguage(Runnable action) {languageButton.setOnAction(e -> action.run());} + /** + * Sets the method to be run when the languageButton is pressed. + * + * @param action the method to execute on button press + */ + public void setOnLanguage(Runnable action) { + languageButton.setOnAction(e -> action.run()); + } - /** - * Sets the method to be run when the quit game button is pressed - * - * @param action the method to execute on button press - */ - public void setOnQuit(Runnable action) { - quitButton.setOnAction(e -> action.run()); - } + /** + * Sets the method to be run when the quit game button is pressed. + * + * @param action the method to execute on button press + */ + public void setOnQuit(Runnable action) { + quitButton.setOnAction(e -> action.run()); + } } \ No newline at end of file diff --git a/millions/src/main/java/no/ntnu/gruppe53/view/StockLineChartView.java b/millions/src/main/java/no/ntnu/gruppe53/view/StockLineChartView.java index adb5dc5..048d5b9 100644 --- a/millions/src/main/java/no/ntnu/gruppe53/view/StockLineChartView.java +++ b/millions/src/main/java/no/ntnu/gruppe53/view/StockLineChartView.java @@ -1,126 +1,128 @@ package no.ntnu.gruppe53.view; + +import java.util.List; import javafx.geometry.Side; import javafx.scene.chart.LineChart; import javafx.scene.chart.NumberAxis; import javafx.scene.chart.XYChart; import no.ntnu.gruppe53.model.Stock; -import java.util.List; - /** * Represents a {@link LineChart} view of a {@link Stock}. + * *Y-axis: Price as a {@code double} value. Represented by a {@link NumberAxis}
+ * *X-axis: Week as an {@code int} value. Represented by a {@code NumberAxis}
*/ public class StockLineChartView { - private final NumberAxis xAxis = new NumberAxis(); - private final NumberAxis yAxis = new NumberAxis(); - - private final LineChartSets autoscale, stepsize and manual values for the range x- and y-axis, as well - * as the labels.
- *Initializes the LineChart.
- */ - - public StockLineChartView() { - xAxis.setAutoRanging(false); - yAxis.setAutoRanging(true); - yAxis.setForceZeroInRange(false); - - xAxis.setLowerBound(1); - - xAxis.setLabel("Week"); - yAxis.setLabel("Price"); - - chart = new LineChart<>(xAxis, yAxis); - } - - /** - * Returns the constructed LineChart. - * - * @return the current LineChart - */ - public LineChartSets autoscale, stepsize and manual values for the range x- and y-axis, as well + * as the labels.
+ * + *Initializes the LineChart.
+ */ + public StockLineChartView() { + xaxis.setAutoRanging(false); + NumberAxis yaxis = new NumberAxis(); + yaxis.setAutoRanging(true); + yaxis.setForceZeroInRange(false); + + xaxis.setLowerBound(1); + + xaxis.setLabel("Week"); + yaxis.setLabel("Price"); + + chart = new LineChart<>(xaxis, yaxis); + } + + /** + * Returns the constructed LineChart. + * + * @return the current LineChart + */ + public LineChartHere the series values are given as a list of {@code XYChart.Series} objects.
+ * + * @param seriesList the list of XYChart.Series containing the x- and y-values for each stock + */ + public void setSeries(ListHere the series values are given as a list of {@code XYChart.Series} objects.
- * - * @param seriesList the list of XYChart.Series containing the x- and y-values for each stock - */ + double xax = calculatexAxisMax(seriesList); - public void setSeries(ListExtends the {@link BorderPane} for easy layout setup.
*/ public class TransactionArchiveView extends BorderPane { - private final LanguageManager lm = LanguageManager.getInstance(); + private final LanguageManager lm = LanguageManager.getInstance(); + + private ListViewBuilds the necessary components and places them in a {@link VBox}.
+ * + *Uses a cell factory to format the string shown
+ * + *Assigns red text to purchases, and green text to sales.
+ * + *Uses the formatBigDecimal method to convert the BigDecimal to a + * string with 2 decimals.
+ * + *Uses a {@link LanguageManager} to dynamically set text based on target language.
+ * + * @return a VBox of the constructed view of the transaction archive + */ + private VBox centerPane() { + VBox vbox = new VBox(10); + vbox.setPadding(new Insets(15, 12, 15, 12)); + vbox.setStyle("-fx-background-color: #00bcf0; "); + + Label titleLabel = new Label(); + titleLabel.textProperty().bind(lm.bindString("historyTitle")); + titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; -fx-text-fill: #303539;"); + + VBox titleBox = new VBox(titleLabel); + titleBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + titleBox.setAlignment(Pos.CENTER); + titleBox.setPadding(new Insets(4)); + titleBox.setMaxWidth(300); + + historyListView = new ListView<>(); + historyListView.setMinHeight(0); + historyListView.setMaxHeight(Double.MAX_VALUE); + + historyListView.setCellFactory(list -> new ListCell<>() { + private Subscription langSubscription; + + @Override + protected void updateItem(Transaction item, boolean empty) { + super.updateItem(item, empty); + + if (langSubscription != null) { + langSubscription.unsubscribe(); + langSubscription = null; + } - private ListViewBuilds the necessary components and places them in a {@link VBox}.
- *Uses a cell factory to format the string shown
- *Assigns red text to purchases, and green text to sales.
- *Uses the formatBigDecimal method to convert the BigDecimal to a - * string with 2 decimals.
- *Uses a {@link LanguageManager} to dynamically set text based on target language.
- * - * @return a VBox of the constructed view of the transaction archive - */ - private VBox centerPane() { - VBox vBox = new VBox(10); - vBox.setPadding(new Insets(15, 12, 15, 12)); - vBox.setStyle("-fx-background-color: #00bcf0; "); - - titleLabel = new Label(); - titleLabel.textProperty().bind(lm.bindString("historyTitle")); - titleLabel.setStyle("-fx-font-size: 20px; -fx-font-weight: bold; -fx-text-fill: #303539;"); - - VBox titleBox = new VBox(titleLabel); - titleBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); - titleBox.setAlignment(Pos.CENTER); - titleBox.setPadding(new Insets(4)); - titleBox.setMaxWidth(300); - - historyListView = new ListView<>(); - historyListView.setMinHeight(0); - historyListView.setMaxHeight(Double.MAX_VALUE); - - historyListView.setCellFactory(list -> new ListCell<>() { - private Subscription langSubscription; - - @Override - protected void updateItem(Transaction item, boolean empty) { - super.updateItem(item, empty); - - if (langSubscription != null) { - langSubscription.unsubscribe(); - langSubscription = null; - } - - if (empty || item == null) { - setText(null); - setStyle(""); - } else { - Runnable updateTextAction = () -> { - String typeStr; - BigDecimal price = BigDecimal.ZERO; - BigDecimal profit = BigDecimal.ZERO; - // Changed to allow for more transaction types in the future - if (item instanceof Purchase) { - typeStr = lm.getString("historyTypePurchase"); - price = item.getShare().getPurchasePrice(); - } else if (item instanceof Sale sale) { - typeStr = lm.getString("historyTypeSale"); - price = item.getShare().getStock().getSalesPrice(); - if (sale.getCalculator() instanceof SaleCalculator saleCalc) { - profit = saleCalc.getProfitProperty().getValue(); - } - } else { - typeStr = "ERROR"; - } - - BigDecimal quantity = item.getShare().getQuantity(); - BigDecimal gross = item.getCalculator().calculateGross(); - BigDecimal commission = item.getCalculator().calculateCommission(); - BigDecimal tax = item.getCalculator().calculateTax(); - BigDecimal total = item.getCalculator().calculateTotal(); - - String symbol = item.getShare().getStock().getSymbol(); - - String template = lm.getString("historyCellFormat"); - - setText(String.format(template, + setText(String.format(template, item.getWeek(), typeStr, symbol, @@ -135,81 +148,88 @@ protected void updateItem(Transaction item, boolean empty) { FormatBigDecimal.formatNumber(tax), FormatBigDecimal.formatNumber(total), FormatBigDecimal.formatNumber(profit) - )); - }; - - langSubscription = lm.getBundleProperty().subscribe(bundle -> updateTextAction.run()); + )); + }; - updateTextAction.run(); + langSubscription = lm.getBundleProperty() + .subscribe(bundle -> updateTextAction.run()); - if (item instanceof Purchase) { - setStyle("-fx-text-fill: #c0392b; -fx-font-weight: bold;"); - } else if (item instanceof Sale) { - setStyle("-fx-text-fill: #27ae60; -fx-font-weight: bold;"); - } - } - } - }); - - HBox searchBox = new HBox(); - searchField = new TextField(); - searchField.promptTextProperty().bind(lm.bindString("search")); - searchBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" - ); + updateTextAction.run(); - searchBox.setPadding(new Insets(8, 14, 8, 14)); - searchBox.setAlignment(Pos.CENTER_LEFT); - searchBox.setMaxWidth(Region.USE_PREF_SIZE); - searchBox.getChildren().addAll(searchField); - - VBox historyListBox = new VBox(historyListView); - historyListBox.setStyle("-fx-background-color: #ffe556;" + - "-fx-text-fill: #303539;" + - "-fx-background-radius: 8;" + - "-fx-border-color: #303539;" + - "-fx-border-radius: 8;" + if (item instanceof Purchase) { + setStyle("-fx-text-fill: #c0392b; -fx-font-weight: bold;"); + } else if (item instanceof Sale) { + setStyle("-fx-text-fill: #27ae60; -fx-font-weight: bold;"); + } + } + } + }); + + HBox searchBox = new HBox(); + searchField = new TextField(); + searchField.promptTextProperty().bind(lm.bindString("search")); + searchBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + searchBox.setPadding(new Insets(8, 14, 8, 14)); + searchBox.setAlignment(Pos.CENTER_LEFT); + searchBox.setMaxWidth(Region.USE_PREF_SIZE); + searchBox.getChildren().addAll(searchField); + + VBox historyListBox = new VBox(historyListView); + historyListBox.setStyle("-fx-background-color: #ffe556;" + + "-fx-text-fill: #303539;" + + "-fx-background-radius: 8;" + + "-fx-border-color: #303539;" + + "-fx-border-radius: 8;" + ); + + historyListBox.setPadding(new Insets(4)); + historyListBox.setMinHeight(0); + historyListBox.setMaxHeight(Double.MAX_VALUE); + + VBox.setVgrow(historyListView, Priority.ALWAYS); + VBox.setVgrow(historyListBox, Priority.ALWAYS); + + vbox.getChildren().addAll(titleBox, searchBox, historyListBox); + return vbox; + } + + /** + * Sets the player to be observed. + * + *And puts the {@link TransactionArchive} into a {@link FilteredList} for searching.
+ * + * @param player the player to be observed + */ + public void setPlayer(Player player) { + if (player != null && player.getTransactionArchive().getObservableTransactions() != null) { + + filteredTransactionList = new FilteredList<>( + player.getTransactionArchive().getObservableTransactions()); + + historyListView.setItems(filteredTransactionList); + + searchField.textProperty().addListener(( + observable, oldText, newText) -> { + String search = newText == null ? "" : newText.toLowerCase(); + + filteredTransactionList.setPredicate(transaction -> search.isBlank() + || + transaction.getShare().getStock() + .getSymbol().toLowerCase().contains(search) + || + transaction.getShare().getStock() + .getCompany().toLowerCase().contains(search) ); + }); - historyListBox.setPadding(new Insets(4)); - historyListBox.setMinHeight(0); - historyListBox.setMaxHeight(Double.MAX_VALUE); - - VBox.setVgrow(historyListView, Priority.ALWAYS); - VBox.setVgrow(historyListBox, Priority.ALWAYS); - - vBox.getChildren().addAll(titleBox, searchBox, historyListBox); - return vBox; - } - - /** - * Sets the player to be observed. - *And puts the {@link TransactionArchive} into a {@link FilteredList} for searching.
- * - * @param player the player to be observed - */ - public void setPlayer(Player player) { - if (player != null && player.getTransactionArchive().getObservableTransactions() != null) { - - - filteredTransactionList = new FilteredList<>(player.getTransactionArchive().getObservableTransactions()); - - historyListView.setItems(filteredTransactionList); - - searchField.textProperty().addListener((observable, oldText, newText) -> { - String search = newText == null ? "" : newText.toLowerCase(); - - filteredTransactionList.setPredicate( transaction -> search.isBlank() - || transaction.getShare().getStock().getSymbol().toLowerCase().contains(search) - || transaction.getShare().getStock().getCompany().toLowerCase().contains(search) - ); - }); - - } else { - historyListView.setItems(null); - } + } else { + historyListView.setItems(null); } + } }