Bump to version 4.0, finished server dialog data.

This commit is contained in:
Andrew Lalis 2021-06-24 10:50:23 +02:00
parent 71a2cca824
commit ac8b269fc8
9 changed files with 191 additions and 18 deletions

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ace-of-shades</artifactId> <artifactId>ace-of-shades</artifactId>
<groupId>nl.andrewlalis</groupId> <groupId>nl.andrewlalis</groupId>
<version>3.1</version> <version>4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,9 +1,7 @@
package nl.andrewlalis.aos_client.launcher; package nl.andrewlalis.aos_client.launcher;
import nl.andrewlalis.aos_client.Client; import nl.andrewlalis.aos_client.Client;
import nl.andrewlalis.aos_client.launcher.servers.ServerInfo; import nl.andrewlalis.aos_client.launcher.servers.*;
import nl.andrewlalis.aos_client.launcher.servers.ServerInfoCellRenderer;
import nl.andrewlalis.aos_client.launcher.servers.ServerInfoListModel;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
@ -12,6 +10,7 @@ import java.awt.event.MouseEvent;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -22,7 +21,9 @@ import java.util.regex.Pattern;
* the menu that the user interacts with before joining a game. * the menu that the user interacts with before joining a game.
*/ */
public class Launcher extends JFrame { public class Launcher extends JFrame {
private static final Pattern addressPattern = Pattern.compile("(.+):(\\d+)"); public static final Pattern addressPattern = Pattern.compile("(.+):(\\d+)");
public static final Path DATA_DIR = Path.of(System.getProperty("user.home"), "ace-of-shades");
public static final Pattern usernamePattern = Pattern.compile("[a-zA-Z0-9_-]+");
public Launcher() throws HeadlessException { public Launcher() throws HeadlessException {
super("Ace of Shades - Launcher"); super("Ace of Shades - Launcher");
@ -36,9 +37,6 @@ public class Launcher extends JFrame {
private Container buildContent() { private Container buildContent() {
JTabbedPane mainPanel = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT); JTabbedPane mainPanel = new JTabbedPane(SwingConstants.TOP, JTabbedPane.SCROLL_TAB_LAYOUT);
mainPanel.addTab("Servers", null, this.getServersPanel(), "View a list of available servers."); mainPanel.addTab("Servers", null, this.getServersPanel(), "View a list of available servers.");
//
// JPanel settingsPanel = new JPanel();
// mainPanel.addTab("Settings", null, settingsPanel, "Change game settings.");
return mainPanel; return mainPanel;
} }
@ -47,8 +45,6 @@ public class Launcher extends JFrame {
JPanel panel = new JPanel(new BorderLayout()); JPanel panel = new JPanel(new BorderLayout());
ServerInfoListModel listModel = new ServerInfoListModel(); ServerInfoListModel listModel = new ServerInfoListModel();
listModel.add(new ServerInfo("one", "localhost:8035", "andrew"));
listModel.add(new ServerInfo("two", "localhost:25565", null));
JList<ServerInfo> serversList = new JList<>(listModel); JList<ServerInfo> serversList = new JList<>(listModel);
serversList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); serversList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
serversList.setCellRenderer(new ServerInfoCellRenderer()); serversList.setCellRenderer(new ServerInfoCellRenderer());
@ -68,8 +64,15 @@ public class Launcher extends JFrame {
menu.add(connectItem); menu.add(connectItem);
JMenuItem editItem = new JMenuItem("Edit"); JMenuItem editItem = new JMenuItem("Edit");
editItem.addActionListener(a -> { editItem.addActionListener(a -> {
// TODO: Open edit dialog. EditServerDialog dialog = new EditServerDialog((Frame) SwingUtilities.getWindowAncestor(panel), server);
dialog.setVisible(true);
ServerInfo editedInfo = dialog.getServerInfo();
if (editedInfo != null) {
server.setName(editedInfo.getName());
server.setHost(editedInfo.getHost());
server.setUsername(editedInfo.getUsername());
listModel.serverEdited(); listModel.serverEdited();
}
}); });
menu.add(editItem); menu.add(editItem);
JMenuItem removeItem = new JMenuItem("Remove"); JMenuItem removeItem = new JMenuItem("Remove");
@ -94,7 +97,12 @@ public class Launcher extends JFrame {
JButton addServerButton = new JButton("Add Server"); JButton addServerButton = new JButton("Add Server");
addServerButton.setToolTipText("Add a new server to the list."); addServerButton.setToolTipText("Add a new server to the list.");
addServerButton.addActionListener(e -> { addServerButton.addActionListener(e -> {
// TODO: Add server dialog. AddServerDialog dialog = new AddServerDialog(this);
dialog.setVisible(true);
ServerInfo server = dialog.getServerInfo();
if (server != null) {
listModel.add(server);
}
}); });
buttonPanel.add(addServerButton); buttonPanel.add(addServerButton);
JButton directConnectButton = new JButton("Direct Connect"); JButton directConnectButton = new JButton("Direct Connect");

View File

@ -0,0 +1,113 @@
package nl.andrewlalis.aos_client.launcher.servers;
import nl.andrewlalis.aos_client.launcher.Launcher;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class AddServerDialog extends JDialog {
protected JTextField serverNameField;
protected JTextField serverAddressField;
protected JTextField usernameField;
private ServerInfo serverInfo;
public AddServerDialog(Frame owner) {
super(owner, true);
this.setTitle("Add Server");
this.setContentPane(this.getContent());
this.pack();
this.setLocationRelativeTo(owner);
}
public ServerInfo getServerInfo() {
return this.serverInfo;
}
private Container getContent() {
JPanel container = new JPanel(new BorderLayout());
JPanel inputPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.gridx = 0;
c.gridy = 0;
inputPanel.add(new JLabel("Name"), c);
serverNameField = new JTextField(20);
c.gridx++;
inputPanel.add(serverNameField, c);
c.gridx = 0;
c.gridy++;
inputPanel.add(new JLabel("Address"), c);
serverAddressField = new JTextField(20);
c.gridx++;
inputPanel.add(serverAddressField, c);
c.gridy++;
c.gridx = 0;
inputPanel.add(new JLabel("Username"), c);
usernameField = new JTextField(20);
c.gridx++;
inputPanel.add(usernameField, c);
container.add(inputPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(e -> {
this.serverInfo = null;
this.dispose();
});
JButton okButton = new JButton("Ok");
okButton.addActionListener(e -> {
var messages = this.validateInputs();
if (!messages.isEmpty()) {
String msg = String.join("\n", messages);
JOptionPane.showMessageDialog(this, "The information you entered is not valid:\n" + msg, "Invalid Server Data", JOptionPane.WARNING_MESSAGE);
} else {
String username = this.usernameField.getText();
if (username.isBlank()) {
username = null;
}
this.serverInfo = new ServerInfo(this.serverNameField.getText(), this.serverAddressField.getText(), username);
this.dispose();
}
});
buttonPanel.add(okButton);
buttonPanel.add(cancelButton);
container.add(buttonPanel, BorderLayout.SOUTH);
return container;
}
private List<String> validateInputs() {
String name = this.serverNameField.getText();
String address = this.serverAddressField.getText();
String username = this.usernameField.getText();
List<String> messages = new ArrayList<>();
if (name == null || name.isBlank()) {
messages.add("Server name cannot be blank.");
}
if (name != null && name.length() > 32) {
messages.add("Server name is too long.");
}
if (address == null || address.isBlank()) {
messages.add("Server address cannot be blank.");
}
if (address != null && !Launcher.addressPattern.matcher(address).matches()) {
messages.add("Server address is not properly formatted as HOST:PORT.");
}
if (username != null && !username.isBlank() && username.length() > 16) {
messages.add("Username is too long. Maximum of 16 characters.");
}
if (username != null && !Launcher.usernamePattern.matcher(username).matches()) {
messages.add("Username should contain only letters, numbers, underscores, and hyphens.");
}
return messages;
}
}

View File

@ -0,0 +1,13 @@
package nl.andrewlalis.aos_client.launcher.servers;
import java.awt.*;
public class EditServerDialog extends AddServerDialog {
public EditServerDialog(Frame owner, ServerInfo server) {
super(owner);
this.setTitle("Edit Server - " + server.getName());
this.serverNameField.setText(server.getName());
this.serverAddressField.setText(server.getHost());
this.usernameField.setText(server.getUsername());
}
}

View File

@ -1,8 +1,9 @@
package nl.andrewlalis.aos_client.launcher.servers; package nl.andrewlalis.aos_client.launcher.servers;
import java.io.Serializable;
import java.util.Objects; import java.util.Objects;
public class ServerInfo implements Comparable<ServerInfo> { public class ServerInfo implements Comparable<ServerInfo>, Serializable {
private String name; private String name;
private String host; private String host;
private String username; private String username;

View File

@ -1,15 +1,39 @@
package nl.andrewlalis.aos_client.launcher.servers; package nl.andrewlalis.aos_client.launcher.servers;
import nl.andrewlalis.aos_client.launcher.Launcher;
import javax.swing.*; import javax.swing.*;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
/**
* Model which represents the list of servers. This model is backed by a file
* containing the serialized list, which is updated any time a server is added,
* edited, or removed.
*/
public class ServerInfoListModel extends AbstractListModel<ServerInfo> { public class ServerInfoListModel extends AbstractListModel<ServerInfo> {
public static final Path SERVERS_FILE = Launcher.DATA_DIR.resolve("servers.dat");
private final List<ServerInfo> servers; private final List<ServerInfo> servers;
@SuppressWarnings("unchecked")
public ServerInfoListModel() { public ServerInfoListModel() {
this.servers = new ArrayList<>(); List<ServerInfo> list = null;
if (Files.exists(SERVERS_FILE)) {
try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(SERVERS_FILE))) {
list = (ArrayList<ServerInfo>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
if (list == null) list = new ArrayList<>();
servers = list;
} }
public void add(ServerInfo server) { public void add(ServerInfo server) {
@ -17,6 +41,7 @@ public class ServerInfoListModel extends AbstractListModel<ServerInfo> {
this.servers.add(server); this.servers.add(server);
this.servers.sort(Comparator.naturalOrder()); this.servers.sort(Comparator.naturalOrder());
this.fireContentsChanged(this, 0, this.getSize()); this.fireContentsChanged(this, 0, this.getSize());
this.save();
} }
public void remove(ServerInfo server) { public void remove(ServerInfo server) {
@ -24,10 +49,12 @@ public class ServerInfoListModel extends AbstractListModel<ServerInfo> {
if (index == -1) return; if (index == -1) return;
this.servers.remove(index); this.servers.remove(index);
this.fireIntervalRemoved(this, index, index); this.fireIntervalRemoved(this, index, index);
this.save();
} }
public void serverEdited() { public void serverEdited() {
this.fireContentsChanged(this, 0, this.getSize()); this.fireContentsChanged(this, 0, this.getSize());
this.save();
} }
@Override @Override
@ -39,4 +66,15 @@ public class ServerInfoListModel extends AbstractListModel<ServerInfo> {
public ServerInfo getElementAt(int index) { public ServerInfo getElementAt(int index) {
return this.servers.get(index); return this.servers.get(index);
} }
private void save() {
try {
Files.createDirectories(SERVERS_FILE.getParent());
ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(SERVERS_FILE));
oos.writeObject(this.servers);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ace-of-shades</artifactId> <artifactId>ace-of-shades</artifactId>
<groupId>nl.andrewlalis</groupId> <groupId>nl.andrewlalis</groupId>
<version>3.1</version> <version>4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -7,7 +7,7 @@
<groupId>nl.andrewlalis</groupId> <groupId>nl.andrewlalis</groupId>
<artifactId>ace-of-shades</artifactId> <artifactId>ace-of-shades</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>3.1</version> <version>4.0</version>
<modules> <modules>
<module>server</module> <module>server</module>
<module>client</module> <module>client</module>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>ace-of-shades</artifactId> <artifactId>ace-of-shades</artifactId>
<groupId>nl.andrewlalis</groupId> <groupId>nl.andrewlalis</groupId>
<version>3.1</version> <version>4.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>