Fix: Resolving Git Merge Conflicts #253

Merged
j.kropff merged 69 commits from chore/ui-checkstyle-fixes into main 2026-04-11 15:10:58 +02:00
17 changed files with 196 additions and 93 deletions
Showing only changes of commit c0c9225d42 - Show all commits
@@ -3,6 +3,7 @@ package ch.unibas.dmi.dbis.cs108.casono.client;
/** /**
* Entry point for the Casono client application. Handles client startup and connection parameters. * Entry point for the Casono client application. Handles client startup and connection parameters.
*/ */
import ch.unibas.dmi.dbis.cs108.casono.client.ui.Launcher; import ch.unibas.dmi.dbis.cs108.casono.client.ui.Launcher;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -77,13 +77,14 @@ public class ChatController {
switch (msg.getMessageType()) { switch (msg.getMessageType()) {
case ChatType.GLOBAL: case ChatType.GLOBAL:
chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg); chatModelMap.get(new ChatKey(ChatType.GLOBAL)).addMessage(msg);
break;
case ChatType.LOBBY: case ChatType.LOBBY:
if (msg.lobbyId == lobbyId) { if (msg.lobbyId == lobbyId) {
chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY), chatModelMap.computeIfAbsent(new ChatKey(ChatType.LOBBY),
(_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg); (_key) -> new ChatModel(ChatType.LOBBY, username, msg.lobbyId, null)).addMessage(msg);
} }
break;
case ChatType.WHISPER: case ChatType.WHISPER:
// TODO: Check, if target person is user and if yes, iterate through all
if (msg.target.equals(username)) { if (msg.target.equals(username)) {
if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) { if (chatModelMap.containsKey(new ChatKey(ChatType.WHISPER, msg.sender))) {
chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg); chatModelMap.get(new ChatKey(ChatType.WHISPER, msg.sender)).addMessage(msg);
@@ -93,6 +94,7 @@ public class ChatController {
chatBoxController.addWhisperChat(msg.sender, value); chatBoxController.addWhisperChat(msg.sender, value);
} }
} }
break;
} }
@@ -1,10 +1,10 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat; package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatViewController;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.function.Consumer;
/** /**
* ChatModel, stores the data for a specific chat * ChatModel, stores the data for a specific chat
@@ -13,6 +13,8 @@ import java.util.ArrayList;
*/ */
public class ChatModel { public class ChatModel {
private ArrayList<Consumer<Message>> listeners = new ArrayList<>();
public ArrayList<Message> messages; public ArrayList<Message> messages;
private final ChatType chattype; private final ChatType chattype;
@@ -62,18 +64,12 @@ public class ChatModel {
*/ */
public synchronized void addMessage(Message msg) { public synchronized void addMessage(Message msg) {
messages.add(msg); messages.add(msg);
count.add(1); listeners.stream().forEach((l)-> l.accept(messages.getLast()));
} }
public void addListener(ChatViewController chatViewController) { public void addListener(Consumer<Message> listener) {
count.addListener( this.listeners.add(listener);
(_count, _p, n) ->
{
if(n.intValue() > 0) {
chatViewController.showMessage();
}
});
} }
public String getTarget() { public String getTarget() {
@@ -1,12 +1,14 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat; package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter; import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBody;
import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.ResponseBodyBuilder;
import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NonNull;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
/** /**
@@ -80,10 +82,16 @@ public class Message {
* @return - request as specified in the network protocol, as String * @return - request as specified in the network protocol, as String
*/ */
public String toArgsString() { public String toArgsString() {
String gameIdString="";
if(lobbyId >= 0) {
gameIdString=" GAME="+lobbyId;
} else {
gameIdString=" GAME='-1'";
}
return String.format( return String.format(
"TYPE=%s GAME=%d USER=%s TARGET=%s TIME=%s TEXT='%s'", "TYPE=%s%s USER='%s' TARGET='%s' TIME='%s' TEXT='%s'",
this.type.toString(), this.type.toString(),
this.lobbyId, gameIdString,
this.sender, this.sender,
this.target, this.target,
this.timestamp, this.timestamp,
@@ -93,16 +101,18 @@ public class Message {
/** Pattern, to analyze the response String with the given parameters */ /** Pattern, to analyze the response String with the given parameters */
public static Pattern msgRex = public static Pattern msgRex =
Pattern.compile( Pattern.compile(
"TYPE=(?<type>\\w+) " + "GAME=(?<game>\\w+) " + "TYPE=(?<type>\\w+) " + "(GAME=(?<game>\\w+) )?" +
"USER=(?<user>\\w+) " + "TARGET=(?<target>\\w+) " + "USER=(?<user>\\w+) " + "(TARGET=(?<target>\\w+) )?" +
"TIME=(?<time>[0-9:.]+) " + "TEXT='(?<text>([^']|\\')+)'"); "TIME=(?<time>[0-9:.]+) " + "TEXT='(?<text>([^']|\\')+)'");
/** /**
* Method to create a Message Object, from the information given by the String * Method to create a Message Object, from the information given by the String
* *
* @param response - String that got sent as a response from the server * @param response - String that got sent as a response from the server
* @return - New Message Object * @return - New Message Object
*/ */
/*
public static Message toMessage(String response) { public static Message toMessage(String response) {
Matcher m = msgRex.matcher(response); Matcher m = msgRex.matcher(response);
if (!m.matches()) { if (!m.matches()) {
@@ -114,16 +124,18 @@ public class Message {
case "GLOBAL": case "GLOBAL":
return new Message( return new Message(
ChatType.GLOBAL, ChatType.GLOBAL,
0, -1,
m.group("user"), m.group("user"),
null, null,
m.group("time"), m.group("time"),
m.group("text")); m.group("text"));
case "LOBBY": case "LOBBY":
int gameId = getGameId(m.group("game"));
return new Message( return new Message(
ChatType.LOBBY, ChatType.LOBBY,
Integer.parseInt(m.group("game")), gameId,
m.group("user"), m.group("user"),
null, null,
m.group("time"), m.group("time"),
@@ -132,7 +144,7 @@ public class Message {
case "WHISPER": case "WHISPER":
return new Message( return new Message(
ChatType.WHISPER, ChatType.WHISPER,
Integer.parseInt(m.group("game")), -1,
m.group("user"), m.group("user"),
m.group("target"), m.group("target"),
m.group("time"), m.group("time"),
@@ -142,13 +154,22 @@ public class Message {
throw new RuntimeException("Unknown message type " + typeString); throw new RuntimeException("Unknown message type " + typeString);
} }
} }
*/
public static Message toMessage(List<RequestParameter> parameters) { private static int getGameId(String gameIdStr) {
int gameId = -1;
if (gameIdStr != null) {
gameId = Integer.parseInt(gameIdStr);
}
return gameId;
}
public static Message toMessageReqPars(List<RequestParameter> parameters) {
String typeString = getParString(parameters, "TYPE"); String typeString = getParString(parameters, "TYPE");
ChatType type = ChatType.valueOf(typeString); ChatType type = ChatType.valueOf(typeString);
return switch (type) { return switch (type) {
case GLOBAL -> new Message(ChatType.GLOBAL, case GLOBAL -> new Message(ChatType.GLOBAL,
0, -1,
getParString(parameters, "USER"), getParString(parameters, "USER"),
null, null,
getParString(parameters, "TIME"), getParString(parameters, "TIME"),
@@ -162,7 +183,7 @@ public class Message {
getParString(parameters, "TEXT") getParString(parameters, "TEXT")
); );
case WHISPER -> new Message(ChatType.WHISPER, case WHISPER -> new Message(ChatType.WHISPER,
Integer.parseInt(getParString(parameters, "GAME")), Integer.parseInt(getParString(parameters, "GAME", "-1")),
getParString(parameters, "USER"), getParString(parameters, "USER"),
getParString(parameters, "TARGET"), getParString(parameters, "TARGET"),
getParString(parameters, "TIME"), getParString(parameters, "TIME"),
@@ -171,11 +192,32 @@ public class Message {
}; };
} }
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) { private static @NonNull String getParString(List<RequestParameter> parameters, String keyString) {
return parameters.stream().filter((p) -> "TYPE".equals(p.key())) return getParString(parameters, keyString, null);
}
private static @NonNull String getParString(List<RequestParameter> parameters, String keyString, String defaultVal) {
Optional<String> parOption = parameters.stream().filter((p) -> keyString.equals(p.key()))
.findFirst() .findFirst()
.map(RequestParameter::value) .map(RequestParameter::value);
.orElseThrow(() -> new RuntimeException("No " + keyString + " found")); if(parOption.isEmpty()) {
if (defaultVal == null) {
throw new RuntimeException("No " + keyString + " found");
} else {
return defaultVal;
}
}
return parOption.get();
}
public ResponseBody toResponse(ResponseBodyBuilder builder) {
builder.param("TYPE", type.name());
builder.param("GAME", lobbyId);
builder.param("USER", this.sender);
if (target != null) {
builder.param("TARGET", target);
}
builder.param("TIME", this.timestamp);
builder.param("TEXT", this.message);
return builder.build();
} }
} }
@@ -1,11 +1,12 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network; package ch.unibas.dmi.dbis.cs108.casono.client.network;
import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message; import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* The ChatClient class is responsible for sending messages to the server and * The ChatClient class is responsible for sending messages to the server and
@@ -15,6 +16,7 @@ import java.util.regex.Pattern;
public class ChatClient { public class ChatClient {
private final ClientService clientService; private final ClientService clientService;
private final Logger logger;
/** /**
* Constructs a ChatClient with the given ClientService for communication. * Constructs a ChatClient with the given ClientService for communication.
@@ -24,6 +26,7 @@ public class ChatClient {
*/ */
public ChatClient(ClientService clientService) { public ChatClient(ClientService clientService) {
this.clientService = clientService; this.clientService = clientService;
this.logger = LogManager.getLogger(ChatClient.class);
} }
/** /**
@@ -34,6 +37,7 @@ public class ChatClient {
*/ */
public void sendMessage(Message message) { public void sendMessage(Message message) {
String request = "SEND_MESSAGE " + message.toArgsString(); String request = "SEND_MESSAGE " + message.toArgsString();
logger.info("Writing to server: " + request);
clientService.processCommand(request); clientService.processCommand(request);
} }
@@ -47,24 +51,20 @@ public class ChatClient {
* the server. * the server.
*/ */
public List<Message> getMessages() { public List<Message> getMessages() {
String countStr = clientService.processCommand("GET_MESSAGE_COUNT"); logger.info("Asking server for new messages");
Matcher m = countRex.matcher(countStr); List<RequestParameter> countStr = ClientService.convertToRequestParameters(clientService.processCommand("GET_MESSAGE_COUNT"));
if (!m.matches()) { RequestParameter countRes = countStr.getFirst();
throw new RuntimeException("Can not parse response: " + countStr); if (!countRes.key().equals("COUNT")) {
logger.error("Not the right response from server");
} }
int count = Integer.parseInt(m.group("count")); int count = Integer.parseInt(countRes.value());
System.out.println("Got " + count + " messages"); logger.info("Got " + count + " messages");
List<Message> messages = new ArrayList<>(); ArrayList<Message> messages = new ArrayList<>();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
String message = clientService.processCommand("GET_NEXT_MESSAGE"); List<RequestParameter> msgRes = ClientService.convertToRequestParameters(clientService.processCommand("GET_NEXT_MESSAGE"));
if (message != null) { Message msg = Message.toMessageReqPars(msgRes);
Message message1 = Message.toMessage(message); messages.add(msg);
messages.add(message1);
}
} }
return messages; return messages;
} }
public static Pattern countRex = Pattern.compile("COUNT=(?<count>[0-9]+)");
} }
// (?<key>\w+)='(?<string>([^']|\')+)'|(?<primVal>[\d\w]+)
@@ -1,5 +1,6 @@
package ch.unibas.dmi.dbis.cs108.casono.client.network; package ch.unibas.dmi.dbis.cs108.casono.client.network;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.RawPacket; import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.RawPacket;
import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport; import ch.unibas.dmi.dbis.cs108.casono.server.network.transport.TcpTransport;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
@@ -8,12 +9,14 @@ import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* The ClientService class is responsible for managing the connection to the * The ClientService class is responsible for managing the connection to the
@@ -58,6 +61,8 @@ public class ClientService {
} }
static Pattern responseRex = Pattern.compile("(?<key>\\w+)=(('(?<string>([^']|\\')+)')|(?<primVal>[+-]?[\\d\\w:]+))");
/** /**
* Sends the Requests to the server and waits for the response If the response is "+OK" it * Sends the Requests to the server and waits for the response If the response is "+OK" it
* proceeds normal If the response "-ERROR" it throws a runtime exception * proceeds normal If the response "-ERROR" it throws a runtime exception
@@ -65,36 +70,61 @@ public class ClientService {
* @param message * @param message
* @return - The response as a string, if it has to be returned (+OK will not be returned) * @return - The response as a string, if it has to be returned (+OK will not be returned)
*/ */
protected String processCommand(String message) { private static String unescape(String input) {
AtomicReference<String> response = new AtomicReference<>(); return input.replaceAll("\\\\'", "'");
}
public static List<RequestParameter> convertToRequestParameters(List<String> input) {
return input.stream().map((String parString)-> responseRex.matcher(parString))
.filter(Matcher::matches)
.map((m)->{
if (!(m.group("string") == null)) {
return new RequestParameter(m.group("key"), unescape(m.group("string")));
} else if (!(m.group("primVal") == null)){
return new RequestParameter(m.group("key"), m.group("primVal"));
} else {
throw new RuntimeException();
}
}).toList();
}
protected List<String> processCommand(String message) {
List<String> response = new ArrayList<>();
sendRequest( sendRequest(
() -> { () -> {
try { try {
writeToTransport(message); writeToTransport(message);
String responseText = null; String responseText = null;
do {
responseText = clienttcptransport.read().payload(); responseText = clienttcptransport.read().payload();
logger.info("Raw message '" + responseText + "'"); logger.info("Raw message '" + responseText + "'");
for(String line: responseText.split("\n")) { Boolean success = null;
int count = 0;
for(String line: responseText.split("\n")) {
if (success == null) {
if ("+OK".equals(line)) { if ("+OK".equals(line)) {
return; success = true;
continue;
} else if (("-ERROR").equals(responseText)) { } else if (("-ERROR").equals(responseText)) {
throw new RuntimeException(responseText); success = false;
} else {
String start = response.get();
if(start == null) {
response.set(line);
} else {
response.set(start + "\n" + line);
}
} }
continue;
} else if ("END".equals(line)) {
break;
} }
} while (true); line = line.replaceFirst("^\t", "");
response.add(line);
}
if (success!= null && success) {
return;
} else {
throw new RuntimeException("Error in "+message+": "+response);
}
} catch (Exception e) { } catch (Exception e) {
throw getRuntimeException(e); throw getRuntimeException(e);
} }
}); });
return response.get(); return response;
} }
/** /**
@@ -4,7 +4,6 @@ import ch.unibas.dmi.dbis.cs108.casono.client.game.Card;
import ch.unibas.dmi.dbis.cs108.casono.client.game.GameState; import ch.unibas.dmi.dbis.cs108.casono.client.game.GameState;
import ch.unibas.dmi.dbis.cs108.casono.client.game.Player; import ch.unibas.dmi.dbis.cs108.casono.client.game.Player;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
@@ -33,7 +32,7 @@ public class GameClient {
* @return A GameState object representing the current state of the game. * @return A GameState object representing the current state of the game.
*/ */
public GameState getGameState() { public GameState getGameState() {
String response = client.processCommand("GET_GAME_STATE"); List<String> response = client.processCommand("GET_GAME_STATE");
return parseGameState(response); return parseGameState(response);
} }
@@ -43,16 +42,14 @@ public class GameClient {
* @param input The raw response string from the server. * @param input The raw response string from the server.
* @return A GameState object representing the current state of the game. * @return A GameState object representing the current state of the game.
*/ */
private GameState parseGameState(String input) { private GameState parseGameState(List<String> input) {
GameState state = new GameState(); GameState state = new GameState();
String[] lines = input.split("\n");
Player currentPlayer = null; Player currentPlayer = null;
Card currentCard = null; Card currentCard = null;
for (String rawLine : lines) { for (String rawLine : input) {
String line = rawLine.trim(); String line = rawLine.trim();
@@ -27,7 +27,7 @@ public class LobbyClient {
* by the server. * by the server.
*/ */
public String fetchLobbyStatusString(int lobbyId) { public String fetchLobbyStatusString(int lobbyId) {
return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId); return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId).getFirst();
} }
/** /**
@@ -37,7 +37,7 @@ public class LobbyClient {
* @return The id of the newly created lobby, as returned by the server. * @return The id of the newly created lobby, as returned by the server.
*/ */
public int createLobby() { public int createLobby() {
String response = client.processCommand("CREATE_LOBBY"); String response = client.processCommand("CREATE_LOBBY").getFirst();
return Integer.parseInt(response); return Integer.parseInt(response);
} }
@@ -49,7 +49,7 @@ public class LobbyClient {
* the server. * the server.
*/ */
public int getLobbyId() { public int getLobbyId() {
String response = client.processCommand("GET_LOBBY_ID"); String response = client.processCommand("GET_LOBBY_ID").getFirst();
return Integer.parseInt(response); return Integer.parseInt(response);
} }
@@ -51,7 +51,7 @@ public class ChatBoxController {
URL resource = getClass().getResource(ressource); URL resource = getClass().getResource(ressource);
FXMLLoader fxmlLoader = new FXMLLoader(resource); FXMLLoader fxmlLoader = new FXMLLoader(resource);
ChatViewController chatViewController = new ChatViewController(username, chatModel, chatController); ChatViewController chatViewController = new ChatViewController(username, chatModel, chatController);
chatModel.addListener(chatViewController); chatModel.addListener((msg)-> chatViewController.showMessage(msg));
try { try {
fxmlLoader.setController(chatViewController); fxmlLoader.setController(chatViewController);
Tab newChat = new Tab(title, fxmlLoader.load()); Tab newChat = new Tab(title, fxmlLoader.load());
@@ -22,13 +22,13 @@ public class ChatViewController implements Initializable {
@FXML private TextField inputField; @FXML private TextField inputField;
@FXML private VBox chatVBox; @FXML private VBox chatInterfaceVBox;
@FXML private HBox controlBar; @FXML private HBox controlBar;
@FXML private ScrollPane scrollPane; @FXML private ScrollPane scrollPane;
@FXML private VBox Chat; @FXML private VBox chat;
private final ChatModel chatModel; private final ChatModel chatModel;
@@ -54,7 +54,7 @@ public class ChatViewController implements Initializable {
public void initialize(URL location, ResourceBundle resourceBundle) { public void initialize(URL location, ResourceBundle resourceBundle) {
inputField.setOnAction(event -> sendMessage()); inputField.setOnAction(event -> sendMessage());
sendButton.setOnAction(event -> sendMessage()); sendButton.setOnAction(event -> sendMessage());
scrollPane.vvalueProperty().bind(chatVBox.heightProperty()); scrollPane.vvalueProperty().bind(chatInterfaceVBox.heightProperty());
} }
public void sendMessage() { public void sendMessage() {
@@ -66,13 +66,13 @@ public class ChatViewController implements Initializable {
} }
} }
public void showMessage() { public void showMessage(Message msg) {
String msg = chatModel.viewNextMessage(); String msgText = String.format("[%s] %s: %s", msg.timestamp, msg.sender, msg.getMessage());
Label label = new Label(msg); Label label = new Label(msgText);
label.getStyleClass().add("info-text"); label.getStyleClass().add("info-text");
label.setWrapText(true); label.setWrapText(true);
label.maxWidthProperty().bind(chatVBox.widthProperty().subtract(CHAT_PADDING)); label.maxWidthProperty().bind(chat.widthProperty().subtract(CHAT_PADDING));
chatVBox.getChildren().add(label); chat.getChildren().add(label);
} }
@@ -31,7 +31,7 @@ public class GetNextMessageHandler implements CommandHandler<GetNextMessageReque
} else { } else {
ErrorResponse response = new ErrorResponse( ErrorResponse response = new ErrorResponse(
request.getContext(), request.getContext(),
"", "NO_USER_ASSOCIATED",
"user could not be identified by SessionId" "user could not be identified by SessionId"
); );
@@ -7,8 +7,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.response.builder.
public class GetNextMessageResponse extends SuccessResponse { public class GetNextMessageResponse extends SuccessResponse {
public GetNextMessageResponse(RequestContext context, Message msg) { public GetNextMessageResponse(RequestContext context, Message msg) {
super(context, ResponseBody.builder() super(context, msg.toResponse(ResponseBody.builder())
.param("MESSAGE", msg.toArgsString()) );
.build());
} }
} }
@@ -7,7 +7,7 @@ import ch.unibas.dmi.dbis.cs108.casono.server.network.protocol.request.Primitive
public class SendMessageParser implements CommandParser<SendMessageRequest> { public class SendMessageParser implements CommandParser<SendMessageRequest> {
@Override @Override
public SendMessageRequest parse(PrimitiveRequest primitiveRequest) { public SendMessageRequest parse(PrimitiveRequest primitiveRequest) {
Message msg = Message.toMessage(primitiveRequest.parameters()); Message msg = Message.toMessageReqPars(primitiveRequest.parameters());
return new SendMessageRequest(primitiveRequest.context(), msg); return new SendMessageRequest(primitiveRequest.context(), msg);
} }
} }
@@ -4,11 +4,13 @@
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<!-- fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController" -->
<VBox xmlns="http://javafx.com/javafx/21" <VBox xmlns="http://javafx.com/javafx/21"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:id="chatBox" fx:id="chatBox"
fx:controller="ch.unibas.dmi.dbis.cs108.casono.client.ui.chatui.ChatBoxController"
VBox.vgrow="ALWAYS" VBox.vgrow="ALWAYS"
stylesheets="@chatui.css"
styleClass="chat-box" styleClass="chat-box"
spacing="10" spacing="10"
maxWidth="Infinity"> maxWidth="Infinity">
@@ -9,16 +9,16 @@
<!-- VBox for the global chat, should only be visible when activated via changeGlobalChatButton--> <!-- VBox for the global chat, should only be visible when activated via changeGlobalChatButton-->
<VBox xmlns="http://javafx.com/javafx/21" <VBox xmlns="http://javafx.com/javafx/21"
xmlns:fx="http://javafx.com/fxml/1" xmlns:fx="http://javafx.com/fxml/1"
fx:id="chatVBox"> fx:id="chatInterfaceVBox"
stylesheets="@chatui.css"
styleClass="chat-box">
<Label text="== CHAT ==" styleClass="chat-header" alignment="CENTER" maxWidth="Infinity"/>
<Region minHeight="4" styleClass="chat-separator"/>
<!-- Chatnachrichten werden hier hinzugefügt --> <!-- Chatnachrichten werden hier hinzugefügt -->
<ScrollPane fx:id="scrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER" <ScrollPane fx:id="scrollPane" fitToWidth="true" vbarPolicy="AS_NEEDED" hbarPolicy="NEVER"
VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane"> VBox.vgrow="ALWAYS" styleClass="chat-scroll-pane">
<content> <content>
<VBox fx:id="Chat" spacing="10" styleClass="chat-VBox"/> <VBox fx:id="chat" spacing="10" styleClass="chat-VBox"/>
</content> </content>
</ScrollPane> </ScrollPane>
@@ -27,8 +27,8 @@
fx:id="controlBar"> fx:id="controlBar">
<!-- TODO: Größe des TextFields dynamisch anpassen --> <!-- TODO: Größe des TextFields dynamisch anpassen -->
<TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..." <TextField fx:id="inputField" HBox.hgrow="ALWAYS" promptText="Nachricht eingeben..."
styleClass="gray-input-field" onAction="#sendMessage"/> styleClass="gray-input-field"/>
<Button fx:id="sendButton" text="SENDEN" onAction="#sendMessage" <Button fx:id="sendButton" text="SENDEN"
styleClass="yellow-button"/> styleClass="yellow-button"/>
</HBox> </HBox>
</VBox> </VBox>
@@ -27,7 +27,9 @@ public class ChatApplication extends Application {
// TODO login UI // TODO login UI
coreClient.login(username); coreClient.login(username);
ChatController chatController = new ChatController(username, clientService); ChatController chatController = new ChatController(username, clientService);
fxmlLoader.setControllerFactory(type -> { ChatBoxController chatBoxController = new ChatBoxController(username, chatController);
fxmlLoader.setController(chatBoxController);
/*fxmlLoader.setControllerFactory(type -> {
if (type == ChatBoxController.class) { if (type == ChatBoxController.class) {
return chatController.getChatBoxController(); return chatController.getChatBoxController();
} else { } else {
@@ -37,7 +39,7 @@ public class ChatApplication extends Application {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
}); });*/
Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT); Scene scene = new Scene(fxmlLoader.load(), SCENE_WIDTH, SCENE_HEIGHT);
stage.setTitle("Chat"); stage.setTitle("Chat");
@@ -1,11 +1,43 @@
package ch.unibas.dmi.dbis.cs108.casono.client.chat; package ch.unibas.dmi.dbis.cs108.casono.client.chat;
import ch.unibas.dmi.dbis.cs108.casono.client.network.ClientService;
import ch.unibas.dmi.dbis.cs108.casono.server.network.command.parsing.RequestParameter;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ChatTest { public class ChatTest {
@Test @Test
public void chatTest() { public void chatTest() {
List<String> list = new ArrayList<String>();
list.add("COUNT=19199");
list.add("TEXT='test \\' test'");
list.add("TEXT='%/§§%&&/%=%$/%))==/?``*\\'\\'**\\'\\'§?'");
list.add("TEXT='Hello World'");
list.add("NUMBER=-56887387394898392849");
List<RequestParameter> newList = ClientService.convertToRequestParameters(list);
RequestParameter par0 = newList.get(0);
assertEquals("COUNT", par0.key());
assertEquals("19199", par0.value());
RequestParameter par1 = newList.get(1);
assertEquals("TEXT", par1.key());
assertEquals("test ' test", par1.value());
RequestParameter par2 = newList.get(2);
assertEquals("TEXT", par2.key());
assertEquals("%/§§%&&/%=%$/%))==/?``*''**''§?", par2.value());
RequestParameter par4 = newList.get(4);
assertEquals("NUMBER", par4.key());
assertEquals("-56887387394898392849", par4.value());
} }
} }