From 767d81aae0e4934fea13f7f1166eb0bac7707343 Mon Sep 17 00:00:00 2001 From: t-pa Date: Fri, 24 Jan 2020 21:07:48 +0100 Subject: [PATCH 1/6] If the currency of the locale is unknown, set as default any other currency. --- .../java/jgnash/uifx/wizard/file/NewFileTwoController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jgnash-fx/src/main/java/jgnash/uifx/wizard/file/NewFileTwoController.java b/jgnash-fx/src/main/java/jgnash/uifx/wizard/file/NewFileTwoController.java index c2a33d870..fe6b80fb4 100644 --- a/jgnash-fx/src/main/java/jgnash/uifx/wizard/file/NewFileTwoController.java +++ b/jgnash-fx/src/main/java/jgnash/uifx/wizard/file/NewFileTwoController.java @@ -69,12 +69,14 @@ private void initDefaultCurrencies() { final String symbol = DefaultCurrencies.getDefault().getSymbol(); // set the default currency by matching the default locale + // if the default locale's currency is unknown, the currency symbol is "XXX" and this Optional will be empty Optional matchingCurrency = currencyNodes.stream() .filter(node -> symbol.equals(node.getSymbol())) .findAny(); - defaultCurrencyComboBox.setValue(matchingCurrency.orElseThrow(() -> - new RuntimeException("Could not match currency"))); + defaultCurrencyComboBox.setValue(matchingCurrency.orElse( + currencyNodes.stream().findFirst().orElseThrow(() -> + new RuntimeException("Could not find any currency")))); updateDescriptor(); } From 1442ac6465d02940d6176ba988f5404102869645 Mon Sep 17 00:00:00 2001 From: t-pa Date: Sat, 20 Feb 2021 22:26:24 +0100 Subject: [PATCH 2/6] Guarantee non-negative scale in CurrencyNode. If the local currency is unknown, it defaults to the pseudo-currency "XXX" with scale -1. This scale is not allowed for CurrencyNodes, so set it to 0 instead. --- .../src/main/java/jgnash/engine/DefaultCurrencies.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java b/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java index f9a064b38..3780fb685 100644 --- a/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java +++ b/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java @@ -111,7 +111,9 @@ public static CurrencyNode buildNode(final Locale locale) { CurrencyNode node = new CurrencyNode(); node.setSymbol(c.getCurrencyCode()); node.setPrefix(symbols.getCurrencySymbol()); - node.setScale((byte) c.getDefaultFractionDigits()); + byte scale = (byte) c.getDefaultFractionDigits(); + if (scale == -1) scale = 0; // scale may be -1, but this is not allowed for CurrencyNodes + node.setScale(scale); return node; } From 4c060770508a82649aeab5e954b4494eeb34bc6e Mon Sep 17 00:00:00 2001 From: t-pa Date: Thu, 25 Feb 2021 23:54:19 +0100 Subject: [PATCH 3/6] Show the correct account also for split transactions. Even if the account combo box is locked in this case, the account is still shown to the user and later reused if a modified transaction entry is built. --- .../main/java/jgnash/uifx/views/register/SlipController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jgnash-fx/src/main/java/jgnash/uifx/views/register/SlipController.java b/jgnash-fx/src/main/java/jgnash/uifx/views/register/SlipController.java index ff2df12ee..8c508d3a8 100644 --- a/jgnash-fx/src/main/java/jgnash/uifx/views/register/SlipController.java +++ b/jgnash-fx/src/main/java/jgnash/uifx/views/register/SlipController.java @@ -292,10 +292,12 @@ private void newTransaction(final Transaction t) { for (final TransactionEntry entry : t.getTransactionEntries()) { if (entry.getCreditAccount() == accountProperty().get()) { accountExchangePane.setExchangedAmount(entry.getDebitAmount().abs()); + accountExchangePane.setSelectedAccount(entry.getDebitAccount()); tagPane.setSelectedTags(entry.getTags()); break; } else if (entry.getDebitAccount() == accountProperty().get()) { accountExchangePane.setExchangedAmount(entry.getCreditAmount()); + accountExchangePane.setSelectedAccount(entry.getCreditAccount()); tagPane.setSelectedTags(entry.getTags()); break; } From 313c47cedd50b7568a906022c941400798be5721 Mon Sep 17 00:00:00 2001 From: t-pa Date: Fri, 26 Feb 2021 00:17:34 +0100 Subject: [PATCH 4/6] Undo newline that was automatically inserted. --- jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java b/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java index 72a9ac141..4682eddb9 100644 --- a/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java +++ b/jgnash-core/src/main/java/jgnash/engine/DefaultCurrencies.java @@ -135,4 +135,4 @@ public static CurrencyNode getDefault() { return buildNode(Locale.US); } } -} +} \ No newline at end of file From 6af4f43b6694499096e0ec7e23eebb91edba895e Mon Sep 17 00:00:00 2001 From: t-pa Date: Sat, 27 Feb 2021 00:18:30 +0100 Subject: [PATCH 5/6] Silently ignore non-investment accounts, do not throw an exception. Also, only include those child accounts that themselves are investment accounts. This solves two problems: Due to a race condition, the constructor is sometimes called with a non-investment account, which led to an IllegalArgumentException and later to NullPointerExceptions. And this now works recursively even if not all child accounts are investment accounts. --- .../engine/InvestmentPerformanceSummary.java | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/jgnash-core/src/main/java/jgnash/engine/InvestmentPerformanceSummary.java b/jgnash-core/src/main/java/jgnash/engine/InvestmentPerformanceSummary.java index ed9c9e192..5e34e2d44 100644 --- a/jgnash-core/src/main/java/jgnash/engine/InvestmentPerformanceSummary.java +++ b/jgnash-core/src/main/java/jgnash/engine/InvestmentPerformanceSummary.java @@ -27,6 +27,7 @@ import java.util.Objects; import java.util.Set; import java.util.TreeMap; +import java.util.TreeSet; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; @@ -61,10 +62,6 @@ public InvestmentPerformanceSummary(final Account account, final LocalDate start this.recursive = recursive; - if (!account.memberOf(AccountGroup.INVEST)) { - throw new IllegalArgumentException("The account is not a valid type"); - } - this.baseCurrency = account.getCurrencyNode(); this.account = account; @@ -79,54 +76,65 @@ public InvestmentPerformanceSummary(final Account account, final LocalDate start setEndDate(endDate); } - transactions = account.getTransactions(getStartDate(), getEndDate()); - - if (recursive && account.getChildCount() > 0) { - collectSubAccountTransactions(account, transactions); - } + transactions = new ArrayList<>(); + collectAccountTransactions(account, transactions); Collections.sort(transactions); } public static Pair getTransactionDateRange(final Account account, final boolean recursive) { - List transactions = new ArrayList<>(account.getSortedTransactionList()); - - if (recursive && account.getChildCount() > 0) { - _collectSubAccountTransactions(account, transactions); - } + List transactions = new ArrayList<>(); + _collectAccountTransactions(account, recursive, transactions); transactions.sort(null); - return new ImmutablePair<>(transactions.get(0).getLocalDate(), - transactions.get(transactions.size() - 1).getLocalDate()); + if (transactions.size() > 0) { + return new ImmutablePair<>(transactions.get(0).getLocalDate(), + transactions.get(transactions.size() - 1).getLocalDate()); + } else { + LocalDate now = LocalDate.now(); + return new ImmutablePair<>(now, now); + } } - private static void _collectSubAccountTransactions(final Account account, final List transactions) { - for (final Account child : account.getChildren(Comparators.getAccountByCode())) { - transactions.addAll(child.getSortedTransactionList()); + private static void _collectAccountTransactions(final Account account, final boolean recursive, final List transactions) { + if (account.memberOf(AccountGroup.INVEST)) { + transactions.addAll(account.getSortedTransactionList()); + } - if (child.getChildCount() > 0) { - _collectSubAccountTransactions(child, transactions); + if (recursive) { + for (final Account child : account.getChildren(Comparators.getAccountByCode())) { + if (child.getChildCount() > 0) { + _collectAccountTransactions(child, recursive, transactions); + } } } } - private void collectSubAccountTransactions(final Account account, final List transactions) { - for (final Account child : account.getChildren(Comparators.getAccountByCode())) { - transactions.addAll(child.getTransactions(getStartDate(), getEndDate())); - - if (child.getChildCount() > 0) { - collectSubAccountTransactions(child, transactions); + private void collectAccountTransactions(final Account account, final List transactions) { + if (account.memberOf(AccountGroup.INVEST)) { + transactions.addAll(account.getTransactions(getStartDate(), getEndDate())); + } + + if (recursive) { + for (final Account child : account.getChildren(Comparators.getAccountByCode())) { + if (child.getChildCount() > 0) { + collectAccountTransactions(child, transactions); + } } } } - private void collectSubAccountSecurities(final Account account, final Set securities) { - for (final Account child : account.getChildren(Comparators.getAccountByCode())) { - securities.addAll(child.getSecurities()); - - if (child.getChildCount() > 0) { - collectSubAccountSecurities(child, securities); + private void collectAccountSecurities(final Account account, final Set securities) { + if (account.memberOf(AccountGroup.INVEST)) { + securities.addAll(account.getSecurities()); + } + + if (recursive) { + for (final Account child : account.getChildren(Comparators.getAccountByCode())) { + if (child.getChildCount() > 0) { + collectAccountSecurities(child, securities); + } } } } @@ -375,11 +383,8 @@ private void calculateInternalRateOfReturn(final SecurityPerformanceData data, f public void runCalculations() { - Set nodes = account.getSecurities(); - - if (recursive) { - collectSubAccountSecurities(account, nodes); - } + Set nodes = new TreeSet<>(); + collectAccountSecurities(account, nodes); for (final SecurityNode node : nodes) { SecurityPerformanceData data = new SecurityPerformanceData(node); From 84838719df85cfd1a99b6525caa403f789892b66 Mon Sep 17 00:00:00 2001 From: t-pa Date: Sat, 27 Feb 2021 00:25:28 +0100 Subject: [PATCH 6/6] Fix race condition. In some circumstances, the filteredList was empty when runLater() finally called setValue(). --- .../src/main/java/jgnash/uifx/control/AccountComboBox.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jgnash-fx/src/main/java/jgnash/uifx/control/AccountComboBox.java b/jgnash-fx/src/main/java/jgnash/uifx/control/AccountComboBox.java index 3dd471bc1..c9c598053 100644 --- a/jgnash-fx/src/main/java/jgnash/uifx/control/AccountComboBox.java +++ b/jgnash-fx/src/main/java/jgnash/uifx/control/AccountComboBox.java @@ -166,7 +166,8 @@ public void setPredicate(final Predicate predicate) { private void selectDefaultAccount() { // Set a default account, must use the filtered list because that is what is visible if (filteredList.size() > 0) { - JavaFXUtils.runLater(() -> setValue(filteredList.get(0))); + final Account account = filteredList.get(0); + JavaFXUtils.runLater(() -> setValue(account)); } }