gui #1
10
JCash.iml
10
JCash.iml
|
@ -7,5 +7,15 @@
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module-library">
|
||||||
|
<library name="JUnit4">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/junit/junit/4.13.1/junit-4.13.1.jar!/" />
|
||||||
|
<root url="jar://$MAVEN_REPOSITORY$/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</orderEntry>
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -1,5 +0,0 @@
|
||||||
public class Main {
|
|
||||||
public static void main(String[] args) {
|
|
||||||
System.out.println("Hello world!");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
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 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() {
|
||||||
|
// 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().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 (null != instance)
|
||||||
|
throw new IllegalStateException(Main.class.getName() + " is already initialized");
|
||||||
|
|
||||||
|
Main.instance = new Main();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(() -> {
|
||||||
|
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.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.setSize(800, 600);
|
||||||
|
this.window.setVisible(true);
|
||||||
|
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
System.out.println("no file selected. goodbye");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package me.teridax.jcash.banking;
|
package me.teridax.jcash.banking;
|
||||||
|
|
||||||
import me.teridax.jcash.decode.Decoder;
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ public abstract class Account {
|
||||||
|
|
||||||
private final int iban;
|
private final int iban;
|
||||||
private final int pin;
|
private final int pin;
|
||||||
private final double balance;
|
private double balance;
|
||||||
|
|
||||||
public Account(int iban, int pin, double balance) {
|
public Account(int iban, int pin, double balance) {
|
||||||
this.iban = iban;
|
this.iban = iban;
|
||||||
|
@ -20,17 +20,17 @@ public abstract class Account {
|
||||||
public static Account fromColumns(String[] columns) {
|
public static Account fromColumns(String[] columns) {
|
||||||
Objects.requireNonNull(columns);
|
Objects.requireNonNull(columns);
|
||||||
|
|
||||||
var iban = Decoder.decodeUniqueIdentificationNumber(columns[0]);
|
var iban = StringUtils.decodeUniqueIdentificationNumber(columns[0]);
|
||||||
var pin = Decoder.decodeUniqueIdentificationNumber(columns[1]);
|
var pin = StringUtils.decodeUniqueIdentificationNumber(columns[1]);
|
||||||
var balance = Decoder.decodeCurrency(columns[2]);
|
var balance = StringUtils.decodeCurrency(columns[2]);
|
||||||
var type = Decoder.decodeName(columns[3]);
|
var type = StringUtils.decodeName(columns[3]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (type.equals("Sparkonto")) {
|
if (type.equals("Sparkonto")) {
|
||||||
var interest = Decoder.decodePercent(columns[4]);
|
var interest = StringUtils.decodePercent(columns[4]);
|
||||||
return new SavingsAccount(iban, pin, balance, interest);
|
return new SavingsAccount(iban, pin, balance, interest);
|
||||||
} else if (type.equals("Girokonto")) {
|
} else if (type.equals("Girokonto")) {
|
||||||
var overdraft = Decoder.decodeCurrency(columns[5]);
|
var overdraft = StringUtils.decodeCurrency(columns[5]);
|
||||||
return new Girokonto(iban, pin, balance, overdraft);
|
return new Girokonto(iban, pin, balance, overdraft);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Invalid account type: " + type);
|
throw new IllegalArgumentException("Invalid account type: " + type);
|
||||||
|
@ -64,4 +64,21 @@ public abstract class Account {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package me.teridax.jcash.banking;
|
package me.teridax.jcash.banking;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class Bank {
|
public final class Bank {
|
||||||
|
@ -46,14 +47,24 @@ public final class Bank {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String validateBlz(String maybeBlz) {
|
public static String validateBlz(String maybeBlz) {
|
||||||
var builder = new StringBuilder();
|
var pattern = Pattern.compile("[\\w\\d-_]+");
|
||||||
maybeBlz.trim().chars().filter(ch -> Character.isDigit(ch) || Character.isLetter(ch)).forEach(builder::append);
|
var matcher = pattern.matcher(maybeBlz);
|
||||||
var blz = builder.toString();
|
|
||||||
|
|
||||||
if (blz.isEmpty()) {
|
if (matcher.find())
|
||||||
throw new IllegalArgumentException("Bank Blz must only contain letters and digits");
|
return matcher.group();
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("not a valid BLZ: " + maybeBlz);
|
||||||
}
|
}
|
||||||
|
|
||||||
return blz;
|
public Optional<Profile> getAccount(int iban) {
|
||||||
|
for (var owner : this.accounts.entrySet()) {
|
||||||
|
for (var account : owner.getValue()) {
|
||||||
|
var tmp = account.getIban();
|
||||||
|
if (tmp == iban) {
|
||||||
|
return Optional.of(new Profile(owner.getKey(), this, account, getAccountsOfOwner(owner.getKey())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package me.teridax.jcash.banking;
|
package me.teridax.jcash.banking;
|
||||||
|
|
||||||
import me.teridax.jcash.decode.Decoder;
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -34,7 +34,7 @@ public final class BankingManagementSystem {
|
||||||
var account = Account.fromColumns(tail(columns, 2));
|
var account = Account.fromColumns(tail(columns, 2));
|
||||||
|
|
||||||
var blz = Bank.validateBlz(columns[1]);
|
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 bankOfLine = new Bank(blz, name);
|
||||||
|
|
||||||
var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst();
|
var bankOfSet = bms.banks.stream().filter(b -> b.equals(bankOfLine)).findFirst();
|
||||||
|
@ -54,4 +54,8 @@ public final class BankingManagementSystem {
|
||||||
throw new IllegalArgumentException("Could not parse file " + file, e);
|
throw new IllegalArgumentException("Could not parse file " + file, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Bank> getBank(String blz) {
|
||||||
|
return this.banks.stream().filter(b -> b.getBlz().equals(blz)).findFirst();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package me.teridax.jcash.banking;
|
package me.teridax.jcash.banking;
|
||||||
|
|
||||||
import me.teridax.jcash.decode.Decoder;
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ public final class Owner {
|
||||||
if (columns.length != 6)
|
if (columns.length != 6)
|
||||||
throw new IllegalArgumentException("Invalid number of columns: " + columns.length);
|
throw new IllegalArgumentException("Invalid number of columns: " + columns.length);
|
||||||
|
|
||||||
var uid = Decoder.decodeUniqueIdentificationNumber(columns[0]);
|
var uid = StringUtils.decodeUniqueIdentificationNumber(columns[0]);
|
||||||
var familyName = Decoder.decodeName(columns[1]);
|
var familyName = StringUtils.decodeName(columns[1]);
|
||||||
var name = Decoder.decodeName(columns[2]);
|
var name = StringUtils.decodeName(columns[2]);
|
||||||
var street = Decoder.decodeStreet(columns[3]);
|
var street = StringUtils.decodeStreet(columns[3]);
|
||||||
var zip = Decoder.decodeUniqueIdentificationNumber(columns[4]);
|
var zip = StringUtils.decodeUniqueIdentificationNumber(columns[4]);
|
||||||
var city = Decoder.decodeName(columns[5]);
|
var city = StringUtils.decodeName(columns[5]);
|
||||||
|
|
||||||
return new Owner(uid, familyName, name, zip, city, street);
|
return new Owner(uid, familyName, name, zip, city, street);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
public class Testing {
|
public class Tests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
|
@ -10,11 +10,29 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertEquals;
|
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;
|
private static final Locale LOCALE = Locale.GERMANY;
|
||||||
private static final NumberFormat LOCAL_NUMBER_FORMAT = NumberFormat.getInstance(LOCALE);
|
/**
|
||||||
|
* 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 {
|
public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException {
|
||||||
Objects.requireNonNull(number);
|
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 {
|
public static double decodeCurrency(String currency) throws IllegalArgumentException, NullPointerException {
|
||||||
Objects.requireNonNull(currency);
|
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 {
|
public static int decodeUniqueIdentificationNumber(String number) throws IllegalArgumentException, NullPointerException {
|
||||||
Objects.requireNonNull(number);
|
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 {
|
public static String decodeName(String name) throws IllegalArgumentException, NullPointerException {
|
||||||
Objects.requireNonNull(name);
|
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 {
|
public static String decodeStreet(String street) throws IllegalArgumentException, NullPointerException {
|
||||||
Objects.requireNonNull(street);
|
Objects.requireNonNull(street);
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package me.teridax.jcash.gui;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.BankingManagementSystem;
|
||||||
|
|
||||||
|
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);
|
||||||
|
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
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") == APPROVE_OPTION) {
|
||||||
|
// parse file content
|
||||||
|
try {
|
||||||
|
return BankingManagementSystem.loadFromCsv(fileChooser.getSelectedFile().toPath());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException("Unable to load database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("No file selected");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
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 {
|
||||||
|
|
||||||
|
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().showLoginScreen();
|
||||||
|
});
|
||||||
|
|
||||||
|
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() {
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
package me.teridax.jcash.gui.account;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.*;
|
||||||
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
|
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<String> accountSelection;
|
||||||
|
|
||||||
|
private JPanel content;
|
||||||
|
|
||||||
|
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(StringUtils.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + " €");
|
||||||
|
|
||||||
|
this.type.setText(account.getClass().getSimpleName());
|
||||||
|
if (account instanceof Girokonto) {
|
||||||
|
this.typeSpecialLabel.setText("Overdraft");
|
||||||
|
this.typeSpecialProperty.setText( StringUtils.LOCAL_NUMBER_FORMAT.format(((Girokonto) account).getOverdraft()) + " €");
|
||||||
|
} else if (account instanceof SavingsAccount) {
|
||||||
|
this.typeSpecialLabel.setText("Interest rate");
|
||||||
|
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);
|
||||||
|
|
||||||
|
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("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("Account", SwingConstants.RIGHT));
|
||||||
|
addInputRow(constraints, content, typeSpecialProperty, 7, typeSpecialLabel);
|
||||||
|
addInputRow(constraints, content, balance, 8, new JLabel("Balance", SwingConstants.RIGHT));
|
||||||
|
|
||||||
|
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() {
|
||||||
|
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.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) {
|
||||||
|
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<String> getAccountSelection() {
|
||||||
|
return accountSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getLogout() {
|
||||||
|
return logout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getTransfer() {
|
||||||
|
return transfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getDeposit() {
|
||||||
|
return deposit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JButton getTakeoff() {
|
||||||
|
return takeoff;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
package me.teridax.jcash.gui.deposit;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.Account;
|
||||||
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
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 void layoutComponents() {
|
||||||
|
dialog.getContentPane().setLayout(new GridBagLayout());
|
||||||
|
|
||||||
|
var c = new GridBagConstraints();
|
||||||
|
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 0;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.weighty = 1;
|
||||||
|
c.gridwidth = 3;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
|
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.weightx = 0;
|
||||||
|
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.weightx = 0.5;
|
||||||
|
dialog.getContentPane().add(value, c);
|
||||||
|
|
||||||
|
c.gridx = 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);
|
||||||
|
dialog.getContentPane().add(buttonPanel, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createComponents(Account account) {
|
||||||
|
this.dialog = new JDialog();
|
||||||
|
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package me.teridax.jcash.gui.login;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.Profile;
|
||||||
|
|
||||||
|
public interface AccountSelectionListener {
|
||||||
|
|
||||||
|
void onAccountSelected(Profile account);
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package me.teridax.jcash.gui.login;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.BankingManagementSystem;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class LoginController {
|
||||||
|
|
||||||
|
private final LoginView view;
|
||||||
|
private final LoginData data;
|
||||||
|
|
||||||
|
private AccountSelectionListener listener;
|
||||||
|
|
||||||
|
public LoginController(BankingManagementSystem bms) {
|
||||||
|
this.view = new LoginView();
|
||||||
|
this.data = new LoginData(bms);
|
||||||
|
|
||||||
|
addActionListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addActionListeners() {
|
||||||
|
this.view.getLogin().addActionListener(this::login);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Integer> getIban() {
|
||||||
|
try {
|
||||||
|
var iban = this.view.getIban().getText();
|
||||||
|
return Optional.of(Integer.parseUnsignedInt(iban));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<Integer> 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()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package me.teridax.jcash.gui.login;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.BankingManagementSystem;
|
||||||
|
import me.teridax.jcash.banking.Profile;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class LoginData {
|
||||||
|
|
||||||
|
private final BankingManagementSystem bms;
|
||||||
|
|
||||||
|
public LoginData(BankingManagementSystem bms) {
|
||||||
|
this.bms = bms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Profile> authenticateAccount(String blz, int iban, int pin) {
|
||||||
|
var optionalBank = bms.getBank(blz);
|
||||||
|
if (optionalBank.isEmpty())
|
||||||
|
return Optional.empty();
|
||||||
|
|
||||||
|
var profile = optionalBank.get().getAccount(iban);
|
||||||
|
return profile.filter(value -> value.getPrimaryAccount().getPin() == pin);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
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 JFormattedTextField blz;
|
||||||
|
private final JFormattedTextField iban;
|
||||||
|
private final JPasswordField pin;
|
||||||
|
private final JButton login;
|
||||||
|
|
||||||
|
public LoginView() {
|
||||||
|
this.blz = new JFormattedTextField("MA2424");
|
||||||
|
this.iban = new JFormattedTextField(getNumberFormat());
|
||||||
|
this.iban.setText("4711");
|
||||||
|
this.pin = new JPasswordField("1234");
|
||||||
|
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 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package me.teridax.jcash.gui.takeoff;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.Account;
|
||||||
|
|
||||||
|
public class TakeoffDialog {
|
||||||
|
|
||||||
|
public TakeoffDialog(Account account, Runnable onTakeoff) {
|
||||||
|
var view = new TakeoffView(account);
|
||||||
|
view.getTakeoff().addActionListener(e -> {
|
||||||
|
account.takeoff(view.getAmount());
|
||||||
|
onTakeoff.run();
|
||||||
|
view.dispose();
|
||||||
|
});
|
||||||
|
view.getCancel().addActionListener(e -> view.dispose());
|
||||||
|
view.showDialog();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package me.teridax.jcash.gui.takeoff;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.Account;
|
||||||
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
import static javax.swing.JOptionPane.ERROR_MESSAGE;
|
||||||
|
import static javax.swing.JOptionPane.showMessageDialog;
|
||||||
|
|
||||||
|
public class TakeoffView {
|
||||||
|
|
||||||
|
private JDialog dialog;
|
||||||
|
private JButton cancel;
|
||||||
|
private JButton takeoff;
|
||||||
|
private JFormattedTextField value;
|
||||||
|
|
||||||
|
public TakeoffView(Account account) {
|
||||||
|
createComponents(account);
|
||||||
|
layoutComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showDialog() {
|
||||||
|
dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
|
||||||
|
dialog.setTitle("Takeoff money");
|
||||||
|
dialog.pack();
|
||||||
|
dialog.setResizable(false);
|
||||||
|
dialog.setLocationRelativeTo(null);
|
||||||
|
dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void layoutComponents() {
|
||||||
|
var c = new GridBagConstraints();
|
||||||
|
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 0;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.weighty = 1;
|
||||||
|
c.gridwidth = 3;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
|
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.weightx = 0;
|
||||||
|
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.weightx = 0.5;
|
||||||
|
dialog.getContentPane().add(value, c);
|
||||||
|
|
||||||
|
c.gridx = 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);
|
||||||
|
dialog.getContentPane().add(buttonPanel, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createComponents(Account account) {
|
||||||
|
this.dialog = new JDialog();
|
||||||
|
|
||||||
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getTakeoff() {
|
||||||
|
return takeoff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
this.dialog.dispose();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.getTransfer().addActionListener(e -> {
|
||||||
|
account.takeoff(view.getAmount());
|
||||||
|
onDeposit.run();
|
||||||
|
view.dispose();
|
||||||
|
});
|
||||||
|
view.getCancel().addActionListener(e -> view.dispose());
|
||||||
|
view.showDialog();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
package me.teridax.jcash.gui.transfer;
|
||||||
|
|
||||||
|
import me.teridax.jcash.banking.Account;
|
||||||
|
import me.teridax.jcash.decode.StringUtils;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.text.NumberFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
import static javax.swing.JOptionPane.ERROR_MESSAGE;
|
||||||
|
import static javax.swing.JOptionPane.showMessageDialog;
|
||||||
|
|
||||||
|
public class TransferView {
|
||||||
|
|
||||||
|
private JDialog dialog;
|
||||||
|
private JButton cancel;
|
||||||
|
private JButton transfer;
|
||||||
|
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("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 void layoutComponents() {
|
||||||
|
var c = new GridBagConstraints();
|
||||||
|
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 0;
|
||||||
|
c.weightx = 1;
|
||||||
|
c.weighty = 1;
|
||||||
|
c.gridwidth = 3;
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL;
|
||||||
|
c.anchor = GridBagConstraints.CENTER;
|
||||||
|
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.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.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.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.weightx = 1;
|
||||||
|
dialog.getContentPane().add(iban, c);
|
||||||
|
|
||||||
|
c.gridx = 0;
|
||||||
|
c.gridy = 2;
|
||||||
|
c.fill = GridBagConstraints.NONE;
|
||||||
|
c.anchor = GridBagConstraints.LAST_LINE_END;
|
||||||
|
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.weightx = 0.5;
|
||||||
|
dialog.getContentPane().add(value, c);
|
||||||
|
|
||||||
|
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);
|
||||||
|
dialog.getContentPane().add(buttonPanel, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createComponents(Account account) {
|
||||||
|
this.dialog = new JDialog();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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 getTransfer() {
|
||||||
|
return transfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose() {
|
||||||
|
this.dialog.dispose();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue