diff options
| author | 2020-06-05 21:46:12 +0200 | |
|---|---|---|
| committer | 2020-06-05 21:46:12 +0200 | |
| commit | 1c3533305c7283d15cc1184954a5a1868b815aba (patch) | |
| tree | 0353dacc33cf83a65fdc661bc10c8d4919813627 /enigma-swing/src/main/java/cuchaz | |
| parent | Fix 'Save Mappings' entry missing from the menu and ctrl+s not working (diff) | |
| parent | Bump version (diff) | |
| download | enigma-1c3533305c7283d15cc1184954a5a1868b815aba.tar.gz enigma-1c3533305c7283d15cc1184954a5a1868b815aba.tar.xz enigma-1c3533305c7283d15cc1184954a5a1868b815aba.zip | |
Merge pull request #254 from 2xsaiko/patch-1
Improve connect/create server dialogs
Diffstat (limited to 'enigma-swing/src/main/java/cuchaz')
4 files changed, 234 insertions, 90 deletions
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java new file mode 100644 index 00000000..b179eac1 --- /dev/null +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/AbstractDialog.java | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | package cuchaz.enigma.gui.dialog; | ||
| 2 | |||
| 3 | import java.awt.*; | ||
| 4 | import java.util.List; | ||
| 5 | |||
| 6 | import javax.swing.JButton; | ||
| 7 | import javax.swing.JDialog; | ||
| 8 | import javax.swing.JLabel; | ||
| 9 | import javax.swing.JPanel; | ||
| 10 | |||
| 11 | import cuchaz.enigma.gui.util.ScaleUtil; | ||
| 12 | import cuchaz.enigma.utils.I18n; | ||
| 13 | import cuchaz.enigma.utils.Pair; | ||
| 14 | import cuchaz.enigma.utils.validation.ValidationContext; | ||
| 15 | |||
| 16 | public abstract class AbstractDialog extends JDialog { | ||
| 17 | |||
| 18 | protected final ValidationContext vc = new ValidationContext(); | ||
| 19 | |||
| 20 | private boolean actionConfirm = false; | ||
| 21 | |||
| 22 | public AbstractDialog(Frame owner, String title, String confirmAction, String cancelAction) { | ||
| 23 | super(owner, I18n.translate(title), true); | ||
| 24 | |||
| 25 | Container contentPane = getContentPane(); | ||
| 26 | contentPane.setLayout(new BorderLayout()); | ||
| 27 | Container inputContainer = new JPanel(new GridBagLayout()); | ||
| 28 | GridBagConstraints c = new GridBagConstraints(); | ||
| 29 | |||
| 30 | List<Pair<String, Component>> components = createComponents(); | ||
| 31 | |||
| 32 | for (int i = 0; i < components.size(); i += 1) { | ||
| 33 | Pair<String, Component> entry = components.get(i); | ||
| 34 | JLabel label = new JLabel(I18n.translate(entry.a)); | ||
| 35 | Component component = entry.b; | ||
| 36 | |||
| 37 | c.gridy = i; | ||
| 38 | c.insets = ScaleUtil.getInsets(4, 4, 4, 4); | ||
| 39 | |||
| 40 | c.gridx = 0; | ||
| 41 | c.weightx = 0.0; | ||
| 42 | c.anchor = GridBagConstraints.LINE_END; | ||
| 43 | c.fill = GridBagConstraints.NONE; | ||
| 44 | inputContainer.add(label, c); | ||
| 45 | |||
| 46 | c.gridx = 1; | ||
| 47 | c.weightx = 1.0; | ||
| 48 | c.anchor = GridBagConstraints.LINE_START; | ||
| 49 | c.fill = GridBagConstraints.HORIZONTAL; | ||
| 50 | inputContainer.add(component, c); | ||
| 51 | } | ||
| 52 | contentPane.add(inputContainer, BorderLayout.CENTER); | ||
| 53 | Container buttonContainer = new JPanel(new FlowLayout(FlowLayout.RIGHT, ScaleUtil.scale(4), ScaleUtil.scale(4))); | ||
| 54 | JButton connectButton = new JButton(I18n.translate(confirmAction)); | ||
| 55 | connectButton.addActionListener(event -> confirm()); | ||
| 56 | buttonContainer.add(connectButton); | ||
| 57 | JButton abortButton = new JButton(I18n.translate(cancelAction)); | ||
| 58 | abortButton.addActionListener(event -> cancel()); | ||
| 59 | buttonContainer.add(abortButton); | ||
| 60 | contentPane.add(buttonContainer, BorderLayout.SOUTH); | ||
| 61 | |||
| 62 | pack(); | ||
| 63 | setLocationRelativeTo(owner); | ||
| 64 | } | ||
| 65 | |||
| 66 | protected abstract List<Pair<String, Component>> createComponents(); | ||
| 67 | |||
| 68 | protected void confirm() { | ||
| 69 | vc.reset(); | ||
| 70 | validateInputs(); | ||
| 71 | if (vc.canProceed()) { | ||
| 72 | actionConfirm = true; | ||
| 73 | setVisible(false); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | protected void cancel() { | ||
| 78 | actionConfirm = false; | ||
| 79 | setVisible(false); | ||
| 80 | } | ||
| 81 | |||
| 82 | public boolean isActionConfirm() { | ||
| 83 | return actionConfirm; | ||
| 84 | } | ||
| 85 | |||
| 86 | public void validateInputs() { | ||
| 87 | } | ||
| 88 | |||
| 89 | } | ||
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java index c5f505cf..f23007a0 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/ConnectToServerDialog.java | |||
| @@ -1,64 +1,93 @@ | |||
| 1 | package cuchaz.enigma.gui.dialog; | 1 | package cuchaz.enigma.gui.dialog; |
| 2 | 2 | ||
| 3 | import java.awt.Component; | ||
| 4 | import java.awt.Dimension; | ||
| 5 | import java.awt.Frame; | ||
| 6 | import java.util.Arrays; | ||
| 7 | import java.util.List; | ||
| 8 | import java.util.Objects; | ||
| 9 | |||
| 10 | import javax.swing.JPasswordField; | ||
| 11 | import javax.swing.JTextField; | ||
| 12 | |||
| 13 | import cuchaz.enigma.gui.elements.ValidatableTextField; | ||
| 14 | import cuchaz.enigma.gui.util.ScaleUtil; | ||
| 3 | import cuchaz.enigma.network.EnigmaServer; | 15 | import cuchaz.enigma.network.EnigmaServer; |
| 4 | import cuchaz.enigma.utils.I18n; | 16 | import cuchaz.enigma.network.ServerAddress; |
| 17 | import cuchaz.enigma.utils.Pair; | ||
| 18 | import cuchaz.enigma.utils.validation.Message; | ||
| 19 | import cuchaz.enigma.utils.validation.StandardValidation; | ||
| 5 | 20 | ||
| 6 | import javax.swing.*; | 21 | public class ConnectToServerDialog extends AbstractDialog { |
| 7 | import java.awt.Frame; | ||
| 8 | 22 | ||
| 9 | public class ConnectToServerDialog { | 23 | private JTextField usernameField; |
| 10 | 24 | private ValidatableTextField ipField; | |
| 11 | public static Result show(Frame parentComponent) { | 25 | private JPasswordField passwordField; |
| 12 | JTextField usernameField = new JTextField(System.getProperty("user.name"), 20); | ||
| 13 | JPanel usernameRow = new JPanel(); | ||
| 14 | usernameRow.add(new JLabel(I18n.translate("prompt.connect.username"))); | ||
| 15 | usernameRow.add(usernameField); | ||
| 16 | JTextField ipField = new JTextField(20); | ||
| 17 | JPanel ipRow = new JPanel(); | ||
| 18 | ipRow.add(new JLabel(I18n.translate("prompt.connect.ip"))); | ||
| 19 | ipRow.add(ipField); | ||
| 20 | JTextField portField = new JTextField(String.valueOf(EnigmaServer.DEFAULT_PORT), 10); | ||
| 21 | JPanel portRow = new JPanel(); | ||
| 22 | portRow.add(new JLabel(I18n.translate("prompt.port"))); | ||
| 23 | portRow.add(portField); | ||
| 24 | JPasswordField passwordField = new JPasswordField(20); | ||
| 25 | JPanel passwordRow = new JPanel(); | ||
| 26 | passwordRow.add(new JLabel(I18n.translate("prompt.password"))); | ||
| 27 | passwordRow.add(passwordField); | ||
| 28 | |||
| 29 | int response = JOptionPane.showConfirmDialog(parentComponent, new Object[]{usernameRow, ipRow, portRow, passwordRow}, I18n.translate("prompt.connect.title"), JOptionPane.OK_CANCEL_OPTION); | ||
| 30 | if (response != JOptionPane.OK_OPTION) { | ||
| 31 | return null; | ||
| 32 | } | ||
| 33 | 26 | ||
| 34 | String username = usernameField.getText(); | 27 | public ConnectToServerDialog(Frame owner) { |
| 35 | String ip = ipField.getText(); | 28 | super(owner, "prompt.connect.title", "prompt.connect.confirm", "prompt.cancel"); |
| 36 | int port; | 29 | |
| 37 | try { | 30 | Dimension preferredSize = getPreferredSize(); |
| 38 | port = Integer.parseInt(portField.getText()); | 31 | preferredSize.width = ScaleUtil.scale(400); |
| 39 | } catch (NumberFormatException e) { | 32 | setPreferredSize(preferredSize); |
| 40 | JOptionPane.showMessageDialog(parentComponent, I18n.translate("prompt.port.nan"), I18n.translate("prompt.connect.title"), JOptionPane.ERROR_MESSAGE); | 33 | pack(); |
| 41 | return null; | 34 | setLocationRelativeTo(owner); |
| 42 | } | 35 | } |
| 43 | if (port < 0 || port >= 65536) { | 36 | |
| 44 | JOptionPane.showMessageDialog(parentComponent, I18n.translate("prompt.port.invalid"), I18n.translate("prompt.connect.title"), JOptionPane.ERROR_MESSAGE); | 37 | @Override |
| 45 | return null; | 38 | protected List<Pair<String, Component>> createComponents() { |
| 39 | usernameField = new JTextField(System.getProperty("user.name")); | ||
| 40 | ipField = new ValidatableTextField(); | ||
| 41 | passwordField = new JPasswordField(); | ||
| 42 | |||
| 43 | usernameField.addActionListener(event -> confirm()); | ||
| 44 | ipField.addActionListener(event -> confirm()); | ||
| 45 | passwordField.addActionListener(event -> confirm()); | ||
| 46 | |||
| 47 | return Arrays.asList( | ||
| 48 | new Pair<>("prompt.connect.username", usernameField), | ||
| 49 | new Pair<>("prompt.connect.address", ipField), | ||
| 50 | new Pair<>("prompt.password", passwordField) | ||
| 51 | ); | ||
| 52 | } | ||
| 53 | |||
| 54 | public void validateInputs() { | ||
| 55 | vc.setActiveElement(ipField); | ||
| 56 | if (StandardValidation.notBlank(vc, ipField.getText())) { | ||
| 57 | vc.raise(Message.INVALID_IP); | ||
| 46 | } | 58 | } |
| 47 | char[] password = passwordField.getPassword(); | 59 | } |
| 60 | |||
| 61 | public Result getResult() { | ||
| 62 | if (!isActionConfirm()) return null; | ||
| 63 | vc.reset(); | ||
| 64 | validateInputs(); | ||
| 65 | if (!vc.canProceed()) return null; | ||
| 66 | return new Result( | ||
| 67 | usernameField.getText(), | ||
| 68 | Objects.requireNonNull(ServerAddress.from(ipField.getText(), EnigmaServer.DEFAULT_PORT)), | ||
| 69 | passwordField.getPassword() | ||
| 70 | ); | ||
| 71 | } | ||
| 72 | |||
| 73 | public static Result show(Frame parent) { | ||
| 74 | ConnectToServerDialog d = new ConnectToServerDialog(parent); | ||
| 75 | |||
| 76 | d.setVisible(true); | ||
| 77 | Result r = d.getResult(); | ||
| 48 | 78 | ||
| 49 | return new Result(username, ip, port, password); | 79 | d.dispose(); |
| 80 | return r; | ||
| 50 | } | 81 | } |
| 51 | 82 | ||
| 52 | public static class Result { | 83 | public static class Result { |
| 53 | private final String username; | 84 | private final String username; |
| 54 | private final String ip; | 85 | private final ServerAddress address; |
| 55 | private final int port; | ||
| 56 | private final char[] password; | 86 | private final char[] password; |
| 57 | 87 | ||
| 58 | public Result(String username, String ip, int port, char[] password) { | 88 | public Result(String username, ServerAddress address, char[] password) { |
| 59 | this.username = username; | 89 | this.username = username; |
| 60 | this.ip = ip; | 90 | this.address = address; |
| 61 | this.port = port; | ||
| 62 | this.password = password; | 91 | this.password = password; |
| 63 | } | 92 | } |
| 64 | 93 | ||
| @@ -66,12 +95,8 @@ public class ConnectToServerDialog { | |||
| 66 | return username; | 95 | return username; |
| 67 | } | 96 | } |
| 68 | 97 | ||
| 69 | public String getIp() { | 98 | public ServerAddress getAddress() { |
| 70 | return ip; | 99 | return address; |
| 71 | } | ||
| 72 | |||
| 73 | public int getPort() { | ||
| 74 | return port; | ||
| 75 | } | 100 | } |
| 76 | 101 | ||
| 77 | public char[] getPassword() { | 102 | public char[] getPassword() { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java index eea1dff1..ddd3bc37 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/dialog/CreateServerDialog.java | |||
| @@ -1,47 +1,77 @@ | |||
| 1 | package cuchaz.enigma.gui.dialog; | 1 | package cuchaz.enigma.gui.dialog; |
| 2 | 2 | ||
| 3 | import java.awt.Component; | ||
| 4 | import java.awt.Dimension; | ||
| 5 | import java.awt.Frame; | ||
| 6 | import java.util.Arrays; | ||
| 7 | import java.util.List; | ||
| 8 | |||
| 9 | import cuchaz.enigma.gui.elements.ValidatablePasswordField; | ||
| 10 | import cuchaz.enigma.gui.elements.ValidatableTextField; | ||
| 11 | import cuchaz.enigma.gui.util.ScaleUtil; | ||
| 3 | import cuchaz.enigma.network.EnigmaServer; | 12 | import cuchaz.enigma.network.EnigmaServer; |
| 4 | import cuchaz.enigma.utils.I18n; | 13 | import cuchaz.enigma.utils.Pair; |
| 5 | 14 | import cuchaz.enigma.utils.validation.Message; | |
| 6 | import javax.swing.*; | 15 | import cuchaz.enigma.utils.validation.StandardValidation; |
| 7 | import java.awt.*; | ||
| 8 | |||
| 9 | public class CreateServerDialog { | ||
| 10 | |||
| 11 | public static Result show(Frame parentComponent) { | ||
| 12 | JTextField portField = new JTextField(String.valueOf(EnigmaServer.DEFAULT_PORT), 10); | ||
| 13 | JPanel portRow = new JPanel(); | ||
| 14 | portRow.add(new JLabel(I18n.translate("prompt.port"))); | ||
| 15 | portRow.add(portField); | ||
| 16 | JPasswordField passwordField = new JPasswordField(20); | ||
| 17 | JPanel passwordRow = new JPanel(); | ||
| 18 | passwordRow.add(new JLabel(I18n.translate("prompt.password"))); | ||
| 19 | passwordRow.add(passwordField); | ||
| 20 | |||
| 21 | int response = JOptionPane.showConfirmDialog(parentComponent, new Object[]{portRow, passwordRow}, I18n.translate("prompt.create_server.title"), JOptionPane.OK_CANCEL_OPTION); | ||
| 22 | if (response != JOptionPane.OK_OPTION) { | ||
| 23 | return null; | ||
| 24 | } | ||
| 25 | 16 | ||
| 26 | int port; | 17 | public class CreateServerDialog extends AbstractDialog { |
| 27 | try { | 18 | |
| 28 | port = Integer.parseInt(portField.getText()); | 19 | private ValidatableTextField portField; |
| 29 | } catch (NumberFormatException e) { | 20 | private ValidatablePasswordField passwordField; |
| 30 | JOptionPane.showMessageDialog(parentComponent, I18n.translate("prompt.port.nan"), I18n.translate("prompt.create_server.title"), JOptionPane.ERROR_MESSAGE); | 21 | |
| 31 | return null; | 22 | public CreateServerDialog(Frame owner) { |
| 32 | } | 23 | super(owner, "prompt.create_server.title", "prompt.create_server.confirm", "prompt.cancel"); |
| 33 | if (port < 0 || port >= 65536) { | 24 | |
| 34 | JOptionPane.showMessageDialog(parentComponent, I18n.translate("prompt.port.invalid"), I18n.translate("prompt.create_server.title"), JOptionPane.ERROR_MESSAGE); | 25 | Dimension preferredSize = getPreferredSize(); |
| 35 | return null; | 26 | preferredSize.width = ScaleUtil.scale(400); |
| 36 | } | 27 | setPreferredSize(preferredSize); |
| 28 | pack(); | ||
| 29 | setLocationRelativeTo(owner); | ||
| 30 | } | ||
| 31 | |||
| 32 | @Override | ||
| 33 | protected List<Pair<String, Component>> createComponents() { | ||
| 34 | portField = new ValidatableTextField(Integer.toString(EnigmaServer.DEFAULT_PORT)); | ||
| 35 | passwordField = new ValidatablePasswordField(); | ||
| 37 | 36 | ||
| 38 | char[] password = passwordField.getPassword(); | 37 | portField.addActionListener(event -> confirm()); |
| 39 | if (password.length > EnigmaServer.MAX_PASSWORD_LENGTH) { | 38 | passwordField.addActionListener(event -> confirm()); |
| 40 | JOptionPane.showMessageDialog(parentComponent, I18n.translate("prompt.password.too_long"), I18n.translate("prompt.create_server.title"), JOptionPane.ERROR_MESSAGE); | 39 | |
| 41 | return null; | 40 | return Arrays.asList( |
| 41 | new Pair<>("prompt.create_server.port", portField), | ||
| 42 | new Pair<>("prompt.password", passwordField) | ||
| 43 | ); | ||
| 44 | } | ||
| 45 | |||
| 46 | @Override | ||
| 47 | public void validateInputs() { | ||
| 48 | vc.setActiveElement(portField); | ||
| 49 | StandardValidation.isIntInRange(vc, portField.getText(), 0, 65535); | ||
| 50 | vc.setActiveElement(passwordField); | ||
| 51 | if (passwordField.getPassword().length > EnigmaServer.MAX_PASSWORD_LENGTH) { | ||
| 52 | vc.raise(Message.FIELD_LENGTH_OUT_OF_RANGE, EnigmaServer.MAX_PASSWORD_LENGTH); | ||
| 42 | } | 53 | } |
| 54 | } | ||
| 55 | |||
| 56 | public Result getResult() { | ||
| 57 | if (!isActionConfirm()) return null; | ||
| 58 | vc.reset(); | ||
| 59 | validateInputs(); | ||
| 60 | if (!vc.canProceed()) return null; | ||
| 61 | return new Result( | ||
| 62 | Integer.parseInt(portField.getText()), | ||
| 63 | passwordField.getPassword() | ||
| 64 | ); | ||
| 65 | } | ||
| 66 | |||
| 67 | public static Result show(Frame parent) { | ||
| 68 | CreateServerDialog d = new CreateServerDialog(parent); | ||
| 69 | |||
| 70 | d.setVisible(true); | ||
| 71 | Result r = d.getResult(); | ||
| 43 | 72 | ||
| 44 | return new Result(port, password); | 73 | d.dispose(); |
| 74 | return r; | ||
| 45 | } | 75 | } |
| 46 | 76 | ||
| 47 | public static class Result { | 77 | public static class Result { |
diff --git a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java index 3378d1a4..1481a9dc 100644 --- a/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java +++ b/enigma-swing/src/main/java/cuchaz/enigma/gui/elements/MenuBar.java | |||
| @@ -227,7 +227,7 @@ public class MenuBar { | |||
| 227 | } | 227 | } |
| 228 | this.gui.getController().disconnectIfConnected(null); | 228 | this.gui.getController().disconnectIfConnected(null); |
| 229 | try { | 229 | try { |
| 230 | this.gui.getController().createClient(result.getUsername(), result.getIp(), result.getPort(), result.getPassword()); | 230 | this.gui.getController().createClient(result.getUsername(), result.getAddress().address, result.getAddress().port, result.getPassword()); |
| 231 | } catch (IOException e) { | 231 | } catch (IOException e) { |
| 232 | JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE); | 232 | JOptionPane.showMessageDialog(this.gui.getFrame(), e.toString(), I18n.translate("menu.collab.connect.error"), JOptionPane.ERROR_MESSAGE); |
| 233 | this.gui.getController().disconnectIfConnected(null); | 233 | this.gui.getController().disconnectIfConnected(null); |