Merge branch 'dev-hosts' into 'dev'

feat(host): gestion de l'ajout de nouveaux hôtes/adresses serveur

See merge request iut_rt/but2/sae302-applicom/bouclyma!9
This commit is contained in:
Emi Boucly 2025-01-28 14:29:36 +01:00
commit 115b5d0a41
6 changed files with 165 additions and 11 deletions

View file

@ -16,17 +16,15 @@ import java.util.logging.Logger;
public class ChatApplication extends Application {
public static final Logger LOGGER = Logger.getLogger(ChatApplication.class.getCanonicalName());
public class EssaiLogger {
static {
try {
InputStream is = EssaiLogger.class.getClassLoader()
InputStream is = ChatApplication.class
.getResource("logging.properties").openStream();
LogManager.getLogManager().readConfiguration(is);
} catch (Exception e) {
LOGGER.log(Level.INFO, "Cannot read configuration file", e);
}
}
}
@Override
public void start(Stage stage) throws IOException {

View file

@ -10,7 +10,9 @@ import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
@ -19,6 +21,7 @@ import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Modality;
import javafx.stage.Stage;
import net.synedra.validatorfx.Check;
import net.synedra.validatorfx.TooltipWrapper;
@ -98,6 +101,7 @@ public class ChatController implements Initializable {
loginTextField.disableProperty().bind(connectionButton.selectedProperty());
hostComboBox.disableProperty().bind(connectionButton.selectedProperty());
hostAddMenuItem.setOnAction(this::handleHostAdd);
avatarMenuItem.setOnAction(this::handleAvatarChange);
avatarImageView.setOnMouseClicked(this::handleAvatarChange);
sendButton.setOnAction(this::onActionSend);
@ -128,6 +132,39 @@ public class ChatController implements Initializable {
}
private void handleHostAdd(ActionEvent actionEvent) {
try {
ChatHostAddController controller = showNewStage("Add host", "chathostadd-view.fxml");
if (controller.isOk()) {
hostComboBox.getItems().add(controller.hostTextField.getText());
hostComboBox.setValue(controller.hostTextField.getText());
}
} catch (IOException e) {
LOGGER.warning("Impossible d'ouvrir la fenêtre de dialogue: fxml introuvable \n" + e.getMessage());
e.printStackTrace();
}
}
/**
* Ouvre une fenêtre modale et attend qu'elle se ferme.
*
* @param title titre de la fenêtre
* @param fxmlFileName nom du fichier FXML décrivant l'interface graphique
* @return l'objet contrôleur associé à la fenêtre
* @throws IOException si le fichier FXML n'est pas trouvé dans les ressources
*/
public <T> T showNewStage(String title, String fxmlFileName) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ChatApplication.class.getResource(fxmlFileName));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setTitle(title);
stage.setResizable(false);
stage.setScene(scene);
stage.showAndWait();
return fxmlLoader.getController();
}
private void initRoomListView() {
try {
roomsListView.setCellFactory(roomListView -> new RoomListViewCell());

View file

@ -0,0 +1,70 @@
package rtgre.chat;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import net.synedra.validatorfx.Check;
import net.synedra.validatorfx.TooltipWrapper;
import net.synedra.validatorfx.Validator;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ChatHostAddController implements Initializable {
public TextField hostTextField;
public Button resetButton;
public HBox submitWrapper;
public Button submitButton;
private boolean ok = false;
public static final Pattern HOST_PORT_REGEX = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
private Validator validatorHost = new Validator();
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
submitButton.setOnAction(this::onActionSubmit);
resetButton.setOnAction(this::onActionReset);
submitButton.disableProperty().bind(validatorHost.containsErrorsProperty());
TooltipWrapper<Button> submitWrapper = new TooltipWrapper<>(
submitButton,
validatorHost.containsErrorsProperty(),
Bindings.concat("Cannot submit:\n", validatorHost.createStringBinding())
);
this.submitWrapper.getChildren().add(submitWrapper);
validatorHost.createCheck()
.dependsOn("host", hostTextField.textProperty())
.withMethod(this::checkHost)
.decorates(hostTextField)
.immediate();
}
private void checkHost(Check.Context context) {
String host = context.get("host");
if (!HOST_PORT_REGEX.matcher(host).matches()) {
context.error("Host should be a valid IP address or name with potentially port number");
}
}
private void onActionReset(ActionEvent actionEvent) {
hostTextField.setText("");
}
private void onActionSubmit(ActionEvent actionEvent) {
ok = true;
((Stage) submitButton.getScene().getWindow()).close();
}
public boolean isOk() {
return ok;
}
}

View file

@ -2,6 +2,7 @@ package rtgre.server;
import org.json.JSONException;
import org.json.JSONObject;
import rtgre.chat.ChatController;
import rtgre.chat.net.ChatClient;
import rtgre.modeles.*;
@ -28,7 +29,7 @@ public class ChatServer {
static {
try {
InputStream is = ChatServer.class.getClassLoader()
InputStream is = ChatController.class
.getResource("logging.properties").openStream();
LogManager.getLogManager().readConfiguration(is);
} catch (Exception e) {

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/23.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="rtgre.chat.ChatHostAddController">
<children>
<GridPane prefWidth="400.0">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" maxWidth="289.0" minWidth="10.0" prefWidth="82.40000190734864" />
<ColumnConstraints hgrow="SOMETIMES" maxWidth="536.0000076293945" minWidth="10.0" prefWidth="307.99999809265137" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label text="Host (IP:port)" />
<TextField fx:id="hostTextField" prefWidth="200.0" GridPane.columnIndex="1" />
</children>
<padding>
<Insets bottom="3.0" left="3.0" right="3.0" top="3.0" />
</padding>
<VBox.margin>
<Insets bottom="15.0" />
</VBox.margin>
</GridPane>
<HBox alignment="TOP_CENTER" spacing="10.0">
<children>
<Button fx:id="resetButton" mnemonicParsing="false" prefWidth="100.0" text="Reset" />
<HBox fx:id="submitWrapper">
<children>
<Button fx:id="submitButton" mnemonicParsing="false" prefWidth="100.0" text="Submit" />
</children>
</HBox>
</children>
</HBox>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>

View file

@ -16,7 +16,7 @@ java.util.logging.SimpleFormatter.format=%1$tF %1$tT.%1$tL | %4$-7s | %2$s | %5$
# niveaux : OFF / SEVERE / WARNING / INFO / CONFIG / FINE / FINER / FINEST / ALL
# Niveau global minimum pour les logs
.level=ALL
.level=FINE
# Niveau minimum pour les logs sur la console
java.util.logging.ConsoleHandler.level=ALL