Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into 51-integrate-topga…
Browse files Browse the repository at this point in the history
…iners-and-toplosers-into-view

# Conflicts:
#	millions/src/main/java/no/ntnu/gruppe53/view/FooterBar.java
#	millions/src/main/java/no/ntnu/gruppe53/view/NavigationBar.java
  • Loading branch information
Arelodgaard committed May 25, 2026
2 parents 84ba81c + 1744810 commit f463ac2
Show file tree
Hide file tree
Showing 22 changed files with 865 additions and 143 deletions.
2 changes: 1 addition & 1 deletion millions/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>25.0.3</version>
<version>25.0.1</version>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
package no.ntnu.gruppe53.controller;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javafx.scene.control.Alert;
import javafx.stage.Stage;
import javafx.util.Subscription;
import no.ntnu.gruppe53.model.*;
import no.ntnu.gruppe53.service.LanguageManager;
import no.ntnu.gruppe53.service.StockLineChartService;
import no.ntnu.gruppe53.view.*;

/**
* Represents the main controller for the views of the stock game.
* <p>Uses a {@link LanguageManager} for methods to change text dynamically.</p>
*/
public class GameController {
private Player player;
private Exchange exchange;
private List<Stock> stocks;
private final LanguageManager lm = LanguageManager.getInstance();

private final ViewController vm;

Expand All @@ -29,6 +29,9 @@ public class GameController {
private PurchaseCalculator purchaseCalculator;
private SaleCalculator saleCalculator;

private Subscription selectedStockPriceSubscription;
private Subscription selectedSharePriceSubscription;

/**
* Initializes the {@link ViewController} to be used for switching views.
* @param vm {@code ViewController} to be used when switching views
Expand Down Expand Up @@ -112,6 +115,7 @@ public void showTransactionHistory() {
* Initializes the {@link NavigationBar} and {@link FooterBar} for the controller.
* <p>Binds functionality to exposed buttons and lists in views.</p>
* <p>Sets subscriptions for observable values for views.</p>
* <p>Sets the method for setting the selected language locale for the footer.</p>
* @param nav the NavigationBar view
* @param footer the FooterBar view
*/
Expand All @@ -120,13 +124,22 @@ public void initialize(NavigationBar nav, FooterBar footer) {
nav.onPortfolioButtonClick(() -> vm.switchView("portfolio"));
nav.onHistoryButtonClick(() -> vm.switchView("history"));

footer.onLanguageChange(selected -> {
lm.setLocale(selected.locale());
});

footer.onAdvanceButtonClick(() -> {
if (exchange != null) {
exchange.advance();
}
});

marketView.onStockSelection(stock -> {
if (selectedStockPriceSubscription != null) {
selectedStockPriceSubscription.unsubscribe();
selectedStockPriceSubscription = null;
}

if (stock != null) {
marketView.setSelectedStockLabel(stock.getSymbol() + " - " + stock.getCompany());
marketView.setupPriceSubscription(stock, currentStock -> {
Expand All @@ -135,6 +148,16 @@ public void initialize(NavigationBar nav, FooterBar footer) {
});
marketView.setPurchaseCalculator(calculatePurchase(marketView.getSelectedStock(),
marketView.getQuantityPurchase()));

selectedStockPriceSubscription = stock.salesPriceProperty().subscribe(newPrice -> {
if (marketView.getSelectedStock() != null) {
marketView.setPurchaseCalculator(calculatePurchase(
marketView.getSelectedStock(),
marketView.getQuantityPurchase()
));
}
});

} else {
marketView.setSelectedStockLabel("");
marketView.clearChart();
Expand All @@ -146,17 +169,28 @@ public void initialize(NavigationBar nav, FooterBar footer) {
if (stock != null) purchaseStock(stock.getSymbol(), marketView.getQuantityPurchase());
});

marketView.onQuantitySelect(() -> {
if (marketView.getSelectedStock() != null) {
marketView.onQuantitySelect(() -> {
if (marketView.getSelectedStock() != null) {
marketView.setPurchaseCalculator(calculatePurchase(marketView.getSelectedStock(),
marketView.getQuantityPurchase()));
}
});
});

portfolioView.onShareSelection(share -> {
if (selectedSharePriceSubscription != null) {
selectedSharePriceSubscription.unsubscribe();
selectedSharePriceSubscription = null;
}
if (share != null) {
portfolioView.setSelectedShareLabel(share.getStock().getSymbol() + " - " + share.getStock().getCompany());
portfolioView.setSaleCalculator(calculateSale(portfolioView.getSelectedShare()));

selectedSharePriceSubscription = share.getStock().salesPriceProperty().subscribe(newPrice -> {
if (portfolioView.getSelectedShare() != null) {
portfolioView.setSaleCalculator(calculateSale(portfolioView.getSelectedShare()));
}
});

} else {
portfolioView.setSelectedShareLabel("");
}
Expand Down Expand Up @@ -206,7 +240,7 @@ private void sellShare(Share selectedShare) {

/**
* Creates a {@link PurchaseCalculator} that can be used for the
* for the setPurchaseCalculator() function in the {@link MarketView}.
* setPurchaseCalculator() function in the {@link MarketView}.
* @param stock the currently selected stock
* @param quantity the currently selected quantity
* @return {@link PurchaseCalculator}
Expand All @@ -224,8 +258,8 @@ private PurchaseCalculator calculatePurchase(Stock stock, int quantity) {

/**
* Creates a {@link SaleCalculator} that can be used for the
* for the setSaleCalculator() function in the {@link PortfolioView}.
* @param share
* setSaleCalculator() function in the {@link PortfolioView}.
* @param share the share to use the calculator on
* @return {@link SaleCalculator}
*/
private SaleCalculator calculateSale(Share share) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
package no.ntnu.gruppe53.controller;

import no.ntnu.gruppe53.service.LanguageManager;
import no.ntnu.gruppe53.service.LanguageOption;
import no.ntnu.gruppe53.service.LanguageRegistry;
import no.ntnu.gruppe53.view.StartView;
import javafx.application.Platform;

import java.util.List;

/**
* The controller for {@link StartView},
* the first view for the player upon launching the app.
* <p>Contains two choices:
* <p>Contains three choices:
* <ul>
* <li>New Game</li>
* <li>Language Select</li>
* <li>Quit</li>
* </ul></p>
* <p>Uses a {@link LanguageManager} to change the UI language.</p>
*/
public class StartViewController {
/**
Expand All @@ -25,6 +32,25 @@ public StartViewController(StartView view, ViewController vm) {
gameController.startNewGame();
});

view.setOnLanguage(() -> {
LanguageManager lm = LanguageManager.getInstance();
List<LanguageOption> availableLanguages = LanguageRegistry.getLanguages();

int currentIndex = 0;
for (int i = 0; i < availableLanguages.size(); i++) {
if (availableLanguages.get(i).locale().equals(lm.getLocale())) {
currentIndex = i;
break;
}
}

int nextIndex = (currentIndex + 1) % availableLanguages.size();
LanguageOption nextLanguage = availableLanguages.get(nextIndex);

lm.setLocale(nextLanguage.locale());
});


view.setOnQuit(Platform::exit);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package no.ntnu.gruppe53.service;

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.
* <p>The possible languages to be used are set by {@link LanguageRegistry}.</p>
*/
public class LanguageManager {

/**
* Sets a default language and creates an observable {@link ResourceBundle}.
*/
private final ObjectProperty<ResourceBundle> bundleProperty =
new SimpleObjectProperty<>();

private LanguageManager() {
setLocale(LanguageRegistry.getDefaultLocale());
}

/**
* Static Inner Class to lazily create the instance
*/
private static class LanguageManagerInner {
private static final LanguageManager INSTANCE =
new LanguageManager();
}

/**
* Returns the instance of the language manager
*
* @return the instance of the language manager
*/
public static LanguageManager getInstance() {
return LanguageManagerInner.INSTANCE;
}

/**
* Returns the observable resource bundle.
*
* @return an observable resource bundle
*/
public ObjectProperty<ResourceBundle> getBundleProperty() {
return bundleProperty;
}

/**
* Sets the locale of the instance to a given locale which determines the properties file to load
* values from.
*
* @param locale the locale to change to
*/
public void setLocale(Locale locale) {
ResourceBundle bundle =
ResourceBundle.getBundle("i18n.lang", locale);

bundleProperty.set(bundle);
}

/**
* Returns the string value of the given key in a .properties file.
*
* @param key the key to look for in the .properties file
* @return the value of the key
*/
public String getString(String key) {
return bundleProperty.get().getString(key);
}

/**
* Returns the current locale.
*
* @return the current locale
*/
public Locale getLocale() {
return bundleProperty.get().getLocale();
}

/**
* Creates a {@link StringBinding} to a given string and associates it with a given key in a .properties file
*
* @param key the key to associate the string binding with
* @return a string binding observable
*/
public StringBinding bindString(String key) {
return Bindings.createStringBinding(
() -> getString(key),
getBundleProperty()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package no.ntnu.gruppe53.service;

import java.util.Locale;

/**
* Acts as a data-carrier representing a language with a string name and a {@link Locale}.
*
* @param name the name of the language
* @param locale the locale of the language
*/
public record LanguageOption(String name, Locale locale) {}

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package no.ntnu.gruppe53.service;

import java.util.List;
import java.util.Locale;

/**
* Represents a registry of allowed {@link LanguageOption}s.
*/
public class LanguageRegistry {

/**
* Sets all possible languages that can be used.
*/
private static final List<LanguageOption> languages = List.of(
new LanguageOption("English", new Locale("en")),
new LanguageOption("Norsk", new Locale("no"))
);

/**
* Sets the default language to be used.
* <p>Searches through the registry to find english and sets it as default.</p>
*/
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 List<LanguageOption> getLanguages() {
return languages;
}

/**
* Returns the default language.
*
* @return the default language
*/
public static LanguageOption getDefaultLanguage() {
return defaultLang;
}

/**
* Returns the default locale of the default language.
*
* @return the default locale
*/
public static Locale getDefaultLocale() {
return defaultLang.locale();
}
}
Loading

0 comments on commit f463ac2

Please sign in to comment.