finishing touches

This commit is contained in:
Sven Vogel 2023-07-19 14:17:52 +02:00
parent 9895ae03b9
commit 7fdb408900
10 changed files with 96 additions and 87 deletions

View File

@ -6,10 +6,7 @@ import me.teridax.jcash.gui.account.AccountController;
import me.teridax.jcash.gui.login.LoginController; import me.teridax.jcash.gui.login.LoginController;
import me.teridax.jcash.lang.Locales; import me.teridax.jcash.lang.Locales;
import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.Objects; import java.util.Objects;
import java.util.logging.*; import java.util.logging.*;
@ -100,8 +97,6 @@ public final class Main {
* Attempts to create a new instance of the singleton class Main. * Attempts to create a new instance of the singleton class Main.
* This method throws an exception if the class is already instantiated. * This method throws an exception if the class is already instantiated.
* @throws IllegalStateException 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() { public static void instance() {
if (null != instance) if (null != instance)

View File

@ -43,8 +43,6 @@ public abstract class Account {
Objects.requireNonNull(columns); Objects.requireNonNull(columns);
Logging.LOGGER.finer("Parsing account from columns"); Logging.LOGGER.finer("Parsing account from columns");
Logging.LOGGER.finer("Decoding account fields");
// deserialize fields // deserialize fields
var iban = StringDecoder.decodeUniqueIdentificationNumber(columns[0]); var iban = StringDecoder.decodeUniqueIdentificationNumber(columns[0]);
var pin = StringDecoder.decodeUniqueIdentificationNumber(columns[1]); var pin = StringDecoder.decodeUniqueIdentificationNumber(columns[1]);

View File

@ -0,0 +1,67 @@
package me.teridax.jcash.decode;
import me.teridax.jcash.lang.Locales;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
import static me.teridax.jcash.decode.StringDecoder.*;
public class DecodeTests {
@Test
public void testDecodeSuccessfulFunctions() {
// make sure a comma separated integer from fractions
Locales.setDefaultLocale("de", "DE");
assertEquals(decodePercent("1,003"), 100.3d, 1e-3d);
decodeUniqueIdentificationNumber("9578647895");
decodeUniqueIdentificationNumber(" 927856347 ");
decodeUniqueIdentificationNumber("0");
decodeUniqueIdentificationNumber("'9578647895");
decodeName("Adolf");
decodeName("Günther");
decodeName("Saßkia");
decodeStreet("Bahnhofstraße 40/1");
decodeStreet("Gülleweg 9");
decodeStreet("Echsengaße 67 / 4");
assertEquals(decodePercent("1,4%"), 1.4, 1e-3d);
assertEquals(decodePercent("99"), 9900.0d);
assertEquals(decodePercent("1,003%"), 1.003, 1e-5d);
assertEquals(decodePercent("1,003"), 100.3, 1e-5d);
assertEquals(decodePercent("'1,003"), 100.3, 1e-5d);
assertEquals(decodeCurrency("1,3€"), 1.3d);
assertEquals(decodeCurrency("0567€"), 567d);
assertEquals(decodeCurrency("145,34"), 145,34d);
assertEquals(decodeCurrency("0,45 €"), 0.45d);
}
@Test
public void decodeLocaleDependent() {
Locales.setDefaultLocale("de", "DE");
assertEquals(decodeCurrency("13.00,45€"), 1300.45);
Locales.setDefaultLocale("en", "EN");
assertEquals(decodeCurrency("13,00.45€"), 1300.45);
}
@Test(expected = IllegalArgumentException.class)
public void testDecodeInvalidFunctions() {
decodeUniqueIdentificationNumber("q0948tvb6q047t 740 t74z0tz 784");
decodeUniqueIdentificationNumber("-39867.8475");
decodeUniqueIdentificationNumber("-398678475");
decodeUniqueIdentificationNumber(" ß9qu908t76q34798t6q734vb9843");
decodeName("John Doe");
decodeName("3490qt67v 0b34");
decodeName("Alexander9");
decodeName("-ga76re78g6$§");
decodeStreet("Bahnhofstraße -40/1");
decodeStreet("Gülleweg 9//567");
decodeStreet("23Echsengaße 67 / 4 Hofwetg 9");
}
}

View File

@ -1,33 +1,26 @@
package me.teridax.jcash.decode; package me.teridax.jcash.decode;
import org.junit.Test; import me.teridax.jcash.lang.Locales;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.text.ParseException; import java.text.ParseException;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static junit.framework.TestCase.assertEquals;
/** /**
* Utility class for converting various single line strings into a specific data type according * Utility class for converting various single line strings into a specific data type according
* to a format mostly dictated by a locale. * to a format mostly dictated by a locale.
*/ */
public class StringDecoder { public class StringDecoder {
/** public static NumberFormat getNumberFormat() {
* Locale to use when converting strings return NumberFormat.getInstance(Locales.getDefaultLocale());
*/ }
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. * 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. * The output value will be in the range [0, 100]. Strings formatted without a percentage
* symbol will be assumed to be normalized and thus multiplied by 100 to retrieve the result in percent.
* @param number the string to convert * @param number the string to convert
* @return the double value * @return the double value
* @throws IllegalArgumentException when the format is invalid * @throws IllegalArgumentException when the format is invalid
@ -36,19 +29,22 @@ public class StringDecoder {
public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException { public static double decodePercent(String number) throws IllegalArgumentException, NullPointerException {
Objects.requireNonNull(number); Objects.requireNonNull(number);
// trim the number and cut out optional percent symbols // trim and cut out weird leading single quotes for numbers
var trimmed = number.trim(); var prepared = number.trim().replaceAll("^\\s*['`](?=\\d)", "");
var pattern = Pattern.compile("^([^%]+)?(%)?$", Pattern.CASE_INSENSITIVE); var pattern = Pattern.compile("^([^%]+)?(%)?$", Pattern.CASE_INSENSITIVE);
var matcher = pattern.matcher(trimmed); var matcher = pattern.matcher(prepared);
if (matcher.find()) { if (matcher.find()) {
// if no percentage symbol is given the number will be multiplied by 100%
var scale = 1e2; var scale = 1e2;
// check if capture group 2 captured a percentage symbol
// if to we don't want to apply any scaling to the value
if (null != matcher.group(2)) if (null != matcher.group(2))
scale = 1; scale = 1;
try { try {
return LOCAL_NUMBER_FORMAT.parse(matcher.group(1)).doubleValue() * scale; return getNumberFormat().parse(matcher.group(1)).doubleValue() * scale;
} catch (ParseException ex) { } catch (ParseException ex) {
throw new IllegalArgumentException("Not a valid number: " + number, ex); throw new IllegalArgumentException("Not a valid number: " + number, ex);
} }
@ -68,10 +64,10 @@ public class StringDecoder {
Objects.requireNonNull(currency); Objects.requireNonNull(currency);
// trim and cut out weird leading single quotes for numbers // trim and cut out weird leading single quotes for numbers
var preparedUID = currency.trim().replaceAll("^\\s*['`](?=\\d)", ""); var prepared = currency.trim().replaceAll("^\\s*['`](?=\\d)", "");
try { try {
return LOCAL_NUMBER_FORMAT.parse(preparedUID).doubleValue(); return getNumberFormat().parse(prepared).doubleValue();
} catch (ParseException ex) { } catch (ParseException ex) {
throw new IllegalArgumentException("Not a valid currency in german locale: " + currency, ex); throw new IllegalArgumentException("Not a valid currency in german locale: " + currency, ex);
} }
@ -93,9 +89,7 @@ public class StringDecoder {
// check if the string is a valid unsigned number // check if the string is a valid unsigned number
try { try {
LOCAL_NUMBER_FORMAT.setParseIntegerOnly(true); var serialNumber = getNumberFormat().parse(preparedUID);
var serialNumber = LOCAL_NUMBER_FORMAT.parse(preparedUID);
LOCAL_NUMBER_FORMAT.setParseIntegerOnly(false);
if (serialNumber.intValue() < 0) if (serialNumber.intValue() < 0)
throw new IllegalArgumentException("Not a valid unique identification number: " + number); throw new IllegalArgumentException("Not a valid unique identification number: " + number);
@ -146,47 +140,4 @@ public class StringDecoder {
throw new IllegalArgumentException("not a void address"); throw new IllegalArgumentException("not a void address");
} }
} }
@Test
public void testDecodeSuccessfulFunctions() {
assertEquals(decodePercent("1,003"), 100.3d, 1e-3d);
decodeUniqueIdentificationNumber("9578647895");
decodeUniqueIdentificationNumber(" 927856347 ");
decodeUniqueIdentificationNumber("0");
decodeName("Adolf");
decodeName("Günther");
decodeName("Saßkia");
decodeStreet("Bahnhofstraße 40/1");
decodeStreet("Gülleweg 9");
decodeStreet("Echsengaße 67 / 4");
assertEquals(decodePercent("1,4%"), 1.4, 1e-3d);
assertEquals(decodePercent("99"), 9900.0d);
assertEquals(decodePercent("1,003%"), 1.003, 1e-5d);
assertEquals(decodePercent("1,003"), 100.3, 1e-5d);
assertEquals(decodeCurrency("1,3€"), 1.3d);
assertEquals(decodeCurrency("145,34"), 145,34d);
assertEquals(decodeCurrency("0,45 €"), 0.45d);
}
@Test(expected = IllegalArgumentException.class)
public void testDecodeInvalidFunctions() {
decodeUniqueIdentificationNumber("q0948tvb6q047t 740 t74z0tz 784");
decodeUniqueIdentificationNumber("-39867.8475");
decodeUniqueIdentificationNumber("-398678475");
decodeUniqueIdentificationNumber(" ß9qu908t76q34798t6q734vb9843");
decodeName("John Doe");
decodeName("3490qt67v 0b34");
decodeName("Alexander9");
decodeName("-ga76re78g6$§");
decodeStreet("Bahnhofstraße -40/1");
decodeStreet("Gülleweg 9//567");
decodeStreet("23Echsengaße 67 / 4 Hofwetg 9");
}
} }

View File

@ -1,7 +1,5 @@
package me.teridax.jcash.gui; package me.teridax.jcash.gui;
import me.teridax.jcash.Main;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;

View File

@ -49,12 +49,12 @@ public class AccountView extends JPanel {
this.name.setText(owner.getName() + " " + owner.getFamilyName()); this.name.setText(owner.getName() + " " + owner.getFamilyName());
this.address.setText(owner.getStreet() + " " + owner.getCity()); this.address.setText(owner.getStreet() + " " + owner.getCity());
this.balance.setText(StringDecoder.LOCAL_NUMBER_FORMAT.format(account.getBalance()) + ""); this.balance.setText(StringDecoder.getNumberFormat().format(account.getBalance()) + "");
this.type.setText(translate(account.getClass().getSimpleName())); this.type.setText(translate(account.getClass().getSimpleName()));
if (account instanceof CurrentAccount) {; if (account instanceof CurrentAccount) {
this.typeSpecialLabel.setText(translate("Overdraft")); this.typeSpecialLabel.setText(translate("Overdraft"));
this.typeSpecialProperty.setText( StringDecoder.LOCAL_NUMBER_FORMAT.format(((CurrentAccount) account).getOverdraft()) + ""); this.typeSpecialProperty.setText( StringDecoder.getNumberFormat().format(((CurrentAccount) account).getOverdraft()) + "");
} else if (account instanceof SavingsAccount) { } else if (account instanceof SavingsAccount) {
this.typeSpecialLabel.setText(translate("Interest rate")); this.typeSpecialLabel.setText(translate("Interest rate"));
this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" ); this.typeSpecialProperty.setText( ((SavingsAccount) account).getInterest() + " %" );

View File

@ -87,7 +87,7 @@ public class DepositView {
this.cancel = new JButton(translate("Cancel")); this.cancel = new JButton(translate("Cancel"));
this.deposit = new JButton(translate("Deposit")); this.deposit = new JButton(translate("Deposit"));
this.value = new JFormattedTextField(StringDecoder.LOCAL_NUMBER_FORMAT); this.value = new JFormattedTextField(StringDecoder.getNumberFormat());
this.dialog.setContentPane(new JPanel(new GridBagLayout())); this.dialog.setContentPane(new JPanel(new GridBagLayout()));
} }

View File

@ -86,7 +86,7 @@ public class TakeoffView {
this.cancel = new JButton(translate("Cancel")); this.cancel = new JButton(translate("Cancel"));
this.takeoff = new JButton(translate("Takeoff")); this.takeoff = new JButton(translate("Takeoff"));
this.value = new JFormattedTextField(StringDecoder.LOCAL_NUMBER_FORMAT); this.value = new JFormattedTextField(StringDecoder.getNumberFormat());
this.dialog.setContentPane(new JPanel(new GridBagLayout())); this.dialog.setContentPane(new JPanel(new GridBagLayout()));
} }

View File

@ -109,7 +109,7 @@ public class TransferView {
this.cancel = new JButton(translate("Cancel")); this.cancel = new JButton(translate("Cancel"));
this.transfer = new JButton(translate("Transfer")); this.transfer = new JButton(translate("Transfer"));
this.value = new JFormattedTextField(StringDecoder.LOCAL_NUMBER_FORMAT); this.value = new JFormattedTextField(StringDecoder.getNumberFormat());
this.iban = new JFormattedTextField(); this.iban = new JFormattedTextField();
this.blz = new JFormattedTextField(); this.blz = new JFormattedTextField();

View File

@ -1,5 +1,7 @@
package me.teridax.jcash.lang; package me.teridax.jcash.lang;
import me.teridax.jcash.Logging;
import java.util.Locale; import java.util.Locale;
/** /**
@ -8,10 +10,7 @@ import java.util.Locale;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class Locales { public class Locales {
/** private static Locale defaultLocale = new Locale("en", "EN");
* Locale string used to identify a certain locale
*/
private static String defaultLocale = "en_EN";
/** /**
* Sets the default locale to use for the application instance. * Sets the default locale to use for the application instance.
@ -24,13 +23,14 @@ public class Locales {
var locale = language + "_" + country; var locale = language + "_" + country;
if (Translator.setTranslationLocale(locale)) { if (Translator.setTranslationLocale(locale)) {
defaultLocale = new Locale(language, country);
// apply locale to JVM // apply locale to JVM
Locale.setDefault(new Locale(language, country)); Locale.setDefault(defaultLocale);
defaultLocale = locale;
} }
Logging.LOGGER.info("Using locale: " + locale);
} }
public static String getDefaultLocale() { public static Locale getDefaultLocale() {
return defaultLocale; return defaultLocale;
} }