From 8ebb4eef8c060822205136cc6f8f4a2068c78d40 Mon Sep 17 00:00:00 2001 From: teridax Date: Thu, 22 Jun 2023 14:58:20 +0200 Subject: [PATCH 1/5] added login screen --- src/Main.java | 16 +++- src/me/teridax/jcash/banking/Bank.java | 11 +++ .../banking/BankingManagementSystem.java | 4 + src/me/teridax/jcash/gui/Loader.java | 30 ++++++++ .../jcash/gui/login/LoginController.java | 58 ++++++++++++++ src/me/teridax/jcash/gui/login/LoginData.java | 24 ++++++ src/me/teridax/jcash/gui/login/LoginView.java | 75 +++++++++++++++++++ 7 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 src/me/teridax/jcash/gui/Loader.java create mode 100644 src/me/teridax/jcash/gui/login/LoginController.java create mode 100644 src/me/teridax/jcash/gui/login/LoginData.java create mode 100644 src/me/teridax/jcash/gui/login/LoginView.java diff --git a/src/Main.java b/src/Main.java index 3e59c38..e456075 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,5 +1,19 @@ +import me.teridax.jcash.gui.login.LoginView; + +import javax.swing.*; + public class Main { + public static void main(String[] args) { - System.out.println("Hello world!"); + SwingUtilities.invokeLater(() -> { + // Loader.load(); + + var window = new JFrame(); + window.setTitle("Bankautomat"); + window.setLocationByPlatform(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.add(new LoginView()); + window.setVisible(true); + }); } } \ No newline at end of file diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java index 13bad12..41fd5d6 100644 --- a/src/me/teridax/jcash/banking/Bank.java +++ b/src/me/teridax/jcash/banking/Bank.java @@ -56,4 +56,15 @@ public final class Bank { return blz; } + + public Optional getAccount(int iban) { + for (var owner : this.accounts.entrySet()) { + for (var account : owner.getValue()) { + if (account.getIban() == iban) { + return Optional.of(account); + } + } + } + return Optional.empty(); + } } diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java index 35d8839..c296c18 100644 --- a/src/me/teridax/jcash/banking/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java @@ -54,4 +54,8 @@ public final class BankingManagementSystem { throw new IllegalArgumentException("Could not parse file " + file, e); } } + + public Optional getBank(String blz) { + return this.banks.stream().filter(b -> b.getBlz().equals(blz)).findFirst(); + } } diff --git a/src/me/teridax/jcash/gui/Loader.java b/src/me/teridax/jcash/gui/Loader.java new file mode 100644 index 0000000..4219c0b --- /dev/null +++ b/src/me/teridax/jcash/gui/Loader.java @@ -0,0 +1,30 @@ +package me.teridax.jcash.gui; + +import me.teridax.jcash.banking.BankingManagementSystem; + +import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; + +public class Loader { + + private static final FileNameExtensionFilter FILE_FILTER = new FileNameExtensionFilter("Comma separated value spreadsheet", "csv", "CSV"); + + public static BankingManagementSystem load() throws IllegalStateException { + var fileChooser = new JFileChooser(); + fileChooser.setMultiSelectionEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setFileFilter(FILE_FILTER); + fileChooser.setDialogType(JFileChooser.OPEN_DIALOG); + fileChooser.setAcceptAllFileFilterUsed(false); + + if (fileChooser.showDialog(null, "Load database") == JFileChooser.APPROVE_OPTION) { + try { + return BankingManagementSystem.loadFromCsv(fileChooser.getSelectedFile().toPath()); + } catch (Exception e) { + throw new IllegalStateException("Unable to load database", e); + } + } + + throw new IllegalStateException("No file selected"); + } +} diff --git a/src/me/teridax/jcash/gui/login/LoginController.java b/src/me/teridax/jcash/gui/login/LoginController.java new file mode 100644 index 0000000..543f42e --- /dev/null +++ b/src/me/teridax/jcash/gui/login/LoginController.java @@ -0,0 +1,58 @@ +package me.teridax.jcash.gui.login; + +import me.teridax.jcash.banking.Account; +import me.teridax.jcash.banking.BankingManagementSystem; + +import java.awt.event.ActionEvent; +import java.util.Optional; + +public class LoginController { + + private LoginView view; + private LoginData data; + + private Optional account; + + public LoginController(BankingManagementSystem bms) { + this.view = new LoginView(); + this.data = new LoginData(bms); + this.account = Optional.empty(); + + addActionListeners(); + } + + private void addActionListeners() { + this.view.getLogin().addActionListener(this::login); + } + + private Optional getIban() { + try { + var iban = this.view.getIban().getText(); + return Optional.of(Integer.parseUnsignedInt(iban)); + } catch (NumberFormatException e) { + return Optional.empty(); + } + } + private Optional getPin() { + try { + var iban = this.view.getPin().getPassword(); + return Optional.of(Integer.parseUnsignedInt(new String(iban))); + } catch (NumberFormatException e) { + return Optional.empty(); + } + } + + private void login(ActionEvent ignored) { + var blz = this.view.getBlz().getText(); + var iban = this.getIban(); + if (iban.isEmpty()) { + return; + } + var pin = this.getPin(); + if (pin.isEmpty()) { + return; + } + + this.account = this.data.authenticateAccount(blz, iban.get(), pin.get()); + } +} diff --git a/src/me/teridax/jcash/gui/login/LoginData.java b/src/me/teridax/jcash/gui/login/LoginData.java new file mode 100644 index 0000000..730128e --- /dev/null +++ b/src/me/teridax/jcash/gui/login/LoginData.java @@ -0,0 +1,24 @@ +package me.teridax.jcash.gui.login; + +import me.teridax.jcash.banking.Account; +import me.teridax.jcash.banking.BankingManagementSystem; + +import java.util.Optional; + +public class LoginData { + + private final BankingManagementSystem bms; + + public LoginData(BankingManagementSystem bms) { + this.bms = bms; + } + + public Optional authenticateAccount(String blz, int iban, int pin) { + var optionalBank = bms.getBank(blz); + if (optionalBank.isEmpty()) + return Optional.empty(); + + var account = optionalBank.get().getAccount(iban); + return account.filter(value -> value.getPin() == pin); + } +} diff --git a/src/me/teridax/jcash/gui/login/LoginView.java b/src/me/teridax/jcash/gui/login/LoginView.java new file mode 100644 index 0000000..7bf3043 --- /dev/null +++ b/src/me/teridax/jcash/gui/login/LoginView.java @@ -0,0 +1,75 @@ +package me.teridax.jcash.gui.login; + +import javax.swing.*; +import java.awt.*; + +public class LoginView extends JPanel { + + private final JTextField blz; + private final JTextField iban; + private final JPasswordField pin; + private final JButton login; + + public LoginView() { + this.blz = new JTextField(); + this.iban = new JTextField(); + this.pin = new JPasswordField(); + this.login = new JButton("Login"); + + setLayout(new BorderLayout(16, 16)); + var content = new JPanel(); + this.setBorder(BorderFactory.createEmptyBorder(8,8,8,8)); + add(new JScrollPane(content), BorderLayout.CENTER); + add(new JLabel("Bankautomat"), BorderLayout.NORTH); + + var layout = new GridBagLayout(); + var constraints = new GridBagConstraints(); + content.setLayout(layout); + + constraints.gridwidth = 4; + + constraints.insets = new Insets(12,12,12,12); + + addInputRow(constraints, content, blz, 1, "BLZ"); + addInputRow(constraints, content, iban, 2, "Kontonummer"); + addInputRow(constraints, content, pin, 3, "Passwort"); + + 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 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; + } +} -- 2.40.1 From c34895f92e25f8d5bc7d62074301bfcd62a95042 Mon Sep 17 00:00:00 2001 From: teridax Date: Thu, 22 Jun 2023 17:19:43 +0200 Subject: [PATCH 2/5] added profile screen --- src/Main.java | 19 -- src/me/teridax/jcash/Main.java | 61 +++++++ src/me/teridax/jcash/banking/Account.java | 4 + src/me/teridax/jcash/banking/Bank.java | 4 +- .../banking/BankingManagementSystem.java | 2 +- src/me/teridax/jcash/banking/Profile.java | 41 +++++ src/me/teridax/jcash/decode/Decoder.java | 2 +- src/me/teridax/jcash/gui/Loader.java | 2 + .../jcash/gui/account/AccountController.java | 33 ++++ .../jcash/gui/account/AccountView.java | 169 ++++++++++++++++++ .../gui/login/AccountSelectionListener.java | 8 + .../jcash/gui/login/LoginController.java | 21 ++- src/me/teridax/jcash/gui/login/LoginData.java | 7 +- src/me/teridax/jcash/gui/login/LoginView.java | 8 +- 14 files changed, 348 insertions(+), 33 deletions(-) delete mode 100644 src/Main.java create mode 100644 src/me/teridax/jcash/Main.java create mode 100644 src/me/teridax/jcash/banking/Profile.java create mode 100644 src/me/teridax/jcash/gui/account/AccountController.java create mode 100644 src/me/teridax/jcash/gui/account/AccountView.java create mode 100644 src/me/teridax/jcash/gui/login/AccountSelectionListener.java diff --git a/src/Main.java b/src/Main.java deleted file mode 100644 index e456075..0000000 --- a/src/Main.java +++ /dev/null @@ -1,19 +0,0 @@ -import me.teridax.jcash.gui.login.LoginView; - -import javax.swing.*; - -public class Main { - - public static void main(String[] args) { - SwingUtilities.invokeLater(() -> { - // Loader.load(); - - var window = new JFrame(); - window.setTitle("Bankautomat"); - window.setLocationByPlatform(true); - window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - window.add(new LoginView()); - window.setVisible(true); - }); - } -} \ No newline at end of file diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java new file mode 100644 index 0000000..7616d32 --- /dev/null +++ b/src/me/teridax/jcash/Main.java @@ -0,0 +1,61 @@ +package me.teridax.jcash; + +import me.teridax.jcash.gui.Loader; +import me.teridax.jcash.gui.account.AccountController; +import me.teridax.jcash.gui.login.LoginController; + +import javax.swing.*; + +public class Main { + + private static Main instance; + + private final JFrame window; + + private Main() { + window = new JFrame(); + window.setTitle("Bankautomat"); + window.setLocationByPlatform(true); + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + + public static void main(String[] args) { + instance(); + getInstance().popLoginScreen(); + } + + public static Main getInstance() { + return instance; + } + + public static void instance() { + if (instance == null) { + instance = new Main(); + return; + } + + throw new IllegalStateException("me.teridax.jcash.Main is already initialized"); + } + + public void popLoginScreen() { + SwingUtilities.invokeLater(() -> { + var path = Loader.load(); + var login = new LoginController(path); + + login.addAccountSelectionListener(account -> { + var profileCont = new AccountController(account); + window.setContentPane(profileCont.getView()); + window.pack(); + }); + + window.setContentPane(login.getView()); + window.pack(); + window.setVisible(true); + }); + } + + public void logout() { + window.setContentPane(new JLabel("you're logged out")); + window.setVisible(false); + } +} \ No newline at end of file diff --git a/src/me/teridax/jcash/banking/Account.java b/src/me/teridax/jcash/banking/Account.java index 7ef9445..961178c 100644 --- a/src/me/teridax/jcash/banking/Account.java +++ b/src/me/teridax/jcash/banking/Account.java @@ -64,4 +64,8 @@ public abstract class Account { return false; } + + public String getDescription() { + return String.format("%s (%s)", iban, getClass().getSimpleName()); + } } diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java index 41fd5d6..87a2af2 100644 --- a/src/me/teridax/jcash/banking/Bank.java +++ b/src/me/teridax/jcash/banking/Bank.java @@ -57,11 +57,11 @@ public final class Bank { return blz; } - public Optional getAccount(int iban) { + public Optional getAccount(int iban) { for (var owner : this.accounts.entrySet()) { for (var account : owner.getValue()) { if (account.getIban() == iban) { - return Optional.of(account); + return Optional.of(new Profile(owner.getKey(), this, account, getAccountsOfOwner(owner.getKey()))); } } } diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java index c296c18..b09d361 100644 --- a/src/me/teridax/jcash/banking/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java @@ -56,6 +56,6 @@ public final class BankingManagementSystem { } public Optional getBank(String blz) { - return this.banks.stream().filter(b -> b.getBlz().equals(blz)).findFirst(); + return this.banks.stream().filter(b -> !b.getBlz().equals(blz)).findFirst(); } } diff --git a/src/me/teridax/jcash/banking/Profile.java b/src/me/teridax/jcash/banking/Profile.java new file mode 100644 index 0000000..9ac33a6 --- /dev/null +++ b/src/me/teridax/jcash/banking/Profile.java @@ -0,0 +1,41 @@ +package me.teridax.jcash.banking; + +public class Profile { + + private Owner owner; + private Bank bank; + private Account primaryAccount; + private Account[] accounts; + + public Profile(Owner owner, Bank bank, Account account, Account[] accounts) { + this.owner = owner; + this.bank = bank; + this.accounts = accounts; + this.primaryAccount = account; + } + + public Account getPrimaryAccount() { + return primaryAccount; + } + + public Owner getOwner() { + return owner; + } + + public Bank getBank() { + return bank; + } + + public Account[] getAccounts() { + return accounts; + } + + public void setPrimaryAccount(String description) { + for (Account account : accounts) { + if (account.getDescription().equals(description)) { + this.primaryAccount = account; + break; + } + } + } +} diff --git a/src/me/teridax/jcash/decode/Decoder.java b/src/me/teridax/jcash/decode/Decoder.java index 4af70b8..4be4189 100644 --- a/src/me/teridax/jcash/decode/Decoder.java +++ b/src/me/teridax/jcash/decode/Decoder.java @@ -13,7 +13,7 @@ import static junit.framework.TestCase.assertEquals; public class Decoder { private static final Locale LOCALE = Locale.GERMANY; - private static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE); + public static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE); public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(number); diff --git a/src/me/teridax/jcash/gui/Loader.java b/src/me/teridax/jcash/gui/Loader.java index 4219c0b..28a9d15 100644 --- a/src/me/teridax/jcash/gui/Loader.java +++ b/src/me/teridax/jcash/gui/Loader.java @@ -4,6 +4,7 @@ import me.teridax.jcash.banking.BankingManagementSystem; import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; +import java.io.File; public class Loader { @@ -16,6 +17,7 @@ public class Loader { fileChooser.setFileFilter(FILE_FILTER); fileChooser.setDialogType(JFileChooser.OPEN_DIALOG); fileChooser.setAcceptAllFileFilterUsed(false); + fileChooser.setCurrentDirectory(new File("/home/teridax/IdeaProjects/JCash/res")); if (fileChooser.showDialog(null, "Load database") == JFileChooser.APPROVE_OPTION) { try { diff --git a/src/me/teridax/jcash/gui/account/AccountController.java b/src/me/teridax/jcash/gui/account/AccountController.java new file mode 100644 index 0000000..6a5227a --- /dev/null +++ b/src/me/teridax/jcash/gui/account/AccountController.java @@ -0,0 +1,33 @@ +package me.teridax.jcash.gui.account; + +import me.teridax.jcash.Main; +import me.teridax.jcash.banking.Profile; + +public class AccountController { + + private final AccountView view; + + public AccountController(Profile profile) { + this.view = new AccountView(); + this.view.setProfile(profile); + + createListeners(profile); + } + + private void createListeners(Profile profile) { + this.view.getAccountSelection().addActionListener(e -> { + var description = ((String) this.view.getAccountSelection().getSelectedItem()); + profile.setPrimaryAccount(description); + this.view.setProfile(profile); + }); + + this.view.getLogout().addActionListener(e -> { + Main.getInstance().logout(); + Main.getInstance().popLoginScreen(); + }); + } + + public AccountView getView() { + return view; + } +} diff --git a/src/me/teridax/jcash/gui/account/AccountView.java b/src/me/teridax/jcash/gui/account/AccountView.java new file mode 100644 index 0000000..4f1364d --- /dev/null +++ b/src/me/teridax/jcash/gui/account/AccountView.java @@ -0,0 +1,169 @@ +package me.teridax.jcash.gui.account; + +import me.teridax.jcash.banking.*; +import me.teridax.jcash.decode.Decoder; + +import javax.swing.*; +import java.awt.*; + +public class AccountView extends JPanel { + + private JTextField iban; + private JTextField name; + private JTextField address; + private JTextField bankName; + private JTextField blz; + private JTextField type; + private JTextField typeSpecialProperty; + private JTextField balance; + + private JLabel typeSpecialLabel; + + private JComboBox accountSelection; + + private JPanel content; + private JPanel buttonPanel; + + private JButton logout; + private JButton transfer; + private JButton deposit; + private JButton takeoff; + + public AccountView() { + createComponents(); + createLayout(); + + setBorder(BorderFactory.createEmptyBorder(8,8,8,8)); + } + + public void setProfile(Profile profile) { + var bank = profile.getBank(); + var account = profile.getPrimaryAccount(); + var owner = profile.getOwner(); + + this.blz.setText(bank.getBlz()); + this.bankName.setText(bank.getName()); + + this.iban.setText(String.valueOf(account.getIban())); + this.name.setText(owner.getName() + " " + owner.getFamilyName()); + this.address.setText(owner.getStreet() + " " + owner.getCity()); + + this.balance.setText(Decoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + " €"); + + this.type.setText(account.getClass().getSimpleName()); + if (account instanceof Girokonto) { + this.typeSpecialLabel.setText("Überziehungsbetrag"); + this.typeSpecialProperty.setText( Decoder.LOCAL_NUMBER_FORMAT.format(((Girokonto) account).getOverdraft()) + " €"); + } else if (account instanceof SavingsAccount) { + this.typeSpecialLabel.setText("Zinsbetrag"); + this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); + } + + this.accountSelection.removeAllItems(); + + for (var otherAccount : profile.getAccounts()) { + this.accountSelection.addItem(otherAccount.getDescription()); + } + this.accountSelection.setSelectedItem(account.getDescription()); + } + + private void createLayout() { + setLayout(new BorderLayout(16, 16)); + add(new JScrollPane(content), BorderLayout.CENTER); + add(buttonPanel, BorderLayout.SOUTH); + + content.setLayout(new GridBagLayout()); + var constraints = new GridBagConstraints(); + + constraints.gridwidth = 4; + constraints.insets = new Insets(12,12,12,12); + + var accountSelectionPanel = new JPanel(new BorderLayout(12, 0)); + accountSelectionPanel.add(iban, BorderLayout.CENTER); + accountSelectionPanel.add(accountSelection, BorderLayout.EAST); + + addInputRow(constraints, content, accountSelectionPanel, 1, new JLabel("Kontonummer", SwingConstants.RIGHT)); + addInputRow(constraints, content, name, 2, new JLabel("Vorname/Nachname", SwingConstants.RIGHT)); + addInputRow(constraints, content, address, 3, new JLabel("Adresse", SwingConstants.RIGHT)); + addInputRow(constraints, content, bankName, 4, new JLabel("Bank", SwingConstants.RIGHT)); + addInputRow(constraints, content, blz, 5, new JLabel("BLZ", SwingConstants.RIGHT)); + addInputRow(constraints, content, type, 6, new JLabel("Konto", SwingConstants.RIGHT)); + addInputRow(constraints, content, typeSpecialProperty, 7, typeSpecialLabel); + addInputRow(constraints, content, balance, 8, new JLabel("Kontostand", SwingConstants.RIGHT)); + + var buttonRightPanel = new JPanel(); + buttonRightPanel.add(transfer); + buttonRightPanel.add(deposit); + buttonRightPanel.add(takeoff); + + buttonPanel.add(logout, BorderLayout.LINE_START); + buttonPanel.add(buttonRightPanel, BorderLayout.LINE_END); + } + + private void createComponents() { + this.blz = new JTextField(); + this.iban = new JTextField(); + this.address = new JTextField(); + this.bankName = new JTextField(); + this.name = new JTextField(); + this.type = new JTextField(); + this.balance = new JTextField(); + this.typeSpecialProperty = new JTextField(); + + this.blz.setEditable(false); + this.iban.setEditable(false); + this.address.setEditable(false); + this.bankName.setEditable(false); + this.name.setEditable(false); + this.type.setEditable(false); + this.balance.setEditable(false); + this.typeSpecialProperty.setEditable(false); + + this.typeSpecialLabel = new JLabel("", SwingConstants.RIGHT); + + this.accountSelection = new JComboBox<>(); + + this.content = new JPanel(); + this.buttonPanel = new JPanel(new BorderLayout()); + + this.logout = new JButton("Abmelden"); + this.transfer = new JButton("Überweisen"); + this.deposit = new JButton("Einzahlen"); + this.takeoff = new JButton("Abheben"); + } + + private void addInputRow(GridBagConstraints constraints, JComponent target, JComponent comp, int row, JLabel label) { + constraints.gridwidth = 1; + constraints.gridx = 1; + constraints.gridy = row; + constraints.weightx = 0; + constraints.fill = GridBagConstraints.HORIZONTAL; + target.add(label, constraints); + + constraints.gridx = 2; + constraints.gridy = row; + constraints.weightx = 1; + constraints.fill = GridBagConstraints.HORIZONTAL; + target.add(comp, constraints); + } + + public JComboBox getAccountSelection() { + return accountSelection; + } + + public JButton getLogout() { + return logout; + } + + public JButton getTransfer() { + return transfer; + } + + public JButton getDeposit() { + return deposit; + } + + public JButton getTakeoff() { + return takeoff; + } +} diff --git a/src/me/teridax/jcash/gui/login/AccountSelectionListener.java b/src/me/teridax/jcash/gui/login/AccountSelectionListener.java new file mode 100644 index 0000000..abeac4f --- /dev/null +++ b/src/me/teridax/jcash/gui/login/AccountSelectionListener.java @@ -0,0 +1,8 @@ +package me.teridax.jcash.gui.login; + +import me.teridax.jcash.banking.Profile; + +public interface AccountSelectionListener { + + void onAccountSelected(Profile account); +} diff --git a/src/me/teridax/jcash/gui/login/LoginController.java b/src/me/teridax/jcash/gui/login/LoginController.java index 543f42e..8d3ed26 100644 --- a/src/me/teridax/jcash/gui/login/LoginController.java +++ b/src/me/teridax/jcash/gui/login/LoginController.java @@ -3,6 +3,7 @@ package me.teridax.jcash.gui.login; import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; +import javax.swing.*; import java.awt.event.ActionEvent; import java.util.Optional; @@ -11,12 +12,11 @@ public class LoginController { private LoginView view; private LoginData data; - private Optional account; + private AccountSelectionListener listener; public LoginController(BankingManagementSystem bms) { this.view = new LoginView(); this.data = new LoginData(bms); - this.account = Optional.empty(); addActionListeners(); } @@ -46,13 +46,28 @@ public class LoginController { var blz = this.view.getBlz().getText(); var iban = this.getIban(); if (iban.isEmpty()) { + JOptionPane.showMessageDialog(null, "invalid IBAN", "Faulty login attempt", JOptionPane.ERROR_MESSAGE); return; } var pin = this.getPin(); if (pin.isEmpty()) { + JOptionPane.showMessageDialog(null, "invalid pin", "Faulty login attempt", JOptionPane.ERROR_MESSAGE); return; } - this.account = this.data.authenticateAccount(blz, iban.get(), pin.get()); + var account = this.data.authenticateAccount(blz, iban.get(), pin.get()); + if (account.isPresent()) { + this.listener.onAccountSelected(account.get()); + } else { + JOptionPane.showMessageDialog(null, "invalid login credentials", "Faulty login attempt", JOptionPane.ERROR_MESSAGE); + } + } + + public void addAccountSelectionListener(AccountSelectionListener listener) { + this.listener = listener; + } + + public LoginView getView() { + return view; } } diff --git a/src/me/teridax/jcash/gui/login/LoginData.java b/src/me/teridax/jcash/gui/login/LoginData.java index 730128e..e599931 100644 --- a/src/me/teridax/jcash/gui/login/LoginData.java +++ b/src/me/teridax/jcash/gui/login/LoginData.java @@ -2,6 +2,7 @@ package me.teridax.jcash.gui.login; import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; +import me.teridax.jcash.banking.Profile; import java.util.Optional; @@ -13,12 +14,12 @@ public class LoginData { this.bms = bms; } - public Optional authenticateAccount(String blz, int iban, int pin) { + public Optional authenticateAccount(String blz, int iban, int pin) { var optionalBank = bms.getBank(blz); if (optionalBank.isEmpty()) return Optional.empty(); - var account = optionalBank.get().getAccount(iban); - return account.filter(value -> value.getPin() == pin); + var profile = optionalBank.get().getAccount(iban); + return profile.filter(value -> value.getPrimaryAccount().getPin() == pin); } } diff --git a/src/me/teridax/jcash/gui/login/LoginView.java b/src/me/teridax/jcash/gui/login/LoginView.java index 7bf3043..5b1114f 100644 --- a/src/me/teridax/jcash/gui/login/LoginView.java +++ b/src/me/teridax/jcash/gui/login/LoginView.java @@ -11,9 +11,9 @@ public class LoginView extends JPanel { private final JButton login; public LoginView() { - this.blz = new JTextField(); - this.iban = new JTextField(); - this.pin = new JPasswordField(); + this.blz = new JTextField("MA2424"); + this.iban = new JTextField("4711"); + this.pin = new JPasswordField("1234"); this.login = new JButton("Login"); setLayout(new BorderLayout(16, 16)); @@ -27,7 +27,6 @@ public class LoginView extends JPanel { content.setLayout(layout); constraints.gridwidth = 4; - constraints.insets = new Insets(12,12,12,12); addInputRow(constraints, content, blz, 1, "BLZ"); @@ -72,4 +71,5 @@ public class LoginView extends JPanel { public JButton getLogin() { return login; } + } -- 2.40.1 From affe69cf2c22418a54a3c623a4b93a00af3c1618 Mon Sep 17 00:00:00 2001 From: teridax Date: Thu, 22 Jun 2023 20:36:51 +0200 Subject: [PATCH 3/5] added deposit/transfer/takeoff screen --- src/me/teridax/jcash/Main.java | 1 - src/me/teridax/jcash/banking/Account.java | 15 +- src/me/teridax/jcash/banking/Bank.java | 16 +- .../banking/BankingManagementSystem.java | 2 +- .../jcash/gui/account/AccountController.java | 15 ++ .../jcash/gui/deposit/DepositDialog.java | 17 ++ .../jcash/gui/deposit/DepositView.java | 124 +++++++++++++ .../jcash/gui/login/LoginController.java | 6 +- src/me/teridax/jcash/gui/login/LoginData.java | 1 - src/me/teridax/jcash/gui/login/LoginView.java | 25 ++- .../jcash/gui/takeoff/TakeoffDialog.java | 17 ++ .../jcash/gui/takeoff/TakeoffView.java | 130 ++++++++++++++ .../jcash/gui/transfer/TransferDialog.java | 17 ++ .../jcash/gui/transfer/TransferView.java | 168 ++++++++++++++++++ 14 files changed, 534 insertions(+), 20 deletions(-) create mode 100644 src/me/teridax/jcash/gui/deposit/DepositDialog.java create mode 100644 src/me/teridax/jcash/gui/deposit/DepositView.java create mode 100644 src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java create mode 100644 src/me/teridax/jcash/gui/takeoff/TakeoffView.java create mode 100644 src/me/teridax/jcash/gui/transfer/TransferDialog.java create mode 100644 src/me/teridax/jcash/gui/transfer/TransferView.java diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java index 7616d32..025f8d5 100644 --- a/src/me/teridax/jcash/Main.java +++ b/src/me/teridax/jcash/Main.java @@ -9,7 +9,6 @@ import javax.swing.*; public class Main { private static Main instance; - private final JFrame window; private Main() { diff --git a/src/me/teridax/jcash/banking/Account.java b/src/me/teridax/jcash/banking/Account.java index 961178c..ec0ded5 100644 --- a/src/me/teridax/jcash/banking/Account.java +++ b/src/me/teridax/jcash/banking/Account.java @@ -9,7 +9,7 @@ public abstract class Account { private final int iban; private final int pin; - private final double balance; + private double balance; public Account(int iban, int pin, double balance) { this.iban = iban; @@ -68,4 +68,17 @@ public abstract class Account { public String getDescription() { return String.format("%s (%s)", iban, getClass().getSimpleName()); } + + public void deposit(double amount) { + this.balance += amount; + } + + @Override + public String toString() { + return String.format("@Account [iban=%d, pin=%d, balance=%.2f]", iban, pin, balance); + } + + public void takeoff(double amount) { + this.balance = Math.max(0, this.balance - amount); + } } diff --git a/src/me/teridax/jcash/banking/Bank.java b/src/me/teridax/jcash/banking/Bank.java index 87a2af2..03b347b 100644 --- a/src/me/teridax/jcash/banking/Bank.java +++ b/src/me/teridax/jcash/banking/Bank.java @@ -1,6 +1,7 @@ package me.teridax.jcash.banking; import java.util.*; +import java.util.regex.Pattern; @SuppressWarnings("unused") public final class Bank { @@ -46,21 +47,20 @@ public final class Bank { } public static String validateBlz(String maybeBlz) { - var builder = new StringBuilder(); - maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append); - var blz = builder.toString(); + var pattern = Pattern.compile("[\\w\\d-_]+"); + var matcher = pattern.matcher(maybeBlz); - if (blz.isEmpty()) { - throw new IllegalArgumentException("Bank Blz must only contain letters and digits"); - } + if (matcher.find()) + return matcher.group(); - return blz; + throw new IllegalArgumentException("not a valid BLZ: " + maybeBlz); } public Optional getAccount(int iban) { for (var owner : this.accounts.entrySet()) { for (var account : owner.getValue()) { - if (account.getIban() == iban) { + var tmp = account.getIban(); + if (tmp == iban) { return Optional.of(new Profile(owner.getKey(), this, account, getAccountsOfOwner(owner.getKey()))); } } diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java index b09d361..c296c18 100644 --- a/src/me/teridax/jcash/banking/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java @@ -56,6 +56,6 @@ public final class BankingManagementSystem { } public Optional getBank(String blz) { - return this.banks.stream().filter(b -> !b.getBlz().equals(blz)).findFirst(); + return this.banks.stream().filter(b -> b.getBlz().equals(blz)).findFirst(); } } diff --git a/src/me/teridax/jcash/gui/account/AccountController.java b/src/me/teridax/jcash/gui/account/AccountController.java index 6a5227a..9f9aa07 100644 --- a/src/me/teridax/jcash/gui/account/AccountController.java +++ b/src/me/teridax/jcash/gui/account/AccountController.java @@ -2,6 +2,9 @@ package me.teridax.jcash.gui.account; import me.teridax.jcash.Main; import me.teridax.jcash.banking.Profile; +import me.teridax.jcash.gui.deposit.DepositDialog; +import me.teridax.jcash.gui.takeoff.TakeoffDialog; +import me.teridax.jcash.gui.transfer.TransferDialog; public class AccountController { @@ -25,6 +28,18 @@ public class AccountController { Main.getInstance().logout(); Main.getInstance().popLoginScreen(); }); + + this.view.getDeposit().addActionListener(e -> { + new DepositDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); + + this.view.getTakeoff().addActionListener(e -> { + new TakeoffDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); + + this.view.getTransfer().addActionListener(e -> { + new TransferDialog(profile.getPrimaryAccount(), () -> this.view.setProfile(profile)); + }); } public AccountView getView() { diff --git a/src/me/teridax/jcash/gui/deposit/DepositDialog.java b/src/me/teridax/jcash/gui/deposit/DepositDialog.java new file mode 100644 index 0000000..00e9e5b --- /dev/null +++ b/src/me/teridax/jcash/gui/deposit/DepositDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.deposit; + +import me.teridax.jcash.banking.Account; + +public class DepositDialog { + + public DepositDialog(Account account, Runnable onDeposit) { + var view = new DepositView(account); + view.getDeposit().addActionListener(e -> { + account.deposit(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/deposit/DepositView.java b/src/me/teridax/jcash/gui/deposit/DepositView.java new file mode 100644 index 0000000..7415a92 --- /dev/null +++ b/src/me/teridax/jcash/gui/deposit/DepositView.java @@ -0,0 +1,124 @@ +package me.teridax.jcash.gui.deposit; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +public class DepositView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField value; + + public DepositView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat() { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(false); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Deposit money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(cancel, c); + + c.gridx = 2; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(deposit, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Einzahlen"); + this.value = new JFormattedTextField(getNumberFormat()); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) + return 0; + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +} diff --git a/src/me/teridax/jcash/gui/login/LoginController.java b/src/me/teridax/jcash/gui/login/LoginController.java index 8d3ed26..06a614f 100644 --- a/src/me/teridax/jcash/gui/login/LoginController.java +++ b/src/me/teridax/jcash/gui/login/LoginController.java @@ -1,6 +1,5 @@ package me.teridax.jcash.gui.login; -import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; import javax.swing.*; @@ -9,8 +8,8 @@ import java.util.Optional; public class LoginController { - private LoginView view; - private LoginData data; + private final LoginView view; + private final LoginData data; private AccountSelectionListener listener; @@ -33,6 +32,7 @@ public class LoginController { return Optional.empty(); } } + private Optional getPin() { try { var iban = this.view.getPin().getPassword(); diff --git a/src/me/teridax/jcash/gui/login/LoginData.java b/src/me/teridax/jcash/gui/login/LoginData.java index e599931..3183c99 100644 --- a/src/me/teridax/jcash/gui/login/LoginData.java +++ b/src/me/teridax/jcash/gui/login/LoginData.java @@ -1,6 +1,5 @@ package me.teridax.jcash.gui.login; -import me.teridax.jcash.banking.Account; import me.teridax.jcash.banking.BankingManagementSystem; import me.teridax.jcash.banking.Profile; diff --git a/src/me/teridax/jcash/gui/login/LoginView.java b/src/me/teridax/jcash/gui/login/LoginView.java index 5b1114f..6d869c0 100644 --- a/src/me/teridax/jcash/gui/login/LoginView.java +++ b/src/me/teridax/jcash/gui/login/LoginView.java @@ -1,18 +1,21 @@ package me.teridax.jcash.gui.login; import javax.swing.*; +import javax.swing.text.NumberFormatter; import java.awt.*; +import java.text.NumberFormat; public class LoginView extends JPanel { - private final JTextField blz; - private final JTextField iban; + private final JFormattedTextField blz; + private final JFormattedTextField iban; private final JPasswordField pin; private final JButton login; public LoginView() { - this.blz = new JTextField("MA2424"); - this.iban = new JTextField("4711"); + this.blz = new JFormattedTextField("MA2424"); + this.iban = new JFormattedTextField(getNumberFormat()); + this.iban.setText("4711"); this.pin = new JPasswordField("1234"); this.login = new JButton("Login"); @@ -41,6 +44,19 @@ public class LoginView extends JPanel { content.add(login, constraints); } + 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; @@ -71,5 +87,4 @@ public class LoginView extends JPanel { public JButton getLogin() { return login; } - } diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java new file mode 100644 index 0000000..e53bb25 --- /dev/null +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.takeoff; + +import me.teridax.jcash.banking.Account; + +public class TakeoffDialog { + + public TakeoffDialog(Account account, Runnable onDeposit) { + var view = new TakeoffView(account); + view.getDeposit().addActionListener(e -> { + account.takeoff(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java new file mode 100644 index 0000000..483ce19 --- /dev/null +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java @@ -0,0 +1,130 @@ +package me.teridax.jcash.gui.takeoff; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; + +public class TakeoffView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField value; + + public TakeoffView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat(double balance) { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(true); + formatter.setMaximum(balance); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Takeoff money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(cancel, c); + + c.gridx = 2; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(deposit, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Auszahlen"); + this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) { + showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); + return 0; + } + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +} diff --git a/src/me/teridax/jcash/gui/transfer/TransferDialog.java b/src/me/teridax/jcash/gui/transfer/TransferDialog.java new file mode 100644 index 0000000..0c56597 --- /dev/null +++ b/src/me/teridax/jcash/gui/transfer/TransferDialog.java @@ -0,0 +1,17 @@ +package me.teridax.jcash.gui.transfer; + +import me.teridax.jcash.banking.Account; + +public class TransferDialog { + + public TransferDialog(Account account, Runnable onDeposit) { + var view = new TransferView(account); + view.getDeposit().addActionListener(e -> { + account.takeoff(view.getAmount()); + onDeposit.run(); + view.dispose(); + }); + view.getCancel().addActionListener(e -> view.dispose()); + view.showDialog(); + } +} diff --git a/src/me/teridax/jcash/gui/transfer/TransferView.java b/src/me/teridax/jcash/gui/transfer/TransferView.java new file mode 100644 index 0000000..f69be5d --- /dev/null +++ b/src/me/teridax/jcash/gui/transfer/TransferView.java @@ -0,0 +1,168 @@ +package me.teridax.jcash.gui.transfer; + +import me.teridax.jcash.banking.Account; + +import javax.swing.*; +import javax.swing.text.NumberFormatter; +import java.awt.*; +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.showMessageDialog; + +public class TransferView { + + private JDialog dialog; + private JButton cancel; + private JButton deposit; + private JFormattedTextField iban; + private JFormattedTextField blz; + private JFormattedTextField value; + + public TransferView(Account account) { + createComponents(account); + layoutComponents(); + } + + public void showDialog() { + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setTitle("Deposit money"); + dialog.pack(); + dialog.setResizable(false); + dialog.setLocationRelativeTo(null); + dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + dialog.setVisible(true); + } + + private NumberFormatter getNumberFormat(double balance) { + var format = NumberFormat.getNumberInstance(Locale.GERMANY); + format.setParseIntegerOnly(false); + format.setMaximumFractionDigits(2); + + var formatter = new NumberFormatter(format); + formatter.setValueClass(Double.class); + formatter.setAllowsInvalid(true); + formatter.setMaximum(balance); + + return formatter; + } + + private void layoutComponents() { + dialog.getContentPane().setLayout(new GridBagLayout()); + + var c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + c.insets = new Insets(10, 10, 10, 10); + dialog.getContentPane().add(new JLabel("Takeoff money"), c); + + c.gridx = 0; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("BLZ", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(blz, c); + + c.gridx = 2; + c.gridy = 1; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("IBAN", SwingConstants.RIGHT), c); + + c.gridx = 3; + c.gridy = 1; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(iban, c); + + c.gridx = 0; + c.gridy = 2; + c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 0; + dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + + c.gridx = 1; + c.gridy = 2; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(value, c); + + c.gridx = 2; + c.gridy = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(cancel, c); + + c.gridx = 3; + c.gridy = 3; + c.fill = GridBagConstraints.HORIZONTAL; + c.anchor = GridBagConstraints.LAST_LINE_END; + c.insets = new Insets(10, 10, 10, 10); + c.weightx = 1; + dialog.getContentPane().add(deposit, c); + + dialog.getContentPane().add(value, c); + } + + private void createComponents(Account account) { + this.dialog = new JDialog(); + + this.cancel = new JButton("Abbrechen"); + this.deposit = new JButton("Auszahlen"); + this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + this.iban = new JFormattedTextField(); + this.blz = new JFormattedTextField(); + + this.dialog.setContentPane(new JPanel(new GridBagLayout())); + } + + public double getAmount() { + if (value.getText().isBlank()) { + showMessageDialog(null, "invalid amount", "currency must not be blank", ERROR_MESSAGE); + return 0; + } + + try { + return NumberFormat.getNumberInstance().parse(value.getText()).doubleValue(); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + public JButton getCancel() { + return cancel; + } + + public JButton getDeposit() { + return deposit; + } + + public void dispose() { + this.dialog.dispose(); + } +} -- 2.40.1 From b301f685a540ac510f9f0afba8d1ccd04abe6cf2 Mon Sep 17 00:00:00 2001 From: teridax Date: Sat, 1 Jul 2023 11:28:28 +0200 Subject: [PATCH 4/5] gui finished --- JCash.iml | 10 +++ src/me/teridax/jcash/Main.java | 60 +++++++++++----- src/me/teridax/jcash/banking/Account.java | 14 ++-- .../banking/BankingManagementSystem.java | 4 +- src/me/teridax/jcash/banking/Owner.java | 14 ++-- .../banking/{Testing.java => Tests.java} | 2 +- .../decode/{Decoder.java => StringUtils.java} | 50 ++++++++++++- src/me/teridax/jcash/gui/Loader.java | 19 ++++- .../jcash/gui/account/AccountController.java | 2 +- .../jcash/gui/account/AccountView.java | 27 +++---- .../jcash/gui/takeoff/TakeoffView.java | 16 +---- .../jcash/gui/transfer/TransferDialog.java | 2 +- .../jcash/gui/transfer/TransferView.java | 72 +++++++------------ 13 files changed, 179 insertions(+), 113 deletions(-) rename src/me/teridax/jcash/banking/{Testing.java => Tests.java} (95%) rename src/me/teridax/jcash/decode/{Decoder.java => StringUtils.java} (68%) diff --git a/JCash.iml b/JCash.iml index c90834f..c3dc060 100644 --- a/JCash.iml +++ b/JCash.iml @@ -7,5 +7,15 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java index 025f8d5..8eac9de 100644 --- a/src/me/teridax/jcash/Main.java +++ b/src/me/teridax/jcash/Main.java @@ -6,53 +6,79 @@ import me.teridax.jcash.gui.login.LoginController; import javax.swing.*; -public class Main { +public final class Main { + /** + * Main instance of this program. Contains the primary window. + */ private static Main instance; + + /** + * Primary window of this program + */ private final JFrame window; private Main() { - window = new JFrame(); - window.setTitle("Bankautomat"); - window.setLocationByPlatform(true); - window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + // create main window and set defaults + this.window = new JFrame(); + this.window.setTitle("Bankautomat"); + this.window.setLocationByPlatform(true); + this.window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String[] args) { + // create main instance and show the login screen instance(); - getInstance().popLoginScreen(); + getInstance().showLoginScreen(); } public static Main getInstance() { return instance; } + /** + * Attempts to create a new instance of the singleton class Main. + * This method throws an exception if the class is already instantiated. + * @throws IllegalStateException if the class is already instantiated + * @pre the static instance of this class should be null. + * @post the static instance of this class will be set + */ public static void instance() { - if (instance == null) { - instance = new Main(); - return; - } + if (null != instance) + throw new IllegalStateException(Main.class.getName() + " is already initialized"); - throw new IllegalStateException("me.teridax.jcash.Main is already initialized"); + Main.instance = new Main(); } - public void popLoginScreen() { + /** + * Shows the open dialog for selecting a database file. After selection, it then proceeds to prompt login. + * Afterward the selected account can be managed. + * This method is non-blocking and all work described is performed asynchronously on the AWT Event dispatcher. + */ + public void showLoginScreen() { SwingUtilities.invokeLater(() -> { + // select db file var path = Loader.load(); + // read database and login var login = new LoginController(path); + // when we have logged in set the account viewer as window content login.addAccountSelectionListener(account -> { var profileCont = new AccountController(account); - window.setContentPane(profileCont.getView()); - window.pack(); + this.window.setContentPane(profileCont.getView()); + this.window.pack(); }); - window.setContentPane(login.getView()); - window.pack(); - window.setVisible(true); + // we are not logged in yet, so show the login prompt on the main window + this.window.setContentPane(login.getView()); + this.window.pack(); + this.window.setVisible(true); }); } + /** + * Logs the user out of the database, hiding the main window. + */ public void logout() { window.setContentPane(new JLabel("you're logged out")); window.setVisible(false); diff --git a/src/me/teridax/jcash/banking/Account.java b/src/me/teridax/jcash/banking/Account.java index ec0ded5..bf4fc4f 100644 --- a/src/me/teridax/jcash/banking/Account.java +++ b/src/me/teridax/jcash/banking/Account.java @@ -1,6 +1,6 @@ package me.teridax.jcash.banking; -import me.teridax.jcash.decode.Decoder; +import me.teridax.jcash.decode.StringUtils; import java.util.Objects; @@ -20,17 +20,17 @@ public abstract class Account { public static Account fromColumns(String[] columns) { Objects.requireNonNull(columns); - var iban = Decoder.decodeUniqueIdentificationNumber(columns[0]); - var pin = Decoder.decodeUniqueIdentificationNumber(columns[1]); - var balance = Decoder.decodeCurrency(columns[2]); - var type = Decoder.decodeName(columns[3]); + var iban = StringUtils.decodeUniqueIdentificationNumber(columns[0]); + var pin = StringUtils.decodeUniqueIdentificationNumber(columns[1]); + var balance = StringUtils.decodeCurrency(columns[2]); + var type = StringUtils.decodeName(columns[3]); try { if (type.equals("Sparkonto")) { - var interest = Decoder.decodePercent(columns[4]); + var interest = StringUtils.decodePercent(columns[4]); return new SavingsAccount(iban, pin, balance, interest); } else if (type.equals("Girokonto")) { - var overdraft = Decoder.decodeCurrency(columns[5]); + var overdraft = StringUtils.decodeCurrency(columns[5]); return new Girokonto(iban, pin, balance, overdraft); } else { throw new IllegalArgumentException("Invalid account type: " + type); diff --git a/src/me/teridax/jcash/banking/BankingManagementSystem.java b/src/me/teridax/jcash/banking/BankingManagementSystem.java index c296c18..57fe941 100644 --- a/src/me/teridax/jcash/banking/BankingManagementSystem.java +++ b/src/me/teridax/jcash/banking/BankingManagementSystem.java @@ -1,6 +1,6 @@ package me.teridax.jcash.banking; -import me.teridax.jcash.decode.Decoder; +import me.teridax.jcash.decode.StringUtils; import java.io.IOException; import java.nio.file.Files; @@ -34,7 +34,7 @@ public final class BankingManagementSystem { var account = Account.fromColumns(tail(columns, 2)); var blz = Bank.validateBlz(columns[1]); - var name = Decoder.decodeName(columns[0]); + var name = StringUtils.decodeName(columns[0]); var bankOfLine = new Bank(blz, name); var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst(); diff --git a/src/me/teridax/jcash/banking/Owner.java b/src/me/teridax/jcash/banking/Owner.java index 07b1bab..5497df1 100644 --- a/src/me/teridax/jcash/banking/Owner.java +++ b/src/me/teridax/jcash/banking/Owner.java @@ -1,6 +1,6 @@ package me.teridax.jcash.banking; -import me.teridax.jcash.decode.Decoder; +import me.teridax.jcash.decode.StringUtils; import java.util.Objects; @@ -28,12 +28,12 @@ public final class Owner { if (columns.length != 6) throw new IllegalArgumentException("Invalid number of columns: " + columns.length); - var uid = Decoder.decodeUniqueIdentificationNumber(columns[0]); - var familyName = Decoder.decodeName(columns[1]); - var name = Decoder.decodeName(columns[2]); - var street = Decoder.decodeStreet(columns[3]); - var zip = Decoder.decodeUniqueIdentificationNumber(columns[4]); - var city = Decoder.decodeName(columns[5]); + var uid = StringUtils.decodeUniqueIdentificationNumber(columns[0]); + var familyName = StringUtils.decodeName(columns[1]); + var name = StringUtils.decodeName(columns[2]); + var street = StringUtils.decodeStreet(columns[3]); + var zip = StringUtils.decodeUniqueIdentificationNumber(columns[4]); + var city = StringUtils.decodeName(columns[5]); return new Owner(uid, familyName, name, zip, city, street); } diff --git a/src/me/teridax/jcash/banking/Testing.java b/src/me/teridax/jcash/banking/Tests.java similarity index 95% rename from src/me/teridax/jcash/banking/Testing.java rename to src/me/teridax/jcash/banking/Tests.java index dee3fa9..ab644fb 100644 --- a/src/me/teridax/jcash/banking/Testing.java +++ b/src/me/teridax/jcash/banking/Tests.java @@ -4,7 +4,7 @@ import org.junit.Test; import java.nio.file.Paths; -public class Testing { +public class Tests { @Test public void test() { diff --git a/src/me/teridax/jcash/decode/Decoder.java b/src/me/teridax/jcash/decode/StringUtils.java similarity index 68% rename from src/me/teridax/jcash/decode/Decoder.java rename to src/me/teridax/jcash/decode/StringUtils.java index 4be4189..5145466 100644 --- a/src/me/teridax/jcash/decode/Decoder.java +++ b/src/me/teridax/jcash/decode/StringUtils.java @@ -10,11 +10,29 @@ import java.util.regex.Pattern; import static junit.framework.TestCase.assertEquals; -public class Decoder { +/** + * Utility class for converting various single line strings into a specific data type according + * to a format mostly dictated by a locale. + */ +public class StringUtils { + /** + * Locale to use when converting strings + */ private static final Locale LOCALE = Locale.GERMANY; + /** + * NumberFormat to use when converting strings + */ public static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE); + /** + * Attempts to convert the given string into a double value representing a percentage. + * The percentage is stored in the range [0,1] and can linearly be mapped to [0, 100] by multiplying with 100. + * @param number the string to convert + * @return the double value + * @throws IllegalArgumentException when the format is invalid + * @throws NullPointerException when the argument is null + */ public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(number); @@ -28,6 +46,13 @@ public class Decoder { } } + /** + * Attempts to convert the given string into a currency value. + * @param currency the string to convert + * @return the double value + * @throws IllegalArgumentException when the format is invalid + * @throws NullPointerException when the argument is null + */ public static double decodeCurrency(String currency) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(currency); @@ -38,6 +63,14 @@ public class Decoder { } } + /** + * Attempts to convert the given string into universally unique number. + * This function does not check for duplicates. The number must be a positive integer. + * @param number the string to convert + * @return the integer serial number + * @throws IllegalArgumentException when the format is invalid + * @throws NullPointerException when the argument is null + */ public static int decodeUniqueIdentificationNumber(String number) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(number); @@ -56,6 +89,14 @@ public class Decoder { } } + /** + * Attempts to convert the given string into a name. + * This method performs validation and trimming. + * @param name the string to convert + * @return the qualified name + * @throws IllegalArgumentException when the format is invalid + * @throws NullPointerException when the argument is null + */ public static String decodeName(String name) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(name); @@ -70,6 +111,13 @@ public class Decoder { } } + /** + * Attempts to convert the given string into a street and an optional house address. + * @param street the string to convert + * @return the address name + * @throws IllegalArgumentException when the format is invalid + * @throws NullPointerException when the argument is null + */ public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException { Objects.requireNonNull(street); diff --git a/src/me/teridax/jcash/gui/Loader.java b/src/me/teridax/jcash/gui/Loader.java index 28a9d15..f12593d 100644 --- a/src/me/teridax/jcash/gui/Loader.java +++ b/src/me/teridax/jcash/gui/Loader.java @@ -6,10 +6,26 @@ import javax.swing.*; import javax.swing.filechooser.FileNameExtensionFilter; import java.io.File; +import static javax.swing.JFileChooser.APPROVE_OPTION; + +/** + * Utility class for loading a BMS configuration from a csv file. + */ public class Loader { + /** + * Filter that only allows for files with *.csv extension + */ private static final FileNameExtensionFilter FILE_FILTER = new FileNameExtensionFilter("Comma separated value spreadsheet", "csv", "CSV"); + private Loader() {} + + /** + * Load a BMS from a csv file. Opens up a dialog which prompts the user to select a single file. + * Once the file is selected this function will try to parse the contents to a BMS and return the instance. + * @return a valid BMS instance loaded from a file + * @throws IllegalStateException When either no file is selected or the selected files content is invalid + */ public static BankingManagementSystem load() throws IllegalStateException { var fileChooser = new JFileChooser(); fileChooser.setMultiSelectionEnabled(false); @@ -19,7 +35,8 @@ public class Loader { fileChooser.setAcceptAllFileFilterUsed(false); fileChooser.setCurrentDirectory(new File("/home/teridax/IdeaProjects/JCash/res")); - if (fileChooser.showDialog(null, "Load database") == JFileChooser.APPROVE_OPTION) { + if (fileChooser.showDialog(null, "Load database") == APPROVE_OPTION) { + // parse file content try { return BankingManagementSystem.loadFromCsv(fileChooser.getSelectedFile().toPath()); } catch (Exception e) { diff --git a/src/me/teridax/jcash/gui/account/AccountController.java b/src/me/teridax/jcash/gui/account/AccountController.java index 9f9aa07..ab849b1 100644 --- a/src/me/teridax/jcash/gui/account/AccountController.java +++ b/src/me/teridax/jcash/gui/account/AccountController.java @@ -26,7 +26,7 @@ public class AccountController { this.view.getLogout().addActionListener(e -> { Main.getInstance().logout(); - Main.getInstance().popLoginScreen(); + Main.getInstance().showLoginScreen(); }); this.view.getDeposit().addActionListener(e -> { diff --git a/src/me/teridax/jcash/gui/account/AccountView.java b/src/me/teridax/jcash/gui/account/AccountView.java index 4f1364d..4b5af30 100644 --- a/src/me/teridax/jcash/gui/account/AccountView.java +++ b/src/me/teridax/jcash/gui/account/AccountView.java @@ -1,7 +1,7 @@ package me.teridax.jcash.gui.account; import me.teridax.jcash.banking.*; -import me.teridax.jcash.decode.Decoder; +import me.teridax.jcash.decode.StringUtils; import javax.swing.*; import java.awt.*; @@ -22,7 +22,6 @@ public class AccountView extends JPanel { private JComboBox accountSelection; private JPanel content; - private JPanel buttonPanel; private JButton logout; private JButton transfer; @@ -48,12 +47,12 @@ public class AccountView extends JPanel { this.name.setText(owner.getName() + " " + owner.getFamilyName()); this.address.setText(owner.getStreet() + " " + owner.getCity()); - this.balance.setText(Decoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + " €"); + this.balance.setText(StringUtils.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + " €"); this.type.setText(account.getClass().getSimpleName()); if (account instanceof Girokonto) { this.typeSpecialLabel.setText("Überziehungsbetrag"); - this.typeSpecialProperty.setText( Decoder.LOCAL_NUMBER_FORMAT.format(((Girokonto) account).getOverdraft()) + " €"); + this.typeSpecialProperty.setText( StringUtils.LOCAL_NUMBER_FORMAT.format(((Girokonto) account).getOverdraft()) + " €"); } else if (account instanceof SavingsAccount) { this.typeSpecialLabel.setText("Zinsbetrag"); this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); @@ -70,7 +69,6 @@ public class AccountView extends JPanel { private void createLayout() { setLayout(new BorderLayout(16, 16)); add(new JScrollPane(content), BorderLayout.CENTER); - add(buttonPanel, BorderLayout.SOUTH); content.setLayout(new GridBagLayout()); var constraints = new GridBagConstraints(); @@ -91,13 +89,17 @@ public class AccountView extends JPanel { addInputRow(constraints, content, typeSpecialProperty, 7, typeSpecialLabel); addInputRow(constraints, content, balance, 8, new JLabel("Kontostand", SwingConstants.RIGHT)); - var buttonRightPanel = new JPanel(); - buttonRightPanel.add(transfer); - buttonRightPanel.add(deposit); - buttonRightPanel.add(takeoff); - - buttonPanel.add(logout, BorderLayout.LINE_START); - buttonPanel.add(buttonRightPanel, BorderLayout.LINE_END); + var buttonPanel = Box.createHorizontalBox(); + buttonPanel.add(Box.createHorizontalStrut(4)); + buttonPanel.add(logout); + buttonPanel.add(Box.createHorizontalStrut(4)); + buttonPanel.add(Box.createGlue()); + buttonPanel.add(transfer); + buttonPanel.add(Box.createHorizontalStrut(4)); + buttonPanel.add(deposit); + buttonPanel.add(Box.createHorizontalStrut(4)); + buttonPanel.add(takeoff); + add(buttonPanel, BorderLayout.SOUTH); } private void createComponents() { @@ -124,7 +126,6 @@ public class AccountView extends JPanel { this.accountSelection = new JComboBox<>(); this.content = new JPanel(); - this.buttonPanel = new JPanel(new BorderLayout()); this.logout = new JButton("Abmelden"); this.transfer = new JButton("Überweisen"); diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java index 483ce19..9a77720 100644 --- a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java @@ -1,6 +1,7 @@ package me.teridax.jcash.gui.takeoff; import me.teridax.jcash.banking.Account; +import me.teridax.jcash.decode.StringUtils; import javax.swing.*; import javax.swing.text.NumberFormatter; @@ -34,19 +35,6 @@ public class TakeoffView { dialog.setVisible(true); } - private NumberFormatter getNumberFormat(double balance) { - var format = NumberFormat.getNumberInstance(Locale.GERMANY); - format.setParseIntegerOnly(false); - format.setMaximumFractionDigits(2); - - var formatter = new NumberFormatter(format); - formatter.setValueClass(Double.class); - formatter.setAllowsInvalid(true); - formatter.setMaximum(balance); - - return formatter; - } - private void layoutComponents() { dialog.getContentPane().setLayout(new GridBagLayout()); @@ -98,7 +86,7 @@ public class TakeoffView { this.cancel = new JButton("Abbrechen"); this.deposit = new JButton("Auszahlen"); - this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + this.value = new JFormattedTextField(StringUtils.LOCAL_NUMBER_FORMAT); this.dialog.setContentPane(new JPanel(new GridBagLayout())); } diff --git a/src/me/teridax/jcash/gui/transfer/TransferDialog.java b/src/me/teridax/jcash/gui/transfer/TransferDialog.java index 0c56597..9f3aa4d 100644 --- a/src/me/teridax/jcash/gui/transfer/TransferDialog.java +++ b/src/me/teridax/jcash/gui/transfer/TransferDialog.java @@ -6,7 +6,7 @@ public class TransferDialog { public TransferDialog(Account account, Runnable onDeposit) { var view = new TransferView(account); - view.getDeposit().addActionListener(e -> { + view.getTransfer().addActionListener(e -> { account.takeoff(view.getAmount()); onDeposit.run(); view.dispose(); diff --git a/src/me/teridax/jcash/gui/transfer/TransferView.java b/src/me/teridax/jcash/gui/transfer/TransferView.java index f69be5d..80b00ee 100644 --- a/src/me/teridax/jcash/gui/transfer/TransferView.java +++ b/src/me/teridax/jcash/gui/transfer/TransferView.java @@ -1,13 +1,12 @@ package me.teridax.jcash.gui.transfer; import me.teridax.jcash.banking.Account; +import me.teridax.jcash.decode.StringUtils; import javax.swing.*; -import javax.swing.text.NumberFormatter; import java.awt.*; import java.text.NumberFormat; import java.text.ParseException; -import java.util.Locale; import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.showMessageDialog; @@ -16,7 +15,7 @@ public class TransferView { private JDialog dialog; private JButton cancel; - private JButton deposit; + private JButton transfer; private JFormattedTextField iban; private JFormattedTextField blz; private JFormattedTextField value; @@ -28,45 +27,33 @@ public class TransferView { public void showDialog() { dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); - dialog.setTitle("Deposit money"); + dialog.setTitle("Transfer money"); dialog.pack(); + dialog.setSize(dialog.getWidth() * 2, dialog.getHeight()); dialog.setResizable(false); dialog.setLocationRelativeTo(null); dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); dialog.setVisible(true); } - private NumberFormatter getNumberFormat(double balance) { - var format = NumberFormat.getNumberInstance(Locale.GERMANY); - format.setParseIntegerOnly(false); - format.setMaximumFractionDigits(2); - - var formatter = new NumberFormatter(format); - formatter.setValueClass(Double.class); - formatter.setAllowsInvalid(true); - formatter.setMaximum(balance); - - return formatter; - } - private void layoutComponents() { - dialog.getContentPane().setLayout(new GridBagLayout()); - var c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; - c.fill = GridBagConstraints.BOTH; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.CENTER; - c.insets = new Insets(10, 10, 10, 10); - dialog.getContentPane().add(new JLabel("Takeoff money"), c); + c.insets = new Insets(4, 4, 4, 4); + dialog.getContentPane().add(new JLabel("Transfer money"), c); c.gridx = 0; c.gridy = 1; + c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 0; dialog.getContentPane().add(new JLabel("BLZ", SwingConstants.RIGHT), c); @@ -74,15 +61,13 @@ public class TransferView { c.gridy = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; + c.weightx = 0.5; dialog.getContentPane().add(blz, c); c.gridx = 2; c.gridy = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 0; dialog.getContentPane().add(new JLabel("IBAN", SwingConstants.RIGHT), c); @@ -90,7 +75,6 @@ public class TransferView { c.gridy = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 1; dialog.getContentPane().add(iban, c); @@ -98,7 +82,6 @@ public class TransferView { c.gridy = 2; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 0; dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); @@ -106,35 +89,28 @@ public class TransferView { c.gridy = 2; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; + c.weightx = 0.5; dialog.getContentPane().add(value, c); - c.gridx = 2; + var buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.add(cancel); + buttonPanel.add(transfer); + + c.gridx = 0; c.gridy = 3; + c.gridwidth = 4; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; - dialog.getContentPane().add(cancel, c); - - c.gridx = 3; - c.gridy = 3; - c.fill = GridBagConstraints.HORIZONTAL; - c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; - dialog.getContentPane().add(deposit, c); - - dialog.getContentPane().add(value, c); + dialog.getContentPane().add(buttonPanel, c); } private void createComponents(Account account) { this.dialog = new JDialog(); - this.cancel = new JButton("Abbrechen"); - this.deposit = new JButton("Auszahlen"); - this.value = new JFormattedTextField(getNumberFormat(account.getBalance())); + this.cancel = new JButton("Cancel"); + this.transfer = new JButton("Transfer"); + this.value = new JFormattedTextField(StringUtils.LOCAL_NUMBER_FORMAT); this.iban = new JFormattedTextField(); this.blz = new JFormattedTextField(); @@ -158,8 +134,8 @@ public class TransferView { return cancel; } - public JButton getDeposit() { - return deposit; + public JButton getTransfer() { + return transfer; } public void dispose() { -- 2.40.1 From 0c19489b1fe9fb5a98ff65235d5d6253558efbf7 Mon Sep 17 00:00:00 2001 From: teridax Date: Sat, 1 Jul 2023 12:47:49 +0200 Subject: [PATCH 5/5] fixed unhandled exception --- src/me/teridax/jcash/Main.java | 34 ++++++----- .../jcash/gui/account/AccountView.java | 22 +++---- .../jcash/gui/deposit/DepositView.java | 59 ++++++++----------- .../jcash/gui/takeoff/TakeoffDialog.java | 6 +- .../jcash/gui/takeoff/TakeoffView.java | 54 ++++++++--------- 5 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/me/teridax/jcash/Main.java b/src/me/teridax/jcash/Main.java index 8eac9de..75463e8 100644 --- a/src/me/teridax/jcash/Main.java +++ b/src/me/teridax/jcash/Main.java @@ -57,22 +57,28 @@ public final class Main { */ public void showLoginScreen() { SwingUtilities.invokeLater(() -> { - // select db file - var path = Loader.load(); - // read database and login - var login = new LoginController(path); + try { + // select db file + var path = Loader.load(); + // read database and login + var login = new LoginController(path); - // when we have logged in set the account viewer as window content - login.addAccountSelectionListener(account -> { - var profileCont = new AccountController(account); - this.window.setContentPane(profileCont.getView()); - this.window.pack(); - }); + // when we have logged in set the account viewer as window content + login.addAccountSelectionListener(account -> { + var profileCont = new AccountController(account); + this.window.setContentPane(profileCont.getView()); + this.window.revalidate(); + this.window.repaint(); + }); - // we are not logged in yet, so show the login prompt on the main window - this.window.setContentPane(login.getView()); - this.window.pack(); - this.window.setVisible(true); + // we are not logged in yet, so show the login prompt on the main window + this.window.setContentPane(login.getView()); + this.window.setSize(800, 600); + this.window.setVisible(true); + + } catch (IllegalStateException e) { + System.out.println("no file selected. goodbye"); + } }); } diff --git a/src/me/teridax/jcash/gui/account/AccountView.java b/src/me/teridax/jcash/gui/account/AccountView.java index 4b5af30..ecdf560 100644 --- a/src/me/teridax/jcash/gui/account/AccountView.java +++ b/src/me/teridax/jcash/gui/account/AccountView.java @@ -51,10 +51,10 @@ public class AccountView extends JPanel { this.type.setText(account.getClass().getSimpleName()); if (account instanceof Girokonto) { - this.typeSpecialLabel.setText("Überziehungsbetrag"); + this.typeSpecialLabel.setText("Overdraft"); this.typeSpecialProperty.setText( StringUtils.LOCAL_NUMBER_FORMAT.format(((Girokonto) account).getOverdraft()) + " €"); } else if (account instanceof SavingsAccount) { - this.typeSpecialLabel.setText("Zinsbetrag"); + this.typeSpecialLabel.setText("Interest rate"); this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); } @@ -80,14 +80,14 @@ public class AccountView extends JPanel { accountSelectionPanel.add(iban, BorderLayout.CENTER); accountSelectionPanel.add(accountSelection, BorderLayout.EAST); - addInputRow(constraints, content, accountSelectionPanel, 1, new JLabel("Kontonummer", SwingConstants.RIGHT)); - addInputRow(constraints, content, name, 2, new JLabel("Vorname/Nachname", SwingConstants.RIGHT)); - addInputRow(constraints, content, address, 3, new JLabel("Adresse", SwingConstants.RIGHT)); + addInputRow(constraints, content, accountSelectionPanel, 1, new JLabel("IBAN", SwingConstants.RIGHT)); + addInputRow(constraints, content, name, 2, new JLabel("Name/Family-name", SwingConstants.RIGHT)); + addInputRow(constraints, content, address, 3, new JLabel("Address", SwingConstants.RIGHT)); addInputRow(constraints, content, bankName, 4, new JLabel("Bank", SwingConstants.RIGHT)); addInputRow(constraints, content, blz, 5, new JLabel("BLZ", SwingConstants.RIGHT)); - addInputRow(constraints, content, type, 6, new JLabel("Konto", SwingConstants.RIGHT)); + addInputRow(constraints, content, type, 6, new JLabel("Account", SwingConstants.RIGHT)); addInputRow(constraints, content, typeSpecialProperty, 7, typeSpecialLabel); - addInputRow(constraints, content, balance, 8, new JLabel("Kontostand", SwingConstants.RIGHT)); + addInputRow(constraints, content, balance, 8, new JLabel("Balance", SwingConstants.RIGHT)); var buttonPanel = Box.createHorizontalBox(); buttonPanel.add(Box.createHorizontalStrut(4)); @@ -127,10 +127,10 @@ public class AccountView extends JPanel { this.content = new JPanel(); - this.logout = new JButton("Abmelden"); - this.transfer = new JButton("Überweisen"); - this.deposit = new JButton("Einzahlen"); - this.takeoff = new JButton("Abheben"); + this.logout = new JButton("Logout"); + this.transfer = new JButton("Transfer"); + this.deposit = new JButton("Deposit"); + this.takeoff = new JButton("Takeoff"); } private void addInputRow(GridBagConstraints constraints, JComponent target, JComponent comp, int row, JLabel label) { diff --git a/src/me/teridax/jcash/gui/deposit/DepositView.java b/src/me/teridax/jcash/gui/deposit/DepositView.java index 7415a92..06529cc 100644 --- a/src/me/teridax/jcash/gui/deposit/DepositView.java +++ b/src/me/teridax/jcash/gui/deposit/DepositView.java @@ -1,13 +1,12 @@ package me.teridax.jcash.gui.deposit; import me.teridax.jcash.banking.Account; +import me.teridax.jcash.decode.StringUtils; import javax.swing.*; -import javax.swing.text.NumberFormatter; import java.awt.*; import java.text.NumberFormat; import java.text.ParseException; -import java.util.Locale; public class DepositView { @@ -31,70 +30,62 @@ public class DepositView { dialog.setVisible(true); } - private NumberFormatter getNumberFormat() { - var format = NumberFormat.getNumberInstance(Locale.GERMANY); - format.setParseIntegerOnly(false); - format.setMaximumFractionDigits(2); - - var formatter = new NumberFormatter(format); - formatter.setValueClass(Double.class); - formatter.setAllowsInvalid(false); - - return formatter; - } - private void layoutComponents() { dialog.getContentPane().setLayout(new GridBagLayout()); var c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; - c.fill = GridBagConstraints.BOTH; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.CENTER; - c.insets = new Insets(10, 10, 10, 10); + c.insets = new Insets(4, 4, 4, 4); dialog.getContentPane().add(new JLabel("Deposit money"), c); c.gridx = 0; c.gridy = 1; + c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 0; - dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + dialog.getContentPane().add(new JLabel("Value", SwingConstants.RIGHT), c); c.gridx = 1; c.gridy = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; + c.weightx = 0.5; dialog.getContentPane().add(value, c); - c.gridx = 1; - c.gridy = 2; - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 0; - dialog.getContentPane().add(cancel, c); - c.gridx = 2; - c.gridy = 2; + c.gridy = 1; c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.weightx = 0; + dialog.getContentPane().add(new JLabel("€"), c); + + var buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.add(cancel); + buttonPanel.add(deposit); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; c.insets = new Insets(10, 10, 10, 10); - c.weightx = 0; - dialog.getContentPane().add(deposit, c); + dialog.getContentPane().add(buttonPanel, c); } private void createComponents(Account account) { this.dialog = new JDialog(); - this.cancel = new JButton("Abbrechen"); - this.deposit = new JButton("Einzahlen"); - this.value = new JFormattedTextField(getNumberFormat()); + this.cancel = new JButton("Cancel"); + this.deposit = new JButton("Deposit"); + this.value = new JFormattedTextField(StringUtils.LOCAL_NUMBER_FORMAT); this.dialog.setContentPane(new JPanel(new GridBagLayout())); } diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java index e53bb25..44e05c6 100644 --- a/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffDialog.java @@ -4,11 +4,11 @@ import me.teridax.jcash.banking.Account; public class TakeoffDialog { - public TakeoffDialog(Account account, Runnable onDeposit) { + public TakeoffDialog(Account account, Runnable onTakeoff) { var view = new TakeoffView(account); - view.getDeposit().addActionListener(e -> { + view.getTakeoff().addActionListener(e -> { account.takeoff(view.getAmount()); - onDeposit.run(); + onTakeoff.run(); view.dispose(); }); view.getCancel().addActionListener(e -> view.dispose()); diff --git a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java index 9a77720..4eed846 100644 --- a/src/me/teridax/jcash/gui/takeoff/TakeoffView.java +++ b/src/me/teridax/jcash/gui/takeoff/TakeoffView.java @@ -4,11 +4,9 @@ import me.teridax.jcash.banking.Account; import me.teridax.jcash.decode.StringUtils; import javax.swing.*; -import javax.swing.text.NumberFormatter; import java.awt.*; import java.text.NumberFormat; import java.text.ParseException; -import java.util.Locale; import static javax.swing.JOptionPane.ERROR_MESSAGE; import static javax.swing.JOptionPane.showMessageDialog; @@ -17,7 +15,7 @@ public class TakeoffView { private JDialog dialog; private JButton cancel; - private JButton deposit; + private JButton takeoff; private JFormattedTextField value; public TakeoffView(Account account) { @@ -27,7 +25,7 @@ public class TakeoffView { public void showDialog() { dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); - dialog.setTitle("Deposit money"); + dialog.setTitle("Takeoff money"); dialog.pack(); dialog.setResizable(false); dialog.setLocationRelativeTo(null); @@ -36,56 +34,58 @@ public class TakeoffView { } private void layoutComponents() { - dialog.getContentPane().setLayout(new GridBagLayout()); - var c = new GridBagConstraints(); + c.gridx = 0; c.gridy = 0; c.weightx = 1; c.weighty = 1; - c.fill = GridBagConstraints.BOTH; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.CENTER; - c.insets = new Insets(10, 10, 10, 10); + c.insets = new Insets(4, 4, 4, 4); dialog.getContentPane().add(new JLabel("Takeoff money"), c); c.gridx = 0; c.gridy = 1; + c.gridwidth = 1; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); c.weightx = 0; - dialog.getContentPane().add(new JLabel("Betrag", SwingConstants.RIGHT), c); + dialog.getContentPane().add(new JLabel("Value", SwingConstants.RIGHT), c); c.gridx = 1; c.gridy = 1; c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 1; + c.weightx = 0.5; dialog.getContentPane().add(value, c); - c.gridx = 1; - c.gridy = 2; - c.fill = GridBagConstraints.NONE; - c.anchor = GridBagConstraints.LAST_LINE_END; - c.insets = new Insets(10, 10, 10, 10); - c.weightx = 0; - dialog.getContentPane().add(cancel, c); - c.gridx = 2; - c.gridy = 2; + c.gridy = 1; c.fill = GridBagConstraints.NONE; + c.anchor = GridBagConstraints.LINE_START; + c.weightx = 0; + dialog.getContentPane().add(new JLabel("€"), c); + + var buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.add(cancel); + buttonPanel.add(takeoff); + + c.gridx = 0; + c.gridy = 2; + c.gridwidth = 3; + c.fill = GridBagConstraints.HORIZONTAL; c.anchor = GridBagConstraints.LAST_LINE_END; c.insets = new Insets(10, 10, 10, 10); - c.weightx = 0; - dialog.getContentPane().add(deposit, c); + dialog.getContentPane().add(buttonPanel, c); } private void createComponents(Account account) { this.dialog = new JDialog(); - this.cancel = new JButton("Abbrechen"); - this.deposit = new JButton("Auszahlen"); + this.cancel = new JButton("Cancel"); + this.takeoff = new JButton("Takeoff"); this.value = new JFormattedTextField(StringUtils.LOCAL_NUMBER_FORMAT); this.dialog.setContentPane(new JPanel(new GridBagLayout())); @@ -108,8 +108,8 @@ public class TakeoffView { return cancel; } - public JButton getDeposit() { - return deposit; + public JButton getTakeoff() { + return takeoff; } public void dispose() { -- 2.40.1