package netgame.chat; import javafx.application.Application; import javafx.application.Platform; import javafx.stage.Stage; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.control.TextArea; import javafx.scene.control.TextInputDialog; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; import javafx.geometry.Insets; import java.io.IOException; import java.util.Optional; import netgame.common.*; /* This class is a demo of the "netgame" package. It's not exactly a game, but * it uses the netgame infrastructure of Hub + Clients to send and receive * messages in the chat room. The chat room server is just a netgame Hub. * A ChatRoomWindow has a subclass that represents a Client for that Hub. * You must run ChatRoomServer on a known computer. Several copies of * ChatRoomWindow can then connect to that server. */ /** * This class represents a client for a "chat room" application. The chat * room is hosted by a server running on some computer. The user of this * program must know the host name (or IP address) of the computer that * hosts the chat room. When this program is run, it asks for that * information. Then, it opens a window that has an input box where the * user can enter messages to be sent to the chat room. The message is * sent when the user presses return in the input box or when the * user clicks a Send button. There is also a text area that shows * a transcript of all messages from participants in the chat room. *

Participants in the chat room are represented only by ID numbers * that are assigned to them by the server when they connect. */ public class ChatRoomWindow extends Application { public static void main(String[] args) { launch(args); } //---------------------------------------------------------------------------- private final static int PORT = 37829; // The ChatRoom port number; can't be // changed here unless the ChatRoomServer // program is also changed. private TextField messageInput; // For entering messages to be sent to the chat room. private Button sendButton; // Sends the contents of the messageInput. private Button quitButton; // Leaves the chat room cleanly, by sending a DisconnectMessage. private TextArea transcript; // Contains all messages sent by chat room participant, as well // as a few additional status messages, // such as when a new user arrives. private ChatClient connection; // Represents the connection to the Hub; used to send messages; // also receives and processes messages from the Hub. private volatile boolean connected; // This is true while the client is connected to the hub. /** * Gets the host name (or IP address) of the chat room server from the * user and then opens the main window. The program ends when the user * closes the window. */ public void start( Stage stage ) { TextInputDialog question = new TextInputDialog(); question.setHeaderText("Enter the host name of the\ncomputer that hosts the chat room."); question.setContentText("Host Name:"); Optional response = question.showAndWait(); if ( ! response.isPresent() ) System.exit(0); String host = response.get().trim(); if (host == null || host.trim().length() == 0) System.exit(0); transcript = new TextArea(); transcript.setPrefRowCount(30); transcript.setPrefColumnCount(60); transcript.setWrapText(true); transcript.setEditable(false); sendButton = new Button("send"); quitButton = new Button("quit"); messageInput = new TextField(); messageInput.setPrefColumnCount(40); sendButton.setOnAction( e -> doSend() ); quitButton.setOnAction( e -> doQuit() ); sendButton.setDefaultButton(true); sendButton.setDisable(true); messageInput.setEditable(false); messageInput.setDisable(true); HBox bottom = new HBox(8, new Label("YOU SAY:"), messageInput, sendButton, quitButton); HBox.setHgrow(messageInput, Priority.ALWAYS); HBox.setMargin(quitButton, new Insets(0,0,0,50)); bottom.setPadding(new Insets(8)); bottom.setStyle("-fx-border-color: black; -fx-border-width:2px"); BorderPane root = new BorderPane(transcript); root.setBottom(bottom); stage.setScene( new Scene(root) ); stage.setTitle("Networked Chat"); stage.setResizable(false); stage.setOnHidden( e -> doQuit() ); stage.show(); new Thread() { // This is a thread that opens the connection to the server. Since // that operation can block, it's not done directly in the constructor. // Once the connection is established, the user interface elements are // enabled so the user can send messages. The Thread dies after // the connection is established or after an error occurs. public void run() { try { addToTranscript("Connecting to " + host + " ..."); connection = new ChatClient(host); connected = true; Platform.runLater( () -> { messageInput.setEditable(true); messageInput.setDisable(false); sendButton.setDisable(false); messageInput.requestFocus(); }); } catch (IOException e) { addToTranscript("Connection attempt failed."); addToTranscript("Error: " + e); } } }.start(); } /** * A ChatClient connects to the Hub and is used to send messages to * and receive messages from a Hub. Messages received from the * Hub will be of type ForwardedMessage and will contain the * ID number of the sender and the string that was sent by * that user. */ private class ChatClient extends Client { /** * Opens a connection to the chat room server on a specified computer. */ ChatClient(String host) throws IOException { super(host, PORT); } /** * Responds when a message is received from the server. It should be * a ForwardedMessage representing something that one of the participants * in the chat room is saying. The message is simply added to the * transcript, along with the ID number of the sender. */ protected void messageReceived(Object message) { if (message instanceof ForwardedMessage) { // (no other message types are expected) ForwardedMessage bm = (ForwardedMessage)message; addToTranscript("#" + bm.senderID + " SAYS: " + bm.message); } } /** * Called when the connection to the client is shut down because of some * error message. (This will happen if the server program is terminated.) */ protected void connectionClosedByError(String message) { addToTranscript("Sorry, communication has shut down due to an error:\n " + message); Platform.runLater( () -> { sendButton.setDisable(true); messageInput.setEditable(false); messageInput.setDisable(true); messageInput.setText(""); }); connected = false; connection = null; } /** * Posts a message to the transcript when someone joins the chat room. */ protected void playerConnected(int newPlayerID) { addToTranscript("Someone new has joined the chat room, with ID number " + newPlayerID); } /** * Posts a message to the transcript when someone leaves the chat room. */ protected void playerDisconnected(int departingPlayerID) { addToTranscript("The person with ID number " + departingPlayerID + " has left the chat room"); } } // end nested class ChatClient /** * Adds a string to the transcript area, followed by a blank line. */ private void addToTranscript(String message) { Platform.runLater( () -> transcript.appendText(message + "\n\n") ); } /** * Called when the user clicks the Quit button or closes * the window by clicking its close box. Called from the * application thread. */ private void doQuit() { if (connected) connection.disconnect(); // Sends a DisconnectMessage to the server. try { Thread.sleep(500); // Time for DisconnectMessage to actually be sent. } catch (InterruptedException e) { } System.exit(0); } /** * Send the string entered by the user as a message * to the Hub, using the ChatClient that handles communication * for this ChatRoomWindow. Note that the string is not added * to the transcript here. It will get added after the Hub * receives the message and broadcasts it to all clients, * including this one. Called from the application thread. */ private void doSend() { String message = messageInput.getText(); if (message.trim().length() == 0) return; connection.send(message); messageInput.selectAll(); messageInput.requestFocus(); } } // end class ChatRoomWindow