Chore/conform ui to checkstyle #184

Merged
jona.walpert merged 5 commits from chore/conform-ui-to-checkstyle into main 2026-03-14 18:21:28 +01:00
15 changed files with 449 additions and 294 deletions
Showing only changes of commit e3e1da0082 - Show all commits
@@ -1,13 +1,13 @@
package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui; package ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.control.Label;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
/** /**
* Controller-Klasse für das Chat-System innerhalb der Spieloberfläche. * Controller-Klasse für das Chat-System innerhalb der Spieloberfläche.
@@ -39,6 +39,8 @@ public class ChatController {
@FXML @FXML
private ScrollPane chatScrollPane; private ScrollPane chatScrollPane;
private static final int CHAT_PADDING = 20;
/** /**
* Initialisiert den ChatController nach dem Laden der FXML. * Initialisiert den ChatController nach dem Laden der FXML.
*/ */
@@ -73,7 +75,7 @@ public class ChatController {
Label label = new Label("[" + time + "] " + player + ": " + message); Label label = new Label("[" + time + "] " + player + ": " + message);
label.getStyleClass().add("info-text"); label.getStyleClass().add("info-text");
label.setWrapText(true); // Zeilenumbruch aktivieren label.setWrapText(true); // Zeilenumbruch aktivieren
label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(20)); label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(CHAT_PADDING));
chatVBox.getChildren().add(label); chatVBox.getChildren().add(label);
} }
@@ -1,18 +1,8 @@
package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui; package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui;
// import javafx.application.Platform;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
// import javafx.scene.control.TextField;
// import javafx.scene.input.KeyCode;
// import javafx.scene.input.KeyEvent;
// import javafx.scene.input.MouseEvent;
// import javafx.scene.layout.HBox;
// import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
// import javafx.stage.Stage;
// import javafx.scene.Scene;
// import javafx.scene.web.WebView;
/** /**
* Controller für die Casino-Spielfläche. * Controller für die Casino-Spielfläche.
@@ -32,7 +22,8 @@ public class CasinoGameController {
@FXML private Label welcomeText; @FXML private Label welcomeText;
@FXML private VBox casinoTable; @FXML private VBox casinoTable;
// TODO: Test-Logik: wird durch echte Spielinteraktionen ersetzt, sobald die GameEngine fertig ist // TODO: Test-Logik: wird durch echte Spielinteraktionen ersetzt,
// sobald die GameEngine fertig ist
@FXML @FXML
public void onTableClick() { public void onTableClick() {
welcomeText.setText("Einsatz akzeptiert!"); welcomeText.setText("Einsatz akzeptiert!");
@@ -1,12 +1,11 @@
package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui; package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui;
import java.io.IOException;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.io.IOException;
/** /**
* Hauptklasse für das Casino-Spiel-UI. * Hauptklasse für das Casino-Spiel-UI.
* *
@@ -20,6 +19,9 @@ import java.io.IOException;
*/ */
public class CasinoGameUI extends Application { public class CasinoGameUI extends Application {
private static final int DEFAULT_WIDTH = 1200;
private static final int DEFAULT_HEIGHT = 800;
/** /**
* Startet die Haupt-Stage der Anwendung. * Startet die Haupt-Stage der Anwendung.
* *
@@ -28,11 +30,13 @@ public class CasinoGameUI extends Application {
*/ */
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(CasinoGameUI.class.getResource("/ui-structure/casinogameui.fxml")); FXMLLoader fxmlLoader =
Scene scene = new Scene(fxmlLoader.load(), 1200, 800); new FXMLLoader(CasinoGameUI.class.getResource("/ui-structure/casinogameui.fxml"));
Scene scene = new Scene(fxmlLoader.load(), DEFAULT_WIDTH, DEFAULT_HEIGHT);
stage.setTitle("Casono (GAME)"); stage.setTitle("Casono (GAME)");
stage.getIcons().add(new javafx.scene.image.Image(getClass().getResource("/images/logoinverted.png").toExternalForm())); String iconPath = getClass().getResource("/images/logoinverted.png").toExternalForm();
stage.getIcons().add(new javafx.scene.image.Image(iconPath));
stage.setScene(scene); stage.setScene(scene);
stage.setFullScreen(true); stage.setFullScreen(true);
stage.show(); stage.show();
@@ -1,23 +1,33 @@
package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents; package ch.unibas.dmi.dbis.cs108.casono.client.ui.gameui.gameuicomponents;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.URI;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.geometry.Insets; import javafx.geometry.Insets;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.*; import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.*; import javafx.scene.input.KeyCode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Rectangle; import javafx.scene.shape.Rectangle;
import javafx.scene.web.WebEngine; import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView; import javafx.scene.web.WebView;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.net.*;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
/** /**
* Experimenteller integrierter Browser für Casono. * Experimenteller integrierter Browser für Casono.
* *
@@ -49,10 +59,27 @@ import java.util.Set;
* - Automatische Cookie-Löschung beim Schließen * - Automatische Cookie-Löschung beim Schließen
*/ */
public class CasinoBrowserController { public class CasinoBrowserController {
private static final Set<String> TRUSTED_DOMAINS = new HashSet<>(); private static final Set<String> TRUSTED_DOMAINS = new HashSet<>();
private static final CookieManager COOKIE_MANAGER = private static final CookieManager COOKIE_MANAGER =
new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER); new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER);
private static final org.apache.logging.log4j.Logger LOGGER =
org.apache.logging.log4j.LogManager.getLogger(CasinoBrowserController.class);
private static final int LOGO_HEIGHT = 40;
private static final int CORNER_RADIUS = 40;
private static final int HBOX_SPACIN = 10;
private static final int VBOX_SPACING = 10;
private static final int PADDING_SIZE = 10;
private static final int WINDOW_WIDTH = 1200;
private static final int WINDOW_HEIGHT = 800;
private static final int ALERT_WIDTH = 600;
private static final int ALERT_HEIGHT = 300;
private static final String LOGO_PATH = "/images/logoinverted.png";
private static final String LOGO_PATH_MAIN = "/images/logo.png";
static { static {
CookieHandler.setDefault(COOKIE_MANAGER); CookieHandler.setDefault(COOKIE_MANAGER);
@@ -104,174 +131,44 @@ public class CasinoBrowserController {
engine.setJavaScriptEnabled(false); engine.setJavaScriptEnabled(false);
// Popup Blocker configurePopupBlocker(engine);
engine.setCreatePopupHandler(config -> {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Popup blockiert");
alert.setHeaderText(null);
alert.setContentText("Popup wurde aus Sicherheitsgründen blockiert.");
try {
Image logo =
new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png"));
Image logomain =
new Image(CasinoBrowserController.class.getResourceAsStream("/images/logo.png"));
if (logo != null) {
Stage alertStage = (Stage) alert.getDialogPane().getScene().getWindow();
if (alertStage != null) {
alertStage.getIcons().add(logo);
}
}
if (logomain != null) {
ImageView logoView = new ImageView(logomain);
logoView.setFitHeight(40);
logoView.setPreserveRatio(true);
alert.setGraphic(logoView);
}
} catch (Exception e) {
System.err.println("Logo konnte nicht geladen werden");
}
alert.showAndWait();
return null;
});
webView.getStyleClass().add("web-view"); webView.getStyleClass().add("web-view");
StackPane webContainer = new StackPane(webView); StackPane webContainer = createWebContainer(webView);
webContainer.getStyleClass().add("browser-web-view");
VBox.setVgrow(webContainer, Priority.ALWAYS);
Rectangle clip = new Rectangle(); Rectangle clip = new Rectangle();
clip.setArcWidth(40); clip.setArcWidth(CORNER_RADIUS);
clip.setArcHeight(40); clip.setArcHeight(CORNER_RADIUS);
webView.setClip(clip); webView.setClip(clip);
webView.widthProperty().addListener((o,a,b)->clip.setWidth(b.doubleValue())); webView.widthProperty().addListener((o, a, b) ->
webView.heightProperty().addListener((o,a,b)->clip.setHeight(b.doubleValue())); clip.setWidth(b.doubleValue()));
webView.heightProperty().addListener((o, a, b) ->
clip.setHeight(b.doubleValue()));
ImageView browserLogo = new ImageView(); ImageView browserLogo = loadLogos(stage);
try { TextField urlField = createUrlField(url);
Image logo = Label securityLabel = createSecurityLabel();
new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png"));
Image logomain =
new Image(CasinoBrowserController.class.getResourceAsStream("/images/logo.png"));
if (logo != null) { Button jsToggle = createJsToggle(engine);
stage.getIcons().add(logo); Button backBtn = createBackButton(engine);
} Button fwdBtn = createForwardButton(engine);
Button reloadBtn = createReloadButton(engine);
Button closeBtn = createCloseButton(stage, webView);
configureUrlEvents(engine, urlField, securityLabel);
if (logomain != null) { HBox taskbar = new HBox(HBOX_SPACIN, browserLogo, backBtn, fwdBtn,
browserLogo.setImage(logomain); reloadBtn, urlField, jsToggle, securityLabel, closeBtn
browserLogo.setFitHeight(30);
browserLogo.setPreserveRatio(true);
}
} catch (Exception e) {
System.err.println("Logo konnte nicht geladen werden");
}
// URL Feld
TextField urlField = new TextField(url);
urlField.getStyleClass().add("gray-input-field");
HBox.setHgrow(urlField, Priority.ALWAYS);
Label securityLabel = new Label("SICHER");
securityLabel.getStyleClass().add("security-label");
// JS Toggle
Button jsToggle = new Button("JS EINSCHALTEN");
jsToggle.getStyleClass().add("red-button");
jsToggle.setOnAction(e -> {
javascriptEnabled = !javascriptEnabled;
engine.setJavaScriptEnabled(javascriptEnabled);
if (javascriptEnabled) {
jsToggle.setText("JS AUSSCHALTEN");
jsToggle.getStyleClass().removeAll("red-button");
jsToggle.getStyleClass().add("yellow-button");
} else {
jsToggle.setText("JS EINSCHALTEN");
jsToggle.getStyleClass().removeAll("yellow-button");
jsToggle.getStyleClass().add("red-button");
}
});
// Navigation
Button backBtn = new Button("<");
backBtn.getStyleClass().add("gray-button");
backBtn.setOnAction(e -> {
if(engine.getHistory().getCurrentIndex() > 0){
engine.getHistory().go(-1);
}
});
Button fwdBtn = new Button(">");
fwdBtn.getStyleClass().add("gray-button");
fwdBtn.setOnAction(e -> {
if(engine.getHistory().getCurrentIndex() <
engine.getHistory().getEntries().size()-1){
engine.getHistory().go(1);
}
});
// Reload Button
Button reloadBtn = new Button("");
reloadBtn.getStyleClass().add("gray-button");
reloadBtn.setOnAction(e -> engine.reload());
// Close
Button closeBtn = new Button("X");
closeBtn.getStyleClass().add("red-button");
closeBtn.setOnAction(e -> {
webView.getEngine().load("about:blank");
clearCookies();
stage.close();
});
// URL Enter
urlField.setOnAction(e ->
loadUrlSafely(engine, urlField.getText(), securityLabel));
engine.locationProperty().addListener((obs,o,n)->urlField.setText(n));
// Taskbar
HBox taskbar = new HBox(
10,
browserLogo,
backBtn,
fwdBtn,
reloadBtn,
urlField,
jsToggle,
securityLabel,
closeBtn
); );
taskbar.getStyleClass().add("taskbar-browser"); taskbar.getStyleClass().add("taskbar-browser");
taskbar.setAlignment(Pos.CENTER_LEFT); taskbar.setAlignment(Pos.CENTER_LEFT);
// Root Scene scene = createScene(taskbar, webContainer);
VBox root = new VBox(10, taskbar, webContainer);
root.getStyleClass().add("browser-root");
root.setPadding(new Insets(10));
Scene scene = new Scene(root,1200,800);
var css = CasinoBrowserController.class.getResource("/ui-structure/casinogameui.css");
if(css != null) { configureKeyEvents(scene, engine);
scene.getStylesheets().add(css.toExternalForm());
}
// F5 Reload
scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case F5 -> engine.reload();
}
});
stage.setScene(scene); stage.setScene(scene);
stage.setTitle("Casono Browser"); stage.setTitle("Casono Browser");
@@ -280,6 +177,276 @@ public class CasinoBrowserController {
}); });
} }
/**
* WebView Container
*
* @param webView WebView Inhalt
* @return StackPane Container
*/
public static StackPane createWebContainer(WebView webView) {
StackPane webContainer = new StackPane(webView);
webContainer.getStyleClass().add("browser-web-view");
VBox.setVgrow(webContainer, Priority.ALWAYS);
return webContainer;
}
/**
* Popup Blocker
*
* @param engine WebEngine nutzen
*/
public static void configurePopupBlocker(WebEngine engine) {
engine.setCreatePopupHandler(config -> {
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Popup blockiert");
alert.setHeaderText(null);
alert.setContentText("Popup wurde aus Sicherheitsgründen blockiert.");
try {
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
Image logo = new Image(stream);
// Variable 'streamM' abgekürzt, um das 100-Zeichen-Limit (LineLength)
// einzuhalten
var streamM = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN);
Image logomain = new Image(streamM);
if (logo != null) {
Stage alertStage = (Stage) alert.getDialogPane().getScene().getWindow();
if (alertStage != null) {
alertStage.getIcons().add(logo);
}
}
if (logomain != null) {
ImageView logoView = new ImageView(logomain);
logoView.setFitHeight(LOGO_HEIGHT);
logoView.setPreserveRatio(true);
alert.setGraphic(logoView);
}
} catch (Exception e) {
LOGGER.error("Logo konnte nicht geladen werden");
}
alert.showAndWait();
return null;
});
}
/**
* Logos laden
*
* @param stage Fenster Stage
* @return ImageView Logo
*/
private static ImageView loadLogos(Stage stage) {
ImageView browserLogo = new ImageView();
try {
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
Image logo = new Image(stream);
// Variable 'streamM' abgekürzt, um das 100-Zeichen-Limit (LineLength)
// einzuhalten
var streamM = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH_MAIN);
Image logomain = new Image(streamM);
if (logo != null) {
stage.getIcons().add(logo);
}
if (logomain != null) {
browserLogo.setImage(logomain);
browserLogo.setFitHeight(LOGO_HEIGHT);
browserLogo.setPreserveRatio(true);
}
} catch (Exception e) {
LOGGER.error("Logo konnte nicht geladen werden");
}
return browserLogo;
}
/**
* URL Feld
*
* @param url Start URL
* @return TextField Eingabe
*/
public static TextField createUrlField(String url) {
TextField urlField = new TextField(url);
urlField.getStyleClass().add("gray-input-field");
HBox.setHgrow(urlField, Priority.ALWAYS);
return urlField;
}
/**
* Sicherheits Label
*
* @return Label Anzeige
*/
public static Label createSecurityLabel() {
Label securityLabel = new Label("SICHER");
securityLabel.getStyleClass().add("security-label");
return securityLabel;
}
/**
* JS Toggle
*
* @param engine WebEngine nutzen
* @return Button Umschalten
*/
public static Button createJsToggle(WebEngine engine){
Button jsToggle = new Button("JS EINSCHALTEN");
jsToggle.getStyleClass().add("red-button");
jsToggle.setOnAction(e -> {
javascriptEnabled = !javascriptEnabled;
engine.setJavaScriptEnabled(javascriptEnabled);
if (javascriptEnabled) {
jsToggle.setText("JS AUSSCHALTEN");
jsToggle.getStyleClass().removeAll("red-button");
jsToggle.getStyleClass().add("yellow-button");
} else {
jsToggle.setText("JS EINSCHALTEN");
jsToggle.getStyleClass().removeAll("yellow-button");
jsToggle.getStyleClass().add("red-button");
}
});
return jsToggle;
}
/**
* Zurück Button
*
* @param engine WebEngine nutzen
* @return Button Zurück
*/
public static Button createBackButton(WebEngine engine) {
Button backBtn = new Button("<");
backBtn.getStyleClass().add("gray-button");
backBtn.setOnAction(e -> {
if (engine.getHistory().getCurrentIndex() > 0) {
engine.getHistory().go(-1);
}
});
return backBtn;
}
/**
* Vorwärts Button
*
* @param engine WebEngine nutzen
* @return Button Vorwärts
*/
public static Button createForwardButton(WebEngine engine) {
Button fwdBtn = new Button(">");
fwdBtn.getStyleClass().add("gray-button");
fwdBtn.setOnAction(e -> {
if (engine.getHistory().getCurrentIndex() <
engine.getHistory().getEntries().size() - 1) {
engine.getHistory().go(1);
}
});
return fwdBtn;
}
/**
* Reload Button
*
* @param engine WebEngine nutzen
* @return Button Reload
*/
public static Button createReloadButton(WebEngine engine) {
Button reloadBtn = new Button("");
reloadBtn.getStyleClass().add("gray-button");
reloadBtn.setOnAction(e -> engine.reload());
return reloadBtn;
}
/**
* Close Button
*
* @param stage Fenster Stage
* @param webView WebView Inhalt
* @return Button Schließen
*/
public static Button createCloseButton(Stage stage, WebView webView) {
Button closeBtn = new Button("X");
closeBtn.getStyleClass().add("red-button");
closeBtn.setOnAction(e -> {
webView.getEngine().load("about:blank");
clearCookies();
stage.close();
});
return closeBtn;
}
/**
* URL Events
*
* @param engine WebEngine nutzen
* @param urlField URL Textfeld
* @param securityLabel Sicherheits Label
*/
public static void configureUrlEvents(WebEngine engine,
TextField urlField,
Label securityLabel) {
urlField.setOnAction(e ->
loadUrlSafely(engine, urlField.getText(), securityLabel));
engine.locationProperty().addListener((obs, o, n) ->
urlField.setText(n));
}
/**
* Scene erstellen
*
* @param taskbar Taskbar HBox
* @param webContainer Web Container
* @return Scene Fenster
*/
public static Scene createScene(HBox taskbar, StackPane webContainer) {
VBox root = new VBox(VBOX_SPACING, taskbar, webContainer);
root.getStyleClass().add("browser-root");
root.setPadding(new Insets(PADDING_SIZE));
Scene scene = new Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT);
var css = CasinoBrowserController.class
.getResource("/ui-structure/casinogameui.css");
if (css != null) {
scene.getStylesheets().add(css.toExternalForm());
}
return scene;
}
/**
* Key Events
*
* @param scene Scene Fenster
* @param engine WebEngine nutzen
*/
public static void configureKeyEvents(Scene scene, WebEngine engine) {
scene.setOnKeyPressed(event -> {
if (event.getCode() == KeyCode.F5) {
engine.reload();
}
});
}
/** /**
* Lädt eine URL in den Browser, nachdem grundlegende Sicherheitsprüfungen * Lädt eine URL in den Browser, nachdem grundlegende Sicherheitsprüfungen
* durchgeführt wurden. * durchgeführt wurden.
@@ -299,20 +466,20 @@ public class CasinoBrowserController {
*/ */
private static void loadUrlSafely(WebEngine engine, String url, Label securityLabel) { private static void loadUrlSafely(WebEngine engine, String url, Label securityLabel) {
try { try {
if(!url.startsWith("http")) { if (!url.startsWith("http")) {
url = "https://" + url; url = "https://" + url;
} }
URI uri = new URI(url); URI uri = new URI(url);
// HTTPS Pflicht // HTTPS Pflicht
if(!"https".equalsIgnoreCase(uri.getScheme())) { if (!"https".equalsIgnoreCase(uri.getScheme())) {
securityLabel.setText("BLOCKIERT"); securityLabel.setText("BLOCKIERT");
return; return;
} }
String host = uri.getHost(); String host = uri.getHost();
if(host == null) { if (host == null) {
securityLabel.setText("ERROR"); securityLabel.setText("ERROR");
return; return;
} }
@@ -321,44 +488,57 @@ public class CasinoBrowserController {
boolean trusted = TRUSTED_DOMAINS.stream().anyMatch(domain -> boolean trusted = TRUSTED_DOMAINS.stream().anyMatch(domain ->
host.equals(domain) || host.endsWith("." + domain)); host.equals(domain) || host.endsWith("." + domain));
if(!trusted) { if (!trusted) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION); if (!showUnknownWebsiteAlert(host)) {
alert.setTitle("Unbekannte Website");
alert.setHeaderText("Diese Website ist nicht bekannt");
alert.setContentText(
host + "\n\nDiese Seite ist nicht vom Casono Browser verifiziert.\nMöchten Sie sie trotzdem öffnen?"
);
Image logo = new Image(CasinoBrowserController.class.getResourceAsStream("/images/logoinverted.png"));
if (logo != null) {
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
if(stage != null) {
stage.getIcons().add(logo);
}
ImageView logomain = new ImageView(logo);
logomain.setFitHeight(50);
logomain.setPreserveRatio(true);
alert.setGraphic(logomain);
}
alert.getDialogPane().setPrefSize(600,300);
Optional<ButtonType> result = alert.showAndWait();
if(result.isEmpty() || result.get() != ButtonType.OK) {
securityLabel.setText("BLOCKIERT"); securityLabel.setText("BLOCKIERT");
return; return;
} }
securityLabel.setText("UNBEKANNT"); securityLabel.setText("UNBEKANNT");
} else { } else {
securityLabel.setText("SICHER"); securityLabel.setText("SICHER");
} }
engine.load(uri.toString()); engine.load(uri.toString());
} } catch (Exception e) {
catch (Exception e) {
securityLabel.setText("ERROR"); securityLabel.setText("ERROR");
} }
} }
/**
* Zeigt Warnung an.
*
* @param host Website Host
* @return OK gedrückt
*/
private static boolean showUnknownWebsiteAlert(String host) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Unbekannte Website");
alert.setHeaderText("Diese Website ist nicht bekannt");
alert.setContentText(
host + "\n\nDiese Seite ist nicht vom " +
"Casono Browser verifiziert.\nMöchten Sie sie trotzdem öffnen?"
);
var stream = CasinoBrowserController.class.getResourceAsStream(LOGO_PATH);
Image logo = new Image(stream);
if (logo != null) {
Stage stage = (Stage) alert.getDialogPane().getScene().getWindow();
if (stage != null) {
stage.getIcons().add(logo);
}
ImageView logomain = new ImageView(logo);
logomain.setFitHeight(LOGO_HEIGHT);
logomain.setPreserveRatio(true);
alert.setGraphic(logomain);
}
alert.getDialogPane().setPrefSize(ALERT_WIDTH, ALERT_HEIGHT);
Optional<ButtonType> result = alert.showAndWait();
if (result.isEmpty() || result.get() != ButtonType.OK) {
return false;
}
return true;
}
} }
@@ -18,11 +18,18 @@ import javafx.scene.layout.HBox;
*/ */
public class TaskbarController { public class TaskbarController {
private static final org.apache.logging.log4j.Logger LOGGER =
org.apache.logging.log4j.LogManager.getLogger(CasinoBrowserController.class);
@FXML private HBox taskbar; @FXML private HBox taskbar;
@FXML private TextField taskbarInput; @FXML private TextField taskbarInput;
private double xOffset = 0; private double xOffset = 0;
private double yOffset = 0; private double yOffset = 0;
private static final double TASKBAR_SCALE = 0.9;
private static final int MIN_CREDITS = 5;
private static final int MAX_CREDITS = 100000;
private static final int CREDIT_STEP = 5;
/** /**
* Wird aufgerufen, wenn die Taskleiste mit der Maus gedrückt wird. * Wird aufgerufen, wenn die Taskleiste mit der Maus gedrückt wird.
@@ -40,7 +47,8 @@ public class TaskbarController {
* Wird aufgerufen, während die Taskleiste mit der Maus gezogen wird. * Wird aufgerufen, während die Taskleiste mit der Maus gezogen wird.
* Aktualisiert die Position und skaliert die Taskleiste leicht zur visuellen Rückmeldung. * Aktualisiert die Position und skaliert die Taskleiste leicht zur visuellen Rückmeldung.
* *
* TODO: Es muss noch gefixt werden, dass die Taskleiste nicht aus dem Fenster verschwinden kann. * TODO: Es muss noch gefixt werden, dass die Taskleiste nicht aus dem
* Fenster verschwinden kann.
* *
* @param event Das Mausereignis * @param event Das Mausereignis
*/ */
@@ -49,8 +57,8 @@ public class TaskbarController {
taskbar.setLayoutX(event.getSceneX() - xOffset); taskbar.setLayoutX(event.getSceneX() - xOffset);
taskbar.setLayoutY(event.getSceneY() - yOffset); taskbar.setLayoutY(event.getSceneY() - yOffset);
taskbar.setScaleX(0.9); taskbar.setScaleX(TASKBAR_SCALE);
taskbar.setScaleY(0.9); taskbar.setScaleY(TASKBAR_SCALE);
} }
/** /**
@@ -108,15 +116,15 @@ public class TaskbarController {
try { try {
int credits = Integer.parseInt(input.trim()); int credits = Integer.parseInt(input.trim());
if (credits >= 5 && credits <= 100000 && credits % 5 == 0) { if (credits >= MIN_CREDITS && credits <= MAX_CREDITS && credits % CREDIT_STEP == 0) {
// TODO: Credits müssen an die GameEngine gesendet werden // TODO: Credits müssen an die GameEngine gesendet werden
System.out.println("Einsatz gesetzt: " + credits + " Casono Credits"); LOGGER.info("Einsatz gesetzt: {} Casono Credits", credits);
taskbarInput.clear(); taskbarInput.clear();
} else { } else {
System.out.println("Fehler: Nur 5er-Schritte (5, 10, ... 100.000) erlaubt!"); LOGGER.info("Fehler: Nur 5er-Schritte (5, 10, ... 100.000) erlaubt!");
} }
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
System.out.println("Fehler: Bitte nur eine Zahl eingeben!"); LOGGER.info("Fehler: Bitte nur eine Zahl eingeben!");
} }
} }
@@ -4,18 +4,21 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.NetworkManager;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /** Application class for starting the server. */
* Application class for starting the server.
*/
public class ServerApp { public class ServerApp {
public static void start(String arg) { public static void start(String arg) {
int port = Integer.parseInt(arg); int port = Integer.parseInt(arg);
System.out.println("You've selected the server. It will accept connections at port " + port);
Logger logger = LogManager.getLogger(ServerApp.class);
logger.info("Starting server at port {}", port);
EventBus eventBus = new EventBus(); EventBus eventBus = new EventBus();
SessionManager sessionManager = new SessionManager(); SessionManager sessionManager = new SessionManager();
eventBus.subscribe(DisconnectEvent.class, event -> sessionManager.removeSession(event.sessionId())); eventBus.subscribe(
DisconnectEvent.class, event -> sessionManager.removeSession(event.sessionId()));
NetworkManager networkManager = new NetworkManager(port, sessionManager, eventBus); NetworkManager networkManager = new NetworkManager(port, sessionManager, eventBus);
networkManager.start(); networkManager.start();
} }
@@ -1,21 +1,17 @@
package ch.unibas.dmi.dbis.cs108.casono.server.network; package ch.unibas.dmi.dbis.cs108.casono.server.network;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus; import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.Session; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.Session;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionManager;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport; import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/** /** Creates and manages the server socket. Accepts new incoming connections and creates sessions. */
* Creates and manages the server socket. Accepts new incoming connections and creates sessions.
*/
public class NetworkManager implements Runnable { public class NetworkManager implements Runnable {
private Integer port; private Integer port;
private Logger logger; private Logger logger;
@@ -27,9 +23,9 @@ public class NetworkManager implements Runnable {
/** /**
* Creates a new NetworkManager with the given port, session manager, and event bus. * Creates a new NetworkManager with the given port, session manager, and event bus.
* *
* @param port the port to listen on * @param port the port to listen on
* @param sessionManager the session manager to use * @param sessionManager the session manager to use
* @param eventBus the event bus for events * @param eventBus the event bus for events
*/ */
public NetworkManager(Integer port, SessionManager sessionManager, EventBus eventBus) { public NetworkManager(Integer port, SessionManager sessionManager, EventBus eventBus) {
this.port = port; this.port = port;
@@ -41,11 +37,9 @@ public class NetworkManager implements Runnable {
this.eventBus.subscribe(DisconnectEvent.class, event -> clientDisconnected(event)); this.eventBus.subscribe(DisconnectEvent.class, event -> clientDisconnected(event));
} }
/** /** Starts the internal thread to accept new connections. */
* Starts the internal thread to accept new connections.
*/
public void start() { public void start() {
logger.debug("Starting server at port " + port); logger.debug("Starting at port {}", port);
thread.start(); thread.start();
} }
@@ -55,19 +49,17 @@ public class NetworkManager implements Runnable {
* @param event the disconnect event * @param event the disconnect event
*/ */
public void clientDisconnected(DisconnectEvent event) { public void clientDisconnected(DisconnectEvent event) {
logger.info("Session " + event.sessionId().value() + " disconnected adhasghd"); logger.info("Session {} disconnected", event.sessionId().value());
} }
/** /** Runs the network manager loop, accepting connections. */
* Runs the network manager loop, accepting connections.
*/
@Override @Override
public void run() { public void run() {
try (ServerSocket serverSocket = new ServerSocket(port)) { try (ServerSocket serverSocket = new ServerSocket(port)) {
while (running) { while (running) {
Socket clientSocket = serverSocket.accept(); Socket clientSocket = serverSocket.accept();
System.out.println("Accepted connection from " + clientSocket.getRemoteSocketAddress()); logger.debug("Accepted connection from {}", clientSocket.getRemoteSocketAddress());
Session session = new Session(new TcpTransport(clientSocket), eventBus); Session session = new Session(new TcpTransport(clientSocket), eventBus);
sessionManager.addSession(session); sessionManager.addSession(session);
@@ -2,7 +2,5 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.events;
import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId; import ch.unibas.dmi.dbis.cs108.casono.server.network.sessions.SessionId;
/** /** Represents a disconnect event for a session. */
* Represents a disconnect event for a session.
*/
public record DisconnectEvent(SessionId sessionId) implements Event {} public record DisconnectEvent(SessionId sessionId) implements Event {}
@@ -1,6 +1,4 @@
package ch.unibas.dmi.dbis.cs108.casono.server.network.events; package ch.unibas.dmi.dbis.cs108.casono.server.network.events;
/** /** Marker interface for events in the event bus system. */
* Marker interface for events in the event bus system.
*/
interface Event {} interface Event {}
@@ -7,9 +7,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /** A simple event bus for publishing and subscribing to events. */
* A simple event bus for publishing and subscribing to events.
*/
public class EventBus { public class EventBus {
private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>(); private final Map<Class<?>, List<Consumer<Object>>> handlers = new ConcurrentHashMap<>();
@@ -17,9 +15,11 @@ public class EventBus {
* Subscribes a handler to a specific event type. * Subscribes a handler to a specific event type.
* *
* @param eventType the class of the event to subscribe to * @param eventType the class of the event to subscribe to
* @param handler the consumer to handle the event * @param handler the consumer to handle the event
*/ */
@SuppressWarnings("unchecked") // This cast is safe, because handlers only get passed the type they subscribed to @SuppressWarnings(
"unchecked") // This cast is safe, because handlers only get passed the type they
// subscribed to
public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) { public <T extends Event> void subscribe(Class<T> eventType, Consumer<T> handler) {
handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>()) handlers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>())
.add((Consumer<Object>) (Consumer<?>) handler); .add((Consumer<Object>) (Consumer<?>) handler);
@@ -1,17 +1,14 @@
package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions; package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TransportLayer;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.DisconnectEvent; /** Represents a client session in the network server. */
import ch.unibas.dmi.dbis.cs108.casono.server.network.events.EventBus;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TransportLayer;
/**
* Represents a client session in the network server.
*/
public class Session implements Runnable { public class Session implements Runnable {
private SessionId id; private SessionId id;
private Thread thread; private Thread thread;
@@ -24,7 +21,7 @@ public class Session implements Runnable {
* Creates a new Session with the given transport and event bus. * Creates a new Session with the given transport and event bus.
* *
* @param transport the transport layer for communication * @param transport the transport layer for communication
* @param eventBus the event bus for publishing events * @param eventBus the event bus for publishing events
* @throws IOException if an I/O error occurs during initialization * @throws IOException if an I/O error occurs during initialization
*/ */
public Session(TransportLayer transport, EventBus eventBus) throws IOException { public Session(TransportLayer transport, EventBus eventBus) throws IOException {
@@ -47,9 +44,7 @@ public class Session implements Runnable {
return this.id; return this.id;
} }
/** /** Starts the session thread. */
* Starts the session thread.
*/
public void start() { public void start() {
thread.start(); thread.start();
} }
@@ -64,14 +59,12 @@ public class Session implements Runnable {
this.running = false; this.running = false;
} }
/** /** Runs the session loop, reading from the transport. */
* Runs the session loop, reading from the transport.
*/
@Override @Override
public void run() { public void run() {
while (running) { while (running) {
try { try {
System.out.println("Recieved: " + transport.read()); logger.debug("Recieved: {}", transport.read());
} catch (EOFException e) { } catch (EOFException e) {
logger.info("Client disconnected"); logger.info("Client disconnected");
eventBus.publish(new DisconnectEvent(id)); eventBus.publish(new DisconnectEvent(id));
@@ -2,15 +2,11 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions;
import java.util.UUID; import java.util.UUID;
/** /** Represents a unique identifier for a session. */
* Represents a unique identifier for a session.
*/
public class SessionId { public class SessionId {
private final UUID value; private final UUID value;
/** /** Creates a new SessionId with a randomly generated UUID. */
* Creates a new SessionId with a randomly generated UUID.
*/
public SessionId() { public SessionId() {
this.value = UUID.randomUUID(); this.value = UUID.randomUUID();
} }
@@ -3,15 +3,11 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.sessions;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** /** Manages active sessions in the server. */
* Manages active sessions in the server.
*/
public class SessionManager { public class SessionManager {
private Map<SessionId, Session> sessions; private Map<SessionId, Session> sessions;
/** /** Constructs a new SessionManager. */
* Constructs a new SessionManager.
*/
public SessionManager() { public SessionManager() {
this.sessions = new ConcurrentHashMap<>(); this.sessions = new ConcurrentHashMap<>();
} }
@@ -23,7 +19,6 @@ public class SessionManager {
*/ */
public void addSession(Session session) { public void addSession(Session session) {
sessions.put(session.getId(), session); sessions.put(session.getId(), session);
System.out.println("Added session " + session.getId().value() + " to session manager");
} }
/** /**
@@ -33,7 +28,6 @@ public class SessionManager {
* @return the removed session, or null if not found * @return the removed session, or null if not found
*/ */
public Session removeSession(SessionId id) { public Session removeSession(SessionId id) {
System.out.println("Removed session " + id.value() + " from session manager");
return sessions.remove(id); return sessions.remove(id);
} }
@@ -6,9 +6,7 @@ import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
/** /** Implements TCP-based transport layer for network communication. */
* Implements TCP-based transport layer for network communication.
*/
public class TcpTransport implements TransportLayer { public class TcpTransport implements TransportLayer {
private Socket socket; private Socket socket;
private DataInputStream in; private DataInputStream in;
@@ -2,9 +2,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.network.transport;
import java.io.IOException; import java.io.IOException;
/** /** Interface for transport layer implementations. */
* Interface for transport layer implementations.
*/
public interface TransportLayer { public interface TransportLayer {
/** /**
* Reads data from the transport layer. * Reads data from the transport layer.