package me.teridax.jcash.gui.login; import javax.swing.*; import javax.swing.text.*; import java.awt.*; import java.text.NumberFormat; import static java.awt.BorderLayout.NORTH; import static javax.swing.SwingConstants.CENTER; import static me.teridax.jcash.lang.Translator.translate; public class LoginView extends JPanel { /** * Maximum number of decimal digits that can be stored lossless by a 32-bit signed integer. * N = log10(2^32-1) = 9,632959861146281 */ private static final int MAX_PIN_DECIMAL_DIGITS = 9; private JFormattedTextField blz; private JFormattedTextField iban; private JPasswordField pin; private JButton login; public LoginView() { createComponents(); layoutComponents(); } private void layoutComponents() { var content = new JPanel(new GridBagLayout()); this.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); this.setLayout(new BorderLayout(16, 16)); this.add(new JScrollPane(content), BorderLayout.CENTER); this.add(new JLabel("

" + translate("Cashmachine") + "", CENTER), NORTH); var constraints = new GridBagConstraints(); constraints.gridwidth = 4; constraints.insets = new Insets(12, 12, 12, 12); addInputRow(constraints, content, blz, 1, translate("BLZ")); addInputRow(constraints, content, iban, 2, translate("IBAN")); addInputRow(constraints, content, pin, 3, translate("PIN")); constraints.gridy = 4; constraints.anchor = GridBagConstraints.PAGE_END; constraints.weightx = 0; constraints.fill = GridBagConstraints.NONE; constraints.insets = new Insets(12, 12, 12, 12); content.add(login, constraints); } private void createComponents() { this.blz = new JFormattedTextField(); this.iban = new JFormattedTextField(getNumberFormat()); this.pin = new JPasswordField(); this.login = new JButton(translate("Login")); restrictPasswordToDigits(); } /** * Adds a document filter onto {@link #pin} that filters out everything that is not a digit. * The filter also restricts the amount of digits that can be entered to {@link #MAX_PIN_DECIMAL_DIGITS} */ private void restrictPasswordToDigits() { ((AbstractDocument) this.pin.getDocument()).setDocumentFilter(new DocumentFilter() { @Override public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException { String newText = fb.getDocument().getText(0, fb.getDocument().getLength()) + text; if (newText.matches(String.format("\\d{1,%s}", MAX_PIN_DECIMAL_DIGITS))) { super.replace(fb, offset, length, text, attrs); } } }); } private NumberFormatter getNumberFormat() { var format = NumberFormat.getIntegerInstance(); format.setGroupingUsed(false); var formatter = new NumberFormatter(format); formatter.setValueClass(Integer.class); formatter.setMinimum(0); formatter.setMaximum(Integer.MAX_VALUE); formatter.setAllowsInvalid(false); return formatter; } private void addInputRow(GridBagConstraints constraints, JComponent target, JComponent comp, int row, String name) { constraints.gridwidth = 1; constraints.gridx = 1; constraints.gridy = row; constraints.weightx = 0; constraints.fill = GridBagConstraints.HORIZONTAL; target.add(new JLabel(name, SwingConstants.RIGHT), constraints); constraints.gridx = 2; constraints.gridy = row; constraints.weightx = 1; constraints.fill = GridBagConstraints.HORIZONTAL; target.add(comp, constraints); } public JTextField getBlz() { return blz; } public JTextField getIban() { return iban; } public JPasswordField getPin() { return pin; } public JButton getLogin() { return login; } }