New controller
This commit is contained in:
parent
1e24c3aba1
commit
7ac2b05254
9 changed files with 293 additions and 23 deletions
|
@ -27,7 +27,7 @@ public class Client {
|
||||||
protected final Socket socket;
|
protected final Socket socket;
|
||||||
protected final ObjectOutputStream out;
|
protected final ObjectOutputStream out;
|
||||||
private ObjectInputStream in;
|
private ObjectInputStream in;
|
||||||
private List<Channel> channels = new ArrayList<>();
|
private final List<Channel> channels = new ArrayList<>();
|
||||||
protected boolean started = false;
|
protected boolean started = false;
|
||||||
|
|
||||||
public Client(String address, int port, String username, String password) throws IOException {
|
public Client(String address, int port, String username, String password) throws IOException {
|
||||||
|
@ -64,8 +64,7 @@ public class Client {
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendMessage(String content) {
|
public void sendMessage(String content) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
out.writeObject(new Command(CommandType.message, List.of(new Message(content, channels.get(0)))));
|
out.writeObject(new Command(CommandType.message, List.of(new Message(content, channels.get(0)))));
|
||||||
out.flush();
|
out.flush();
|
||||||
|
@ -73,8 +72,6 @@ public class Client {
|
||||||
System.err.println("Fail to send message !");
|
System.err.println("Fail to send message !");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void action(Object data) throws IOException {
|
public void action(Object data) throws IOException {
|
||||||
|
@ -100,6 +97,7 @@ public class Client {
|
||||||
private void commandLogin() throws IOException {
|
private void commandLogin() throws IOException {
|
||||||
out.writeObject(new Command(CommandType.list, null));
|
out.writeObject(new Command(CommandType.list, null));
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
||||||
out.writeObject(new Command(CommandType.join, List.of("general")));
|
out.writeObject(new Command(CommandType.join, List.of("general")));
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
@ -129,17 +127,13 @@ public class Client {
|
||||||
Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
|
Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
|
||||||
clientSendThread.start();
|
clientSendThread.start();
|
||||||
|
|
||||||
Thread clientReceiveThread = new Thread(new ClientReceive(this, socket));
|
Thread clientReceiveThread = new Thread(new ClientReceive(this));
|
||||||
clientReceiveThread.start();
|
clientReceiveThread.start();
|
||||||
|
|
||||||
started = true;
|
started = true;
|
||||||
|
|
||||||
out.writeObject(new Command(CommandType.login, List.of(username, password)));
|
out.writeObject(new Command(CommandType.login, List.of(username, password)));
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
||||||
clientSendThread.join();
|
|
||||||
socket.close();
|
|
||||||
clientReceiveThread.interrupt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectInputStream getIn() throws IOException {
|
public ObjectInputStream getIn() throws IOException {
|
||||||
|
|
|
@ -2,21 +2,19 @@ package fr.univ.lyon1.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
|
||||||
public class ClientReceive implements Runnable {
|
public class ClientReceive implements Runnable {
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private ObjectInputStream in;
|
|
||||||
private final Socket socket;
|
|
||||||
|
|
||||||
public ClientReceive(Client client, Socket socket) {
|
public ClientReceive(Client client) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.socket = socket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
ObjectInputStream in;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
in = client.getIn();
|
in = client.getIn();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -26,6 +24,7 @@ public class ClientReceive implements Runnable {
|
||||||
|
|
||||||
while(true) {
|
while(true) {
|
||||||
Object data;
|
Object data;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
data = in.readObject();
|
data = in.readObject();
|
||||||
} catch (ClassNotFoundException|IOException e) {
|
} catch (ClassNotFoundException|IOException e) {
|
||||||
|
@ -33,13 +32,16 @@ public class ClientReceive implements Runnable {
|
||||||
System.err.println("Connexion closed");
|
System.err.println("Connexion closed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.err.println("Fail to read object !");
|
System.err.println("Fail to read object !");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(1000);
|
Thread.currentThread().join(1000);
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ public class ClientGUI extends Client {
|
||||||
if (started)
|
if (started)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Thread clientReceiveThread = new Thread(new ClientReceive(this, super.socket));
|
Thread clientReceiveThread = new Thread(new ClientReceive(this));
|
||||||
clientReceiveThread.start();
|
clientReceiveThread.start();
|
||||||
|
|
||||||
out.writeObject(new Command(CommandType.login, List.of(this.username, this.password))); // ToDo: Setup login
|
out.writeObject(new Command(CommandType.login, List.of(this.username, this.password))); // ToDo: Setup login
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package fr.univ.lyon1.gui;
|
package fr.univ.lyon1.gui;
|
||||||
|
|
||||||
import fr.univ.lyon1.gui.handlers.MainHandler;
|
import fr.univ.lyon1.gui.handlers.ApplicationHandler;
|
||||||
import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler;
|
import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler;
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
@ -12,7 +12,7 @@ public class MainGui extends Application {
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) {
|
public void start(Stage stage) {
|
||||||
try {
|
try {
|
||||||
new MainHandler().launch(stage);
|
new ApplicationHandler().launch(stage);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
|
|
||||||
|
|
221
src/fr/univ/lyon1/gui/controller/ApplicationController.java
Normal file
221
src/fr/univ/lyon1/gui/controller/ApplicationController.java
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
package fr.univ.lyon1.gui.controller;
|
||||||
|
|
||||||
|
import fr.univ.lyon1.common.Channel;
|
||||||
|
import fr.univ.lyon1.common.ChatSSL;
|
||||||
|
import fr.univ.lyon1.common.Message;
|
||||||
|
import fr.univ.lyon1.common.ServerConfiguration;
|
||||||
|
import fr.univ.lyon1.common.command.Command;
|
||||||
|
import fr.univ.lyon1.common.command.CommandType;
|
||||||
|
import fr.univ.lyon1.common.exception.ChatException;
|
||||||
|
import fr.univ.lyon1.common.exception.UnknownCommand;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.layout.VBox;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.scene.text.Text;
|
||||||
|
import javafx.scene.text.TextFlow;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import javax.net.SocketFactory;
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLParameters;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ApplicationController {
|
||||||
|
@NotNull
|
||||||
|
private final List<Channel> channels = new ArrayList<>();
|
||||||
|
@Nullable
|
||||||
|
private Channel currentChannel = null;
|
||||||
|
|
||||||
|
private boolean isRunning = true;
|
||||||
|
@NotNull
|
||||||
|
private final Socket socket;
|
||||||
|
@NotNull
|
||||||
|
private final ObjectOutputStream objectOutputStream;
|
||||||
|
@NotNull
|
||||||
|
private final ObjectInputStream objectInputStream;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
public TextArea textSendArea;
|
||||||
|
@FXML
|
||||||
|
public TextFlow textReceiveArea;
|
||||||
|
@FXML
|
||||||
|
public VBox vboxChannelsList;
|
||||||
|
|
||||||
|
public ApplicationController() throws IOException {
|
||||||
|
System.out.println("Loading configuration...");
|
||||||
|
@NotNull
|
||||||
|
final ServerConfiguration serverConfiguration = ServerConfiguration.load();
|
||||||
|
|
||||||
|
System.out.println("Init socket...");
|
||||||
|
this.socket = this.initSSLSocket(serverConfiguration.getAddress(), serverConfiguration.getPort());
|
||||||
|
this.objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
|
||||||
|
this.objectInputStream = new ObjectInputStream(socket.getInputStream());
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
final Thread receiveObjectThread = new Thread(() -> {
|
||||||
|
while (this.isRunning) {
|
||||||
|
try {
|
||||||
|
@Nullable
|
||||||
|
final Object object = this.objectInputStream.readObject();
|
||||||
|
|
||||||
|
if (object != null) {
|
||||||
|
if (object instanceof Command) {
|
||||||
|
switch (((Command) object).getType()) {
|
||||||
|
// If client receive login type message
|
||||||
|
case login -> {
|
||||||
|
// Request all list of users
|
||||||
|
this.sendObject(new Command(CommandType.list, null));
|
||||||
|
// TODO: List all channels available
|
||||||
|
// Join a channel
|
||||||
|
this.sendObject(new Command(CommandType.join, List.of("general")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If client receive a message type
|
||||||
|
case message -> {
|
||||||
|
@NotNull
|
||||||
|
final Message message = (Message) ((Command) object).getArgs().get(0);
|
||||||
|
System.out.println("Message received : " + message.toString());
|
||||||
|
|
||||||
|
// If same channel
|
||||||
|
if (this.currentChannel != null && message.getChannel().getUUID().equals(this.currentChannel.getUUID())) {
|
||||||
|
Platform.runLater(() -> this.textReceiveArea.getChildren().add(new Text("@" + message.getSender().getUsername() + ": " + message.getContent())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If client receive all users
|
||||||
|
case list -> {
|
||||||
|
System.out.println("Connected users : " + Arrays.toString(((Command) object).getArgs().toArray()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If client receive a join type message
|
||||||
|
case join -> {
|
||||||
|
@NotNull
|
||||||
|
final Channel channel = (Channel) ((Command) object).getArgs().get(0);
|
||||||
|
boolean ifChannelExists = this.channels.stream().anyMatch(fChannel -> fChannel.getName().equalsIgnoreCase(channel.getName()));
|
||||||
|
System.out.println("Channel exists : " + ifChannelExists);
|
||||||
|
this.currentChannel = channel;
|
||||||
|
this.channels.add(channel);
|
||||||
|
System.out.println("Successfully connected to : " + this.currentChannel.toString());
|
||||||
|
|
||||||
|
if (!ifChannelExists) {
|
||||||
|
@NotNull
|
||||||
|
final Text text = new Text("- #" + channel.getName());
|
||||||
|
text.setFill(Color.RED);
|
||||||
|
|
||||||
|
text.setOnMousePressed(event -> {
|
||||||
|
System.out.println("Selected channel : #" + channel.getName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.sendObject(new Command(CommandType.join, List.of(channel.getName())));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Platform.runLater(() -> this.vboxChannelsList.getChildren().add(text));
|
||||||
|
} else {
|
||||||
|
this.vboxChannelsList.getChildren().stream().filter(node -> node instanceof Text).forEach(txt -> ((Text) txt).setFill(Color.BLACK));
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
final Text text = (Text) this.vboxChannelsList.getChildren().stream().filter(node -> node instanceof Text && ((Text) node).getText().equalsIgnoreCase("- #" + channel.getName())).toList().get(0);
|
||||||
|
text.setFill(Color.RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (object instanceof ChatException) {
|
||||||
|
((ChatException) object).printStackTrace();
|
||||||
|
} else
|
||||||
|
this.sendObject(new UnknownCommand());
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
this.closeSocket();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.out.println("Can not close connection");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
if (e instanceof SocketException) {
|
||||||
|
try {
|
||||||
|
this.closeSocket();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
System.out.println("Can not close connection");
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
receiveObjectThread.start();
|
||||||
|
|
||||||
|
System.out.println("Login...");
|
||||||
|
this.sendObject(new Command(CommandType.login, List.of(serverConfiguration.getPseudo(), serverConfiguration.getPassword())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeSocket() throws IOException {
|
||||||
|
this.isRunning = false;
|
||||||
|
this.objectOutputStream.close();
|
||||||
|
this.objectInputStream.close();
|
||||||
|
this.socket.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Socket initSSLSocket(@NotNull String address, int port) throws IOException {
|
||||||
|
SSLContext ctx = ChatSSL.getSSLContext();
|
||||||
|
SocketFactory factory = ctx.getSocketFactory();
|
||||||
|
Socket connection = factory.createSocket(address, port);
|
||||||
|
((SSLSocket) connection).setEnabledProtocols(new String[] {ChatSSL.tlsVersion});
|
||||||
|
SSLParameters sslParams = new SSLParameters();
|
||||||
|
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
|
||||||
|
((SSLSocket) connection).setSSLParameters(sslParams);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendObject(@NotNull Object object) throws IOException {
|
||||||
|
this.objectOutputStream.writeObject(object);
|
||||||
|
this.objectOutputStream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void keyPressedOnTextSendArea(KeyEvent keyEvent) {
|
||||||
|
if (keyEvent.getCode() == KeyCode.ENTER) {
|
||||||
|
this.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send() {
|
||||||
|
@NotNull
|
||||||
|
final String textToSend = this.textSendArea.getText();
|
||||||
|
this.clear();
|
||||||
|
System.out.print(">> Send : " + textToSend);
|
||||||
|
Platform.runLater(() -> this.textReceiveArea.getChildren().add(new Text("*>> " + textToSend)));
|
||||||
|
|
||||||
|
if (this.currentChannel != null) {
|
||||||
|
try {
|
||||||
|
this.sendObject(new Command(CommandType.message, List.of(new Message(textToSend, this.currentChannel))));
|
||||||
|
} catch (IOException e) {
|
||||||
|
System.out.println("Can not send message to server : " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.textSendArea.setText("");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package fr.univ.lyon1.gui.controller;
|
package fr.univ.lyon1.gui.controller;
|
||||||
|
|
||||||
import fr.univ.lyon1.common.ServerConfiguration;
|
import fr.univ.lyon1.common.ServerConfiguration;
|
||||||
import fr.univ.lyon1.gui.handlers.MainHandler;
|
import fr.univ.lyon1.gui.handlers.ApplicationHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.control.TextField;
|
import javafx.scene.control.TextField;
|
||||||
|
@ -58,10 +58,12 @@ public class ConnectGuiController {
|
||||||
System.out.println("File saved, next step...");
|
System.out.println("File saved, next step...");
|
||||||
|
|
||||||
System.out.println("Get scene...");
|
System.out.println("Get scene...");
|
||||||
|
|
||||||
|
// Change scene
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
final Stage stage = (Stage) this.connectButton.getScene().getWindow();
|
final Stage stage = (Stage) this.connectButton.getScene().getWindow();
|
||||||
System.out.println("Scene : " + stage.toString());
|
new ApplicationHandler().launch(stage);
|
||||||
new MainHandler().launch(stage);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
|
|
||||||
|
|
18
src/fr/univ/lyon1/gui/handlers/ApplicationHandler.java
Normal file
18
src/fr/univ/lyon1/gui/handlers/ApplicationHandler.java
Normal 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 ApplicationHandler implements Handler {
|
||||||
|
@Override
|
||||||
|
public void launch(Stage stage) throws IOException {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("message_gui.fxml"));
|
||||||
|
Scene scene = new Scene(fxmlLoader.load(), 600, 400);
|
||||||
|
stage.setTitle("Chat client");
|
||||||
|
stage.setScene(scene);
|
||||||
|
stage.show();
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ public class ServerConfigurationHandler implements Handler {
|
||||||
@Override
|
@Override
|
||||||
public void launch(Stage stage) throws IOException {
|
public void launch(Stage stage) throws IOException {
|
||||||
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("connect_gui.fxml"));
|
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("connect_gui.fxml"));
|
||||||
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
|
Scene scene = new Scene(fxmlLoader.load(), 640, 480);
|
||||||
stage.setTitle("Configuration du serveur");
|
stage.setTitle("Configuration du serveur");
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|
33
src/main/resources/message_gui.fxml
Normal file
33
src/main/resources/message_gui.fxml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<?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/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univ.lyon1.gui.controller.ApplicationController">
|
||||||
|
<SplitPane dividerPositions="0.29797979797979796" prefHeight="542.0" prefWidth="600.0">
|
||||||
|
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||||
|
<VBox prefHeight="400.0" prefWidth="175.0">
|
||||||
|
<Label alignment="CENTER" contentDisplay="CENTER" prefHeight="31.0" prefWidth="175.0" text="Channels" textAlignment="CENTER" />
|
||||||
|
<VBox prefHeight="371.0" prefWidth="175.0" fx:id="vboxChannelsList" />
|
||||||
|
</VBox>
|
||||||
|
</AnchorPane>
|
||||||
|
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
|
||||||
|
<VBox prefHeight="398.0" prefWidth="417.0">
|
||||||
|
<ScrollPane prefHeight="280.0" prefWidth="417.0">
|
||||||
|
<TextFlow fx:id="textReceiveArea" prefHeight="276.0" prefWidth="415.0" />
|
||||||
|
</ScrollPane>
|
||||||
|
<Separator prefHeight="25.0" prefWidth="417.0" />
|
||||||
|
<HBox prefHeight="100.0" prefWidth="200.0">
|
||||||
|
<TextArea fx:id="textSendArea" onKeyPressed="#keyPressedOnTextSendArea" prefHeight="100.0" prefWidth="300.0" />
|
||||||
|
<StackPane prefHeight="98.0" prefWidth="29.0" />
|
||||||
|
<VBox prefHeight="200.0" prefWidth="100.0">
|
||||||
|
<Button mnemonicParsing="false" onAction="#send" prefHeight="40.0" prefWidth="128.0" text="Envoyer" />
|
||||||
|
<StackPane prefHeight="20.0" prefWidth="100.0" />
|
||||||
|
<Button layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#clear" prefHeight="40.0" prefWidth="207.0" text="Nettoyer" />
|
||||||
|
</VBox>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
||||||
|
</AnchorPane>
|
||||||
|
</SplitPane>
|
||||||
|
</VBox>
|
Reference in a new issue