Added hyperlinks for entity management pages.
This commit is contained in:
		
							parent
							
								
									1cdadc9fc4
								
							
						
					
					
						commit
						ae2713dbd0
					
				| 
						 | 
				
			
			@ -15,13 +15,14 @@ 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.PredicateValidator;
 | 
			
		||||
import javafx.application.Platform;
 | 
			
		||||
import javafx.beans.binding.BooleanExpression;
 | 
			
		||||
import javafx.beans.property.Property;
 | 
			
		||||
import javafx.beans.property.SimpleObjectProperty;
 | 
			
		||||
import javafx.collections.FXCollections;
 | 
			
		||||
import javafx.collections.ObservableList;
 | 
			
		||||
import javafx.event.ActionEvent;
 | 
			
		||||
import javafx.fxml.FXML;
 | 
			
		||||
import javafx.geometry.Pos;
 | 
			
		||||
import javafx.scene.Node;
 | 
			
		||||
import javafx.scene.control.*;
 | 
			
		||||
import javafx.scene.input.KeyCode;
 | 
			
		||||
import javafx.scene.layout.BorderPane;
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,10 @@ import java.util.*;
 | 
			
		|||
 | 
			
		||||
import static com.andrewlalis.perfin.PerfinApp.router;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Controller for the "edit-transaction" view, which is where the user can
 | 
			
		||||
 * create or edit transactions.
 | 
			
		||||
 */
 | 
			
		||||
public class EditTransactionController implements RouteSelectionListener {
 | 
			
		||||
    private static final Logger log = LoggerFactory.getLogger(EditTransactionController.class);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -82,45 +87,8 @@ public class EditTransactionController implements RouteSelectionListener {
 | 
			
		|||
        var descriptionValid = new ValidationApplier<>(new PredicateValidator<String>()
 | 
			
		||||
                .addTerminalPredicate(s -> s == null || s.length() <= 255, "Description is too long.")
 | 
			
		||||
        ).validatedInitially().attach(descriptionField, descriptionField.textProperty());
 | 
			
		||||
 | 
			
		||||
        // Linked accounts will use a property derived from both the debit and credit selections.
 | 
			
		||||
        Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts());
 | 
			
		||||
        debitAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
 | 
			
		||||
        creditAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
 | 
			
		||||
        var linkedAccountsValid = new ValidationApplier<>(getLinkedAccountsValidator())
 | 
			
		||||
                .validatedInitially()
 | 
			
		||||
                .attach(linkedAccountsContainer, linkedAccountsProperty);
 | 
			
		||||
 | 
			
		||||
        // Set up the list of added tags.
 | 
			
		||||
        addTagButton.disableProperty().bind(tagsComboBox.valueProperty().map(s -> s == null || s.isBlank()));
 | 
			
		||||
        addTagButton.setOnAction(event -> {
 | 
			
		||||
            if (tagsComboBox.getValue() == null) return;
 | 
			
		||||
            String tag = tagsComboBox.getValue().strip();
 | 
			
		||||
            if (!selectedTags.contains(tag)) {
 | 
			
		||||
                selectedTags.add(tag);
 | 
			
		||||
                selectedTags.sort(String::compareToIgnoreCase);
 | 
			
		||||
            }
 | 
			
		||||
            tagsComboBox.setValue(null);
 | 
			
		||||
        });
 | 
			
		||||
        tagsComboBox.setOnKeyPressed(event -> {
 | 
			
		||||
            if (event.getCode() == KeyCode.ENTER) {
 | 
			
		||||
                addTagButton.fire();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        BindingUtil.mapContent(tagsVBox.getChildren(), selectedTags, tag -> {
 | 
			
		||||
            Label label = new Label(tag);
 | 
			
		||||
            label.setMaxWidth(Double.POSITIVE_INFINITY);
 | 
			
		||||
            label.getStyleClass().addAll("bold-text");
 | 
			
		||||
            Button removeButton = new Button("Remove");
 | 
			
		||||
            removeButton.setOnAction(event -> {
 | 
			
		||||
                selectedTags.remove(tag);
 | 
			
		||||
            });
 | 
			
		||||
            BorderPane tile = new BorderPane(label);
 | 
			
		||||
            tile.setRight(removeButton);
 | 
			
		||||
            tile.getStyleClass().addAll("std-spacing");
 | 
			
		||||
            BorderPane.setAlignment(label, Pos.CENTER_LEFT);
 | 
			
		||||
            return tile;
 | 
			
		||||
        });
 | 
			
		||||
        var linkedAccountsValid = initializeLinkedAccountsValidationUi();
 | 
			
		||||
        initializeTagSelectionUi();
 | 
			
		||||
 | 
			
		||||
        var formValid = timestampValid.and(amountValid).and(descriptionValid).and(linkedAccountsValid);
 | 
			
		||||
        saveButton.disableProperty().bind(formValid.not());
 | 
			
		||||
| 
						 | 
				
			
			@ -279,6 +247,47 @@ public class EditTransactionController implements RouteSelectionListener {
 | 
			
		|||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private BooleanExpression initializeLinkedAccountsValidationUi() {
 | 
			
		||||
        Property<CreditAndDebitAccounts> linkedAccountsProperty = new SimpleObjectProperty<>(getSelectedAccounts());
 | 
			
		||||
        debitAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
 | 
			
		||||
        creditAccountSelector.valueProperty().addListener((observable, oldValue, newValue) -> linkedAccountsProperty.setValue(getSelectedAccounts()));
 | 
			
		||||
        return new ValidationApplier<>(getLinkedAccountsValidator())
 | 
			
		||||
                .validatedInitially()
 | 
			
		||||
                .attach(linkedAccountsContainer, linkedAccountsProperty);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void initializeTagSelectionUi() {
 | 
			
		||||
        addTagButton.disableProperty().bind(tagsComboBox.valueProperty().map(s -> s == null || s.isBlank()));
 | 
			
		||||
        addTagButton.setOnAction(event -> {
 | 
			
		||||
            if (tagsComboBox.getValue() == null) return;
 | 
			
		||||
            String tag = tagsComboBox.getValue().strip();
 | 
			
		||||
            if (!selectedTags.contains(tag)) {
 | 
			
		||||
                selectedTags.add(tag);
 | 
			
		||||
                selectedTags.sort(String::compareToIgnoreCase);
 | 
			
		||||
            }
 | 
			
		||||
            tagsComboBox.setValue(null);
 | 
			
		||||
        });
 | 
			
		||||
        tagsComboBox.setOnKeyPressed(event -> {
 | 
			
		||||
            if (event.getCode() == KeyCode.ENTER) {
 | 
			
		||||
                addTagButton.fire();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        BindingUtil.mapContent(tagsVBox.getChildren(), selectedTags, this::createTagListTile);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Node createTagListTile(String tag) {
 | 
			
		||||
        Label label = new Label(tag);
 | 
			
		||||
        label.setMaxWidth(Double.POSITIVE_INFINITY);
 | 
			
		||||
        label.getStyleClass().addAll("bold-text");
 | 
			
		||||
        Button removeButton = new Button("Remove");
 | 
			
		||||
        removeButton.setOnAction(event -> selectedTags.remove(tag));
 | 
			
		||||
        BorderPane tile = new BorderPane(label);
 | 
			
		||||
        tile.setRight(removeButton);
 | 
			
		||||
        tile.getStyleClass().addAll("std-spacing");
 | 
			
		||||
        BorderPane.setAlignment(label, Pos.CENTER_LEFT);
 | 
			
		||||
        return tile;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private CreditAndDebitAccounts getSelectedAccounts() {
 | 
			
		||||
        return new CreditAndDebitAccounts(
 | 
			
		||||
                creditAccountSelector.getValue(),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,13 +60,22 @@
 | 
			
		|||
                        <ColumnConstraints hgrow="ALWAYS" halignment="RIGHT"/>
 | 
			
		||||
                    </columnConstraints>
 | 
			
		||||
 | 
			
		||||
                    <Label text="Vendor" labelFor="${vendorComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                    <VBox>
 | 
			
		||||
                        <Label text="Vendor" labelFor="${vendorComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                        <Hyperlink text="Manage vendors" styleClass="small-font"/>
 | 
			
		||||
                    </VBox>
 | 
			
		||||
                    <ComboBox fx:id="vendorComboBox" editable="true" maxWidth="Infinity"/>
 | 
			
		||||
 | 
			
		||||
                    <Label text="Category" labelFor="${categoryComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                    <VBox>
 | 
			
		||||
                        <Label text="Category" labelFor="${categoryComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                        <Hyperlink text="Manage categories" styleClass="small-font"/>
 | 
			
		||||
                    </VBox>
 | 
			
		||||
                    <ComboBox fx:id="categoryComboBox" editable="true" maxWidth="Infinity"/>
 | 
			
		||||
 | 
			
		||||
                    <Label text="Tags" labelFor="${tagsComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                    <VBox>
 | 
			
		||||
                        <Label text="Tags" labelFor="${tagsComboBox}" styleClass="bold-text"/>
 | 
			
		||||
                        <Hyperlink text="Manage tags" styleClass="small-font"/>
 | 
			
		||||
                    </VBox>
 | 
			
		||||
                    <VBox maxWidth="Infinity">
 | 
			
		||||
                        <HBox styleClass="std-spacing">
 | 
			
		||||
                            <ComboBox fx:id="tagsComboBox" editable="true" HBox.hgrow="ALWAYS" maxWidth="Infinity"/>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue