finishing touches
This commit is contained in:
parent
9895ae03b9
commit
7fdb408900
|
@ -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)
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() + " %" );
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue