Added new AccountSelectionBox, still buggy due to weird javafx combobox stuff.

This commit is contained in:
Andrew Lalis 2024-01-11 22:16:24 -05:00
parent 7ceaca7068
commit 3521dee149
4 changed files with 79 additions and 38 deletions

View File

@ -8,7 +8,7 @@ import com.andrewlalis.perfin.model.Account;
import com.andrewlalis.perfin.model.CreditAndDebitAccounts; import com.andrewlalis.perfin.model.CreditAndDebitAccounts;
import com.andrewlalis.perfin.model.Profile; import com.andrewlalis.perfin.model.Profile;
import com.andrewlalis.perfin.model.Transaction; import com.andrewlalis.perfin.model.Transaction;
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory; import com.andrewlalis.perfin.view.component.AccountSelectionBox;
import com.andrewlalis.perfin.view.component.FileSelectionArea; import com.andrewlalis.perfin.view.component.FileSelectionArea;
import com.andrewlalis.perfin.view.component.validation.ValidationApplier; import com.andrewlalis.perfin.view.component.validation.ValidationApplier;
import com.andrewlalis.perfin.view.component.validation.validators.CurrencyAmountValidator; import com.andrewlalis.perfin.view.component.validation.validators.CurrencyAmountValidator;
@ -42,14 +42,16 @@ public class EditTransactionController implements RouteSelectionListener {
@FXML public TextArea descriptionField; @FXML public TextArea descriptionField;
@FXML public HBox linkedAccountsContainer; @FXML public HBox linkedAccountsContainer;
@FXML public ComboBox<Account> linkDebitAccountComboBox; @FXML public AccountSelectionBox debitAccountSelector;
@FXML public ComboBox<Account> linkCreditAccountComboBox; @FXML public AccountSelectionBox creditAccountSelector;
@FXML public VBox attachmentsVBox; @FXML public VBox attachmentsVBox;
private FileSelectionArea attachmentsSelectionArea; private FileSelectionArea attachmentsSelectionArea;
@FXML public Button saveButton; @FXML public Button saveButton;
private Transaction transaction;
@FXML public void initialize() { @FXML public void initialize() {
// Setup error field validation. // Setup error field validation.
var timestampValid = new ValidationApplier<>(new PredicateValidator<String>() var timestampValid = new ValidationApplier<>(new PredicateValidator<String>()
@ -67,8 +69,8 @@ public class EditTransactionController implements RouteSelectionListener {
).validatedInitially().attach(descriptionField, descriptionField.textProperty()); ).validatedInitially().attach(descriptionField, descriptionField.textProperty());
// Linked accounts will use a property derived from both the debit and credit selections. // Linked accounts will use a property derived from both the debit and credit selections.
Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts()); Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts());
linkDebitAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts())); debitAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
linkCreditAccountComboBox.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts())); creditAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
var linkedAccountsValid = new ValidationApplier<>(new PredicateValidator<CreditAndDebitAccounts>() var linkedAccountsValid = new ValidationApplier<>(new PredicateValidator<CreditAndDebitAccounts>()
.addPredicate(accounts -> accounts.hasCredit() || accounts.hasDebit(), "At least one account must be linked.") .addPredicate(accounts -> accounts.hasCredit() || accounts.hasDebit(), "At least one account must be linked.")
.addPredicate( .addPredicate(
@ -81,13 +83,7 @@ public class EditTransactionController implements RouteSelectionListener {
saveButton.disableProperty().bind(formValid.not()); saveButton.disableProperty().bind(formValid.not());
// Update the lists of accounts available for linking based on the selected currency. // Update the lists of accounts available for linking based on the selected currency.
var cellFactory = new AccountComboBoxCellFactory();
linkDebitAccountComboBox.setCellFactory(cellFactory);
linkDebitAccountComboBox.setButtonCell(cellFactory.call(null));
linkCreditAccountComboBox.setCellFactory(cellFactory);
linkCreditAccountComboBox.setButtonCell(cellFactory.call(null));
currencyChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> { currencyChoiceBox.valueProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Set currency to " + newValue);
updateLinkAccountComboBoxes(newValue); updateLinkAccountComboBoxes(newValue);
}); });
@ -126,7 +122,7 @@ public class EditTransactionController implements RouteSelectionListener {
@Override @Override
public void onRouteSelected(Object context) { public void onRouteSelected(Object context) {
Transaction transaction = (Transaction) context; transaction = (Transaction) context;
boolean creatingNew = transaction == null; boolean creatingNew = transaction == null;
if (creatingNew) { if (creatingNew) {
@ -147,11 +143,8 @@ public class EditTransactionController implements RouteSelectionListener {
Thread.ofVirtual().start(() -> Profile.getCurrent().getDataSource().useTransactionRepository(repo -> { Thread.ofVirtual().start(() -> Profile.getCurrent().getDataSource().useTransactionRepository(repo -> {
CreditAndDebitAccounts accounts = repo.findLinkedAccounts(transaction.id); CreditAndDebitAccounts accounts = repo.findLinkedAccounts(transaction.id);
Platform.runLater(() -> { Platform.runLater(() -> {
System.out.println(linkCreditAccountComboBox.getItems().indexOf(accounts.creditAccount())); debitAccountSelector.getSelectionModel().select(accounts.debitAccount());
// linkCreditAccountComboBox.getSelectionModel().select(accounts.creditAccount()); creditAccountSelector.getSelectionModel().select(accounts.creditAccount());
// linkCreditAccountComboBox.getButtonCell().updateIndex(linkCreditAccountComboBox.getSelectionModel().getSelectedIndex());
// linkDebitAccountComboBox.getSelectionModel().select(accounts.debitAccount());
// linkDebitAccountComboBox.getButtonCell().updateIndex(linkDebitAccountComboBox.getSelectionModel().getSelectedIndex());
}); });
})); }));
} }
@ -173,8 +166,8 @@ public class EditTransactionController implements RouteSelectionListener {
private CreditAndDebitAccounts getSelectedAccounts() { private CreditAndDebitAccounts getSelectedAccounts() {
return new CreditAndDebitAccounts( return new CreditAndDebitAccounts(
linkCreditAccountComboBox.getValue(), creditAccountSelector.getValue(),
linkDebitAccountComboBox.getValue() debitAccountSelector.getValue()
); );
} }
@ -202,18 +195,16 @@ public class EditTransactionController implements RouteSelectionListener {
Profile.getCurrent().getDataSource().useAccountRepository(repo -> { Profile.getCurrent().getDataSource().useAccountRepository(repo -> {
List<Account> availableAccounts = new ArrayList<>(); List<Account> availableAccounts = new ArrayList<>();
if (currency != null) availableAccounts.addAll(repo.findAllByCurrency(currency)); if (currency != null) availableAccounts.addAll(repo.findAllByCurrency(currency));
availableAccounts.add(null);
Platform.runLater(() -> { Platform.runLater(() -> {
linkDebitAccountComboBox.getItems().clear(); debitAccountSelector.setAccounts(availableAccounts);
linkDebitAccountComboBox.getItems().addAll(availableAccounts); creditAccountSelector.setAccounts(availableAccounts);
linkDebitAccountComboBox.getSelectionModel().selectLast(); if (transaction != null) {
linkDebitAccountComboBox.getButtonCell().updateIndex(availableAccounts.size() - 1); Profile.getCurrent().getDataSource().useTransactionRepository(transactionRepo -> {
var linkedAccounts = transactionRepo.findLinkedAccounts(transaction.id);
linkCreditAccountComboBox.getItems().clear(); debitAccountSelector.getSelectionModel().select(linkedAccounts.debitAccount());
linkCreditAccountComboBox.getItems().addAll(availableAccounts); creditAccountSelector.getSelectionModel().select(linkedAccounts.creditAccount());
linkCreditAccountComboBox.getSelectionModel().selectLast(); });
linkCreditAccountComboBox.getButtonCell().updateIndex(availableAccounts.size() - 1); }
System.out.println("link account boxes updated.");
}); });
}); });
}); });

View File

@ -24,6 +24,7 @@ public class AccountComboBoxCellFactory implements Callback<ListView<Account>, L
public AccountListCell(String emptyCellText) { public AccountListCell(String emptyCellText) {
this.emptyCellText = emptyCellText; this.emptyCellText = emptyCellText;
label.getStyleClass().add("normal-color-text-fill"); label.getStyleClass().add("normal-color-text-fill");
setGraphic(label);
} }
@Override @Override

View File

@ -0,0 +1,52 @@
package com.andrewlalis.perfin.view.component;
import com.andrewlalis.perfin.model.Account;
import com.andrewlalis.perfin.view.AccountComboBoxCellFactory;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.ComboBox;
import java.util.List;
/**
* A box that allows the user to select one account from a list of options.
*/
public class AccountSelectionBox extends ComboBox<Account> {
private final BooleanProperty allowNoneProperty = new SimpleBooleanProperty(true);
public AccountSelectionBox() {
valueProperty().bind(getSelectionModel().selectedItemProperty());
var factory = new AccountComboBoxCellFactory();
setCellFactory(factory);
setButtonCell(factory.call(null));
}
public void setAccounts(List<Account> accounts) {
if (getAllowNone() && !accounts.contains(null)) {
accounts.add(null);
}
getItems().clear();
getItems().addAll(accounts);
int idx;
if (getAllowNone()) {
getSelectionModel().select(null);
idx = accounts.indexOf(null);
} else {
getSelectionModel().clearSelection();
idx = 0;
}
getButtonCell().updateIndex(idx);
}
public final BooleanProperty allowNoneProperty() {
return allowNoneProperty;
}
public final boolean getAllowNone() {
return allowNoneProperty.get();
}
public final void setAllowNone(boolean value) {
allowNoneProperty.set(value);
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import com.andrewlalis.perfin.view.component.AccountSelectionBox?>
<?import com.andrewlalis.perfin.view.component.PropertiesPane?> <?import com.andrewlalis.perfin.view.component.PropertiesPane?>
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
@ -41,16 +42,12 @@
<!-- Container for linked accounts --> <!-- Container for linked accounts -->
<HBox styleClass="std-padding,std-spacing" fx:id="linkedAccountsContainer"> <HBox styleClass="std-padding,std-spacing" fx:id="linkedAccountsContainer">
<VBox> <VBox>
<Label text="Debited Account" labelFor="${linkDebitAccountComboBox}" styleClass="bold-text"/> <Label text="Debited Account" labelFor="${debitAccountSelector}" styleClass="bold-text"/>
<ComboBox fx:id="linkDebitAccountComboBox"> <AccountSelectionBox fx:id="debitAccountSelector" allowNone="true"/>
<tooltip><Tooltip text="The account whose assets will increase as a result of this transaction."/></tooltip>
</ComboBox>
</VBox> </VBox>
<VBox> <VBox>
<Label text="Credited Account" labelFor="${linkCreditAccountComboBox}" styleClass="bold-text"/> <Label text="Credited Account" labelFor="${creditAccountSelector}" styleClass="bold-text"/>
<ComboBox fx:id="linkCreditAccountComboBox"> <AccountSelectionBox fx:id="creditAccountSelector" allowNone="true"/>
<tooltip><Tooltip text="The account whose assets will decrease as a result of this transaction."/></tooltip>
</ComboBox>
</VBox> </VBox>
</HBox> </HBox>
<!-- Container for attachments --> <!-- Container for attachments -->