Archived
1
0
Fork 0

Merge branch 'ziedelth' into 'main'

Ziedelth

See merge request p1905458/java-tp!2
This commit is contained in:
Ethanell 2022-01-07 09:27:13 +00:00
commit 6b3cd0613e
13 changed files with 336 additions and 44 deletions

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
.idea/ .idea/
/target/ /target/
/connection.properties

21
pom.xml
View file

@ -34,21 +34,33 @@
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>5.7.1</version> <version>5.8.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.7.1</version> <version>5.8.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>22.0.0</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<defaultGoal>package</defaultGoal>
<sourceDirectory>src</sourceDirectory> <sourceDirectory>src</sourceDirectory>
<testSourceDirectory>src/test/</testSourceDirectory> <testSourceDirectory>src/test/</testSourceDirectory>
<resources>
<resource>
<targetPath>resources</targetPath>
</resource>
</resources>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -73,6 +85,11 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View file

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.2" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="fr.univ.lyon1.gui.controller.ConnectGuiController">
<Label text="Connexion">
<font>
<Font name="System Bold" size="18.0"/>
</font>
</Label>
<StackPane prefHeight="10.0" prefWidth="200.0"/>
<HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<Label text="Adresse :"/>
<TextField fx:id="addressTextField">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
</HBox>
<HBox alignment="CENTER" layoutX="10.0" layoutY="174.0" prefHeight="50.0" prefWidth="200.0">
<Label text="Port :"/>
<TextField fx:id="portTextField">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
</HBox>
<Button mnemonicParsing="false" text="Se connecter" onAction="#connect" fx:id="connectButton">
<VBox.margin>
<Insets top="20.0"/>
</VBox.margin>
</Button>
</VBox>

View file

@ -0,0 +1,43 @@
package fr.univ.lyon1.common;
import org.jetbrains.annotations.NotNull;
import java.io.*;
import java.util.Properties;
public record ServerConfiguration(@NotNull String address, int port) {
@NotNull
private static final File file = new File("connection.properties");
public ServerConfiguration(@NotNull String address, int port) {
this.address = address;
this.port = port;
}
public static ServerConfiguration load() throws IOException, NumberFormatException {
// Check if file non exists, return error to launch server configuration
if (!file.exists()) {
System.out.println("File not exists");
throw new IOException("File not exists");
}
@NotNull final Properties properties = new Properties();
properties.load(new FileReader(file));
return new ServerConfiguration(properties.getProperty("address"), Integer.parseInt(properties.getProperty("port")));
}
public void save() throws IOException {
@NotNull final Properties properties = new Properties();
properties.setProperty("address", this.address);
properties.setProperty("port", String.valueOf(this.port));
properties.store(new FileWriter(file), "Information needed to connect to the server");
}
public @NotNull String getAddress() {
return address;
}
public int getPort() {
return port;
}
}

View file

@ -3,15 +3,16 @@ package fr.univ.lyon1.gui;
import fr.univ.lyon1.client.Client; import fr.univ.lyon1.client.Client;
import fr.univ.lyon1.client.ClientReceive; import fr.univ.lyon1.client.ClientReceive;
import fr.univ.lyon1.common.Message; import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.gui.handlers.MainHandler;
import java.io.IOException; import java.io.IOException;
public class ClientGUI extends Client { public class ClientGUI extends Client {
private final MainGui gui; private final MainHandler gui;
public ClientGUI(MainGui gui, String address, int port) throws IOException, InterruptedException { public ClientGUI(MainHandler handler, String address, int port) throws IOException, InterruptedException {
super(address, port); super(address, port);
this.gui = gui; this.gui = handler;
} }
@Override @Override

View file

@ -1,5 +1,6 @@
package fr.univ.lyon1.gui; package fr.univ.lyon1.gui;
import fr.univ.lyon1.gui.handlers.MainHandler;
import javafx.application.Platform; import javafx.application.Platform;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.scene.Parent; import javafx.scene.Parent;
@ -12,15 +13,13 @@ import javafx.scene.text.Text;
import javafx.scene.text.TextFlow; import javafx.scene.text.TextFlow;
public class ClientPanel extends Parent { public class ClientPanel extends Parent {
private TextArea textToSend = new TextArea(); private final TextArea textToSend = new TextArea();
private ScrollPane scrollReceivedText = new ScrollPane(); private final TextFlow receivedText = new TextFlow();
private TextFlow receivedText = new TextFlow(); private final MainHandler gui;
private Button sendBtn = new Button();
private Button clearBtn = new Button();
private final MainGui gui;
ClientPanel(MainGui gui) { public ClientPanel(MainHandler gui) {
this.gui = gui; this.gui = gui;
ScrollPane scrollReceivedText = new ScrollPane();
scrollReceivedText.setLayoutX(20); scrollReceivedText.setLayoutX(20);
scrollReceivedText.setLayoutY(20); scrollReceivedText.setLayoutY(20);
scrollReceivedText.setPrefWidth(400); scrollReceivedText.setPrefWidth(400);
@ -29,13 +28,14 @@ public class ClientPanel extends Parent {
scrollReceivedText.vvalueProperty().bind(receivedText.heightProperty()); scrollReceivedText.vvalueProperty().bind(receivedText.heightProperty());
this.getChildren().add(scrollReceivedText); this.getChildren().add(scrollReceivedText);
Button sendBtn = new Button();
sendBtn.setPrefWidth(80); sendBtn.setPrefWidth(80);
int btnMargin = 20; int btnMargin = 20;
textToSend.setLayoutX(scrollReceivedText.getLayoutX()); textToSend.setLayoutX(scrollReceivedText.getLayoutX());
textToSend.setLayoutY(scrollReceivedText.getLayoutY() + scrollReceivedText.getPrefHeight() + 20); textToSend.setLayoutY(scrollReceivedText.getLayoutY() + scrollReceivedText.getPrefHeight() + 20);
textToSend.setPrefWidth(400-sendBtn.getPrefWidth()-btnMargin); textToSend.setPrefWidth(400- sendBtn.getPrefWidth()-btnMargin);
textToSend.setPrefHeight(100); textToSend.setPrefHeight(100);
this.getChildren().add(textToSend); this.getChildren().add(textToSend);
textToSend.setOnKeyPressed(this::textToSendKeyPressed); textToSend.setOnKeyPressed(this::textToSendKeyPressed);
@ -49,6 +49,7 @@ public class ClientPanel extends Parent {
this.getChildren().add(sendBtn); this.getChildren().add(sendBtn);
sendBtn.setOnAction(this::sendBtnAction); sendBtn.setOnAction(this::sendBtnAction);
Button clearBtn = new Button();
clearBtn.setText("Clear"); clearBtn.setText("Clear");
clearBtn.setLayoutX(sendBtn.getLayoutX()); clearBtn.setLayoutX(sendBtn.getLayoutX());
clearBtn.setPrefWidth(sendBtn.getPrefWidth()); clearBtn.setPrefWidth(sendBtn.getPrefWidth());

View file

@ -1,45 +1,35 @@
package fr.univ.lyon1.gui; package fr.univ.lyon1.gui;
import fr.univ.lyon1.gui.handlers.MainHandler;
import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler;
import javafx.application.Application; import javafx.application.Application;
import javafx.scene.Group; import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.util.List; import java.io.IOException;
public class MainGui extends Application { public class MainGui extends Application {
private ClientPanel clientPanel;
private ClientGUI client;
@Override @Override
public void start(Stage stage) throws Exception { public void start(Stage stage) {
List<String> parameters = this.getParameters().getUnnamed(); try {
client = new ClientGUI(this, parameters.get(0), Integer.parseInt(parameters.get(1))); new MainHandler().launch(stage);
//ToDo: error management especially for bad server IP/port } catch (IOException | InterruptedException e) {
//ToDo: Server IP/port enter by user on the GUI // Launch server configuration
try {
new ServerConfigurationHandler().launch(stage);
} catch (IOException ex) {
// Can not launch server configuration, stop application
System.exit(1);
}
}
stage.setTitle("Chat client"); stage.setOnCloseRequest(event -> {
stage.setWidth(440); Platform.exit();
System.exit(0);
clientPanel = new ClientPanel(this); });
Group root = new Group();
root.getChildren().add(clientPanel);
Scene scene = new Scene(root, 600, 500);
stage.setScene(scene);
stage.show();
client.run();
} }
public static void main(String[] args) { public static void main(String[] args) {
Application.launch(MainGui.class, args); Application.launch(MainGui.class, args);
} }
public void sendMessage(String msg) {
client.sendMessage(msg);
}
public void receiveMessage(String msg) {
clientPanel.addMessage(msg);
}
} }

View file

@ -0,0 +1,95 @@
package fr.univ.lyon1.gui.controller;
import fr.univ.lyon1.common.ServerConfiguration;
import fr.univ.lyon1.gui.handlers.MainHandler;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.Socket;
public class ConnectGuiController {
@FXML
public TextField addressTextField;
@FXML
public TextField portTextField;
@FXML
public Button connectButton;
/**
* Called by submit button in resources/connect_gui.fxml
*/
public void connect() {
this.connectButton.setDisable(true);
@NotNull
final String address = this.addressTextField.getText();
@NotNull
final String port = this.portTextField.getText();
System.out.println("Checking if port is valid...");
// Check if the port is a number and if it's an available port
if (this.isNumber(port) && this.isAvailablePort(Integer.parseInt(port))) {
final int iPort = Integer.parseInt(port);
System.out.println("Port valid, next step...");
System.out.println("Checking if connection is available...");
// Check if the connection is available
if (this.isAccessible(address, iPort)) {
System.out.println("Connection available, saving file...");
try {
// Save server configuration
new ServerConfiguration(address, iPort).save();
Dialog.showSuccessDialog("Connecté", "Vous êtes bien connecté au serveur");
System.out.println("File saved, next step...");
@NotNull
final Stage stage = (Stage) this.connectButton.getScene().getWindow();
new MainHandler().launch(stage);
} catch (IOException e) {
Dialog.showErrorDialog("Erreur", "Impossible de sauvegarder les informations de connexion au serveur");
this.connectButton.setDisable(false);
System.out.println("Failed to save file, error: " + e.getMessage());
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
System.out.println("Connection not available");
Dialog.showErrorDialog("Erreur de connexion", "Impossible de se connecter au serveur, veuillez vérifier les informations saisies");
this.connectButton.setDisable(false);
}
} else {
Dialog.showErrorDialog("Erreur", "Veuillez saisir un numéro de port valide");
this.connectButton.setDisable(false);
}
}
private boolean isNumber(String text) {
try {
Integer.parseInt(text);
return true;
} catch (NumberFormatException ignored) {
return false;
}
}
private boolean isAvailablePort(int port) {
return !(port < 0 || port > 0xFFFF);
}
private boolean isAccessible(String address, int port) {
try {
@NotNull
final Socket socket = new Socket(address, port);
socket.setSoTimeout(5 * 1000);
return true;
} catch (IOException exception) {
return false;
}
}
}

View file

@ -0,0 +1,24 @@
package fr.univ.lyon1.gui.controller;
import javafx.scene.control.Alert;
import org.jetbrains.annotations.NotNull;
public class Dialog {
public static void showErrorDialog(String title, String description) {
@NotNull
final Alert alert = new Alert(Alert.AlertType.WARNING);
extracted(title, description, alert);
}
public static void showSuccessDialog(String title, String description) {
@NotNull
final Alert alert = new Alert(Alert.AlertType.INFORMATION);
extracted(title, description, alert);
}
private static void extracted(String title, String description, @NotNull Alert alert) {
alert.setTitle(title);
alert.setContentText(description);
alert.show();
}
}

View file

@ -0,0 +1,9 @@
package fr.univ.lyon1.gui.handlers;
import javafx.stage.Stage;
import java.io.IOException;
public interface Handler {
void launch(Stage stage) throws IOException, InterruptedException;
}

View file

@ -0,0 +1,50 @@
package fr.univ.lyon1.gui.handlers;
import fr.univ.lyon1.common.ServerConfiguration;
import fr.univ.lyon1.gui.ClientGUI;
import fr.univ.lyon1.gui.ClientPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
public class MainHandler implements Handler {
private ClientPanel clientPanel;
@Nullable
private ClientGUI client;
@Override
public void launch(Stage stage) throws IOException, InterruptedException {
@NotNull
final ServerConfiguration serverConfiguration = ServerConfiguration.load();
this.client = new ClientGUI(this, serverConfiguration.getAddress(), serverConfiguration.getPort());
stage.setTitle("Chat client");
stage.setWidth(440);
this.clientPanel = new ClientPanel(this);
Group root = new Group();
root.getChildren().add(this.clientPanel);
Scene scene = new Scene(root, 600, 500);
stage.setScene(scene);
stage.show();
if (this.client != null) {
this.client.run();
}
}
public void sendMessage(String msg) {
if (client != null) {
client.sendMessage(msg);
}
}
public void receiveMessage(String msg) {
clientPanel.addMessage(msg);
}
}

View file

@ -0,0 +1,18 @@
package fr.univ.lyon1.gui.handlers;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class ServerConfigurationHandler implements Handler {
@Override
public void launch(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("connect_gui.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Configuration du serveur");
stage.setScene(scene);
stage.show();
}
}

View file

@ -1,9 +1,14 @@
module fr.univ.lyon1.gui { module fr.univ.lyon {
requires javafx.controls; requires javafx.controls;
requires javafx.fxml; requires javafx.fxml;
requires org.kordamp.bootstrapfx.core; requires org.kordamp.bootstrapfx.core;
requires org.jetbrains.annotations;
opens fr.univ.lyon1.gui to javafx.fxml; opens fr.univ.lyon1.gui to javafx.fxml;
exports fr.univ.lyon1.common;
exports fr.univ.lyon1.gui; exports fr.univ.lyon1.gui;
exports fr.univ.lyon1.gui.controller;
exports fr.univ.lyon1.gui.handlers;
} }