package com.esotericsoftware.kryonet.examples.chat;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import javax.swing.DefaultListModel;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import com.esotericsoftware.kryonet.examples.chat.Network.ChatMessage;
import com.esotericsoftware.kryonet.examples.chat.Network.RegisterName;
import com.esotericsoftware.kryonet.examples.chat.Network.UpdateNames;
import com.esotericsoftware.minlog.Log;
public class ChatClient {
ChatFrame chatFrame;
Client client;
public ChatClient () {
client = new Client();
client.start();
// For consistency, the classes to be sent over the network are
// registered by the same method for both the client and server.
Network.register(client);
client.addListener(new Listener() {
public void connected (Connection connection) {
RegisterName registerName = new RegisterName();
registerName.name = "meow";
client.sendTCP(registerName);
}
public void received (Connection connection, Object object) {
if (object instanceof UpdateNames) {
UpdateNames updateNames = (UpdateNames)object;
chatFrame.setNames(updateNames.names);
return;
}
if (object instanceof ChatMessage) {
ChatMessage chatMessage = (ChatMessage)object;
chatFrame.addMessage(chatMessage.text);
return;
}
}
public void disconnected (Connection connection) {
EventQueue.invokeLater(new Runnable() {
public void run () {
// Closing the frame calls the close listener which will stop the client's update thread.
chatFrame.dispose();
}
});
}
});
// Request the host from the user.
String input = (String)JOptionPane.showInputDialog(null, "Host:", "Connect to chat server", JOptionPane.QUESTION_MESSAGE,
null, null, "localhost");
if (input == null || input.trim().length() == 0) System.exit(1);
final String host = input.trim();
// Request the user's name.
input = (String)JOptionPane.showInputDialog(null, "Name:", "Connect to chat server", JOptionPane.QUESTION_MESSAGE, null,
null, "Test");
if (input == null || input.trim().length() == 0) System.exit(1);
final String name = input.trim();
// All the ugly Swing stuff is hidden in ChatFrame so it doesn't clutter the KryoNet example code.
chatFrame = new ChatFrame(host);
// This listener is called when the send button is clicked.
chatFrame.setSendListener(new Runnable() {
public void run () {
ChatMessage chatMessage = new ChatMessage();
chatMessage.text = chatFrame.getSendText();
client.sendTCP(chatMessage);
}
});
// This listener is called when the chat window is closed.
chatFrame.setCloseListener(new Runnable() {
public void run () {
client.stop();
}
});
chatFrame.setVisible(true);
// We'll do the connect on a new thread so the ChatFrame can show a progress bar.
// Connecting to localhost is usually so fast you won't see the progress bar.
new Thread("Connect") {
public void run () {
try {
client.connect(5000, host, Network.port);
// Server communication after connection can go here, or in Listener#connected().
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
}
}.start();
}
static private class ChatFrame extends JFrame {
CardLayout cardLayout;
JProgressBar progressBar;
JList messageList;
JTextField sendText;
JButton sendButton;
JList nameList;
public ChatFrame (String host) {
super("Chat Client");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(640, 200);
setLocationRelativeTo(null);
Container contentPane = getContentPane();
cardLayout = new CardLayout();
contentPane.setLayout(cardLayout);
{
JPanel panel = new JPanel(new BorderLayout());
contentPane.add(panel, "progress");
panel.add(new JLabel("Connecting to " + host + "..."));
{
panel.add(progressBar = new JProgressBar(), BorderLayout.SOUTH);
progressBar.setIndeterminate(true);
}
}
{
JPanel panel = new JPanel(new BorderLayout());
contentPane.add(panel, "chat");
{
JPanel topPanel = new JPanel(new GridLayout(1, 2));
panel.add(topPanel);
{
topPanel.add(new JScrollPane(messageList = new JList()));
messageList.setModel(new DefaultListModel());
}
{
topPanel.add(new JScrollPane(nameList = new JList()));
nameList.setModel(new DefaultListModel());
}
DefaultListSelectionModel disableSelections = new DefaultListSelectionModel() {
public void setSelectionInterval (int index0, int index1) {
}
};
messageList.setSelectionModel(disableSelections);
nameList.setSelectionModel(disableSelections);
}
{
JPanel bottomPanel = new JPanel(new GridBagLayout());
panel.add(bottomPanel, BorderLayout.SOUTH);
bottomPanel.add(sendText = new JTextField(), new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER,
GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
bottomPanel.add(sendButton = new JButton("Send"), new GridBagConstraints(1, 0, 1, 1, 0, 0,
GridBagConstraints.CENTER, 0, new Insets(0, 0, 0, 0), 0, 0));
}
}
sendText.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent e) {
sendButton.doClick();
}
});
}
public void setSendListener (final Runnable listener) {
sendButton.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent evt) {
if (getSendText().length() == 0) return;
listener.run();
sendText.setText("");
sendText.requestFocus();
}
});
}
public void setCloseListener (final Runnable listener) {
addWindowListener(new WindowAdapter() {
public void windowClosed (WindowEvent evt) {
listener.run();
}
public void windowActivated (WindowEvent evt) {
sendText.requestFocus();
}
});
}
public String getSendText () {
return sendText.getText().trim();
}
public void setNames (final String[] names) {
// This listener is run on the client's update thread, which was started by client.start().
// We must be careful to only interact with Swing components on the Swing event thread.
EventQueue.invokeLater(new Runnable() {
public void run () {
cardLayout.show(getContentPane(), "chat");
DefaultListModel model = (DefaultListModel)nameList.getModel();
model.removeAllElements();
for (String name : names)
model.addElement(name);
}
});
}
public void addMessage (final String message) {
EventQueue.invokeLater(new Runnable() {
public void run () {
DefaultListModel model = (DefaultListModel)messageList.getModel();
model.addElement(message);
messageList.ensureIndexIsVisible(model.size() - 1);
}
});
}
}
public static void main (String[] args) {
Log.set(Log.LEVEL_DEBUG);
new ChatClient();
}
}