Bump to version 4.0, finished server dialog data.
This commit is contained in:
parent
71a2cca824
commit
ac8b269fc8
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue