From a3aa3af70b0c268326f317e32479a35fb54c48c0 Mon Sep 17 00:00:00 2001 From: Safak Date: Sun, 8 Dec 2024 00:00:37 +0100 Subject: [PATCH] Begfix Sortierung und Filterung in PrivateBank.java --- src/main/java/bank/PrivateBank.java | 23 +- src/main/java/ui/AccountviewController.java | 245 ++++++++++++++++++-- src/main/java/ui/MainviewController.java | 112 ++++++--- src/main/java/ui/main.java | 13 ++ src/main/resources/Accountview.fxml | 7 +- src/main/resources/Mainview.fxml | 7 +- 6 files changed, 345 insertions(+), 62 deletions(-) diff --git a/src/main/java/bank/PrivateBank.java b/src/main/java/bank/PrivateBank.java index 5a435c1..ea2b3ae 100644 --- a/src/main/java/bank/PrivateBank.java +++ b/src/main/java/bank/PrivateBank.java @@ -163,7 +163,7 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser */ @Override - public void createAccount(String account, List transactions) throws AccountAlreadyExistsException, TransactionAlreadyExistException, TransactionAttributeException, IOException { + public void createAccount(String account, List transactions) throws AccountAlreadyExistsException, TransactionAlreadyExistException, TransactionAttributeException { createAccount(account); for (Transaction transaction : transactions) { if (this.accountsToTransactions.get(account).contains(transaction)) @@ -221,7 +221,7 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser // 2 setting as incoming transfer else if (transaction instanceof IncomingTransfer) { - if (((IncomingTransfer) transaction).getSender().equals("") || ((IncomingTransfer) transaction).getRecipient().equals("")) + if (((IncomingTransfer) transaction).getSender().isEmpty() || ((IncomingTransfer) transaction).getRecipient().equals("")) throw new TransactionAttributeException("Transfer without sender or recipient"); else if (((IncomingTransfer) transaction).getRecipient().equals(account)) @@ -232,7 +232,7 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser // 3 setting as outgoing transfer else if (transaction instanceof OutgoingTransfer) { - if (((OutgoingTransfer) transaction).getSender().equals("") || ((OutgoingTransfer) transaction).getRecipient().equals("")) + if (((OutgoingTransfer) transaction).getSender().isEmpty() || ((OutgoingTransfer) transaction).getRecipient().isEmpty()) throw new TransactionAttributeException("Transfer without sender or recipient"); else if (((OutgoingTransfer) transaction).getSender().equals(account)) @@ -332,8 +332,16 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser */ @Override public List getTransactionsSorted(String account, boolean asc) { - List transactions = this.accountsToTransactions.get(account); - transactions.sort(Comparator.comparingDouble(Transaction::calculate)); + List transactions = new ArrayList<>(this.accountsToTransactions.get(account)); + + if (transactions == null || transactions.isEmpty()) + return new ArrayList<>(); + + if (asc) + transactions.sort(Comparator.comparingDouble(Transaction::calculate)); + else + transactions.sort(Comparator.comparingDouble(Transaction::calculate).reversed()); + return transactions; } @@ -346,7 +354,8 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser */ @Override public List getTransactionsByType(String account, boolean positive) { - List transactions = this.accountsToTransactions.get(account); + // an der Kopie der Liste Arbeiten oder nur Filtern und nicht entfernen + List transactions = new ArrayList<>(this.accountsToTransactions.get(account)); if (positive) transactions.removeIf(transaction -> transaction.calculate() >= 0); else @@ -400,7 +409,7 @@ public class PrivateBank implements Bank, JsonSerializer, JsonDeser * * @throws IOException if an error occurs while deserializing */ - public void readAccounts() throws IOException, java.io.IOException, AccountAlreadyExistsException, TransactionAlreadyExistException, AccountDoesNotExistException, TransactionAttributeException { + public void readAccounts() throws java.io.IOException, AccountAlreadyExistsException, TransactionAlreadyExistException, TransactionAttributeException { /* 1. JSONs einlesen 2. for each Transaction diff --git a/src/main/java/ui/AccountviewController.java b/src/main/java/ui/AccountviewController.java index ff68aca..cb26a16 100644 --- a/src/main/java/ui/AccountviewController.java +++ b/src/main/java/ui/AccountviewController.java @@ -2,15 +2,21 @@ package ui; import bank.PrivateBank; import bank.Transaction; +import bank.exceptions.AccountDoesNotExistException; +import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; +import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.control.*; +import javafx.scene.layout.GridPane; import javafx.stage.Stage; import java.io.IOException; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public class AccountviewController { @@ -21,27 +27,80 @@ public class AccountviewController { private Label balanceLabel; @FXML - private ListView transactionListView; + private ListView transactionListView; private PrivateBank privateBank; private String currentAccount; + /** + * Creates a second copied instance of a Bank + * + * @param accountName + * @param bank + */ public void setAccount(String accountName, PrivateBank bank) { this.currentAccount = accountName; this.privateBank = bank; updateAccountInfo(); loadTransactions(); + + // Kontextmenü erstellen + ContextMenu contextMenu = new ContextMenu(); + + // Kontextmenü-Items definieren + MenuItem deleteItem = new MenuItem("Löschen"); + + // Kontextmenü-Item Aktion: Transaktion löschen + deleteItem.setOnAction( + event -> { + Transaction selectedTransaction = transactionListView.getSelectionModel().getSelectedItem(); + if (selectedTransaction != null) { + boolean confirmed = showDeleteConfirmation(selectedTransaction); + if (confirmed) { + Alert errorAlert = new Alert(Alert.AlertType.ERROR); + errorAlert.setTitle("Fehler"); + try { + privateBank.removeTransaction(currentAccount, selectedTransaction); + transactionListView.getItems().remove(selectedTransaction); + updateAccountInfo(); + } catch (AccountDoesNotExistException e) { + errorAlert.setHeaderText("Account existiert nicht"); + errorAlert.setContentText("Der Account \"" + currentAccount + "\" existiert nicht."); + errorAlert.showAndWait(); + } catch (bank.exceptions.IOException e) { + errorAlert.setHeaderText("Account JSON Fehler"); + errorAlert.setContentText("Die JSON des Accounts \"" + currentAccount + "\" konnte nicht bearbeitet werden."); + errorAlert.showAndWait(); + } catch (Exception e) { + e.printStackTrace(); + errorAlert.setHeaderText("Transaktion konnte nicht gelöscht werden."); + errorAlert.setContentText("Es ist ein unerwarteter Fehler aufgetreten."); + errorAlert.showAndWait(); + } + } + } + } + ); + + // Kontextmenü-Items dem Kontextmenü hinzufügen + contextMenu.getItems().add(deleteItem); + + // An ListView binden + transactionListView.setContextMenu(contextMenu); } + /** + * Updates the labels of an account + */ private void updateAccountInfo() { + double balance = this.privateBank.getAccountBalance(currentAccount); + accountNameLabel.setText("Account: " + currentAccount); - double balance = privateBank.getAccountBalance(currentAccount); balanceLabel.setText("Balance: " + balance); } private void loadTransactions() { - var transactions = privateBank.getTransactions(currentAccount); - showTransactions(transactions); + showTransactions(this.privateBank.getTransactions(currentAccount)); } @FXML @@ -59,40 +118,192 @@ public class AccountviewController { @FXML private void onSortAscending() { - var sortedTransactions = privateBank.getTransactionsSorted(currentAccount, true); - showTransactions(sortedTransactions); + showTransactions(this.privateBank.getTransactionsSorted(currentAccount, true)); } @FXML private void onSortDescending() { - var sortedTransactions = privateBank.getTransactionsSorted(currentAccount, false); - showTransactions(sortedTransactions); + showTransactions(this.privateBank.getTransactionsSorted(currentAccount, false)); } @FXML private void onShowPositive() { - var positive = privateBank.getTransactionsByType(currentAccount, true); - showTransactions(positive); + showTransactions(this.privateBank.getTransactionsByType(currentAccount, false)); } @FXML private void onShowNegative() { - var negative = privateBank.getTransactionsByType(currentAccount, false); - showTransactions(negative); + showTransactions(this.privateBank.getTransactionsByType(currentAccount, true)); } @FXML private void onShowAll() { - var all = privateBank.getTransactions(currentAccount); - showTransactions(all); + System.out.println(this.privateBank.getTransactions(currentAccount)); + showTransactions(this.privateBank.getTransactions(currentAccount)); } + /** + * Sets the Listview of transaction based on a given list + * + * @param transactions + */ private void showTransactions(List transactions) { List displayList = new ArrayList<>(); - for (var t : transactions) { + for (Transaction t : transactions) displayList.add(t.toString()); - } - transactionListView.getItems().setAll(displayList); + + transactionListView.getItems().setAll(transactions); updateAccountInfo(); // Balance neu anzeigen, falls sich was geändert hat } + + private boolean showDeleteConfirmation(Transaction transaction) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("Transaktion löschen"); + alert.setHeaderText("Soll die Transaktion wirklich gelöscht werden?"); + alert.setContentText("Transaktion:\n" + transaction.toString() + "\n\nDiese Aktion kann nicht rückgängig gemacht werden."); + + ButtonType yesButton = new ButtonType("Ja", ButtonBar.ButtonData.YES); + ButtonType noButton = new ButtonType("Nein", ButtonBar.ButtonData.NO); + + alert.getButtonTypes().setAll(yesButton, noButton); + + var result = alert.showAndWait(); + return result.isPresent() && result.get() == yesButton; + } + + private boolean validateTransactionInput(ComboBox typeComboBox, TextField amountField, TextField descriptionField, TextField senderReceiverField) { + String type = typeComboBox.getValue(); + String amountStr = amountField.getText().trim(); + String desc = descriptionField.getText().trim(); + + // Basis-Checks + if (desc.isEmpty()) return false; + double amount; + try { + amount = Double.parseDouble(amountStr); + } catch (NumberFormatException e) { + return false; + } + + if (type.equals("Transfer")) { + String partner = senderReceiverField.getText().trim(); + if (partner.isEmpty()) return false; + } + + return true; + } + + private Optional showNewTransactionDialog() { + Dialog dialog = new Dialog<>(); + dialog.setTitle("Neue Transaktion"); + dialog.setHeaderText("Bitte geben Sie die Daten der neuen Transaktion ein."); + + // Buttons + ButtonType okButton = new ButtonType("OK", ButtonBar.ButtonData.OK_DONE); + ButtonType cancelButton = new ButtonType("Abbrechen", ButtonBar.ButtonData.CANCEL_CLOSE); + dialog.getDialogPane().getButtonTypes().addAll(okButton, cancelButton); + + // UI-Elemente + Label typeLabel = new Label("Typ:"); + ComboBox typeComboBox = new ComboBox<>(); + typeComboBox.getItems().addAll("Payment", "Transfer"); + typeComboBox.getSelectionModel().selectFirst(); // Default Payment + + Label amountLabel = new Label("Betrag:"); + TextField amountField = new TextField(); + + Label descriptionLabel = new Label("Beschreibung:"); + TextField descriptionField = new TextField(); + + Label senderReceiverLabel = new Label("Partner-Konto (nur bei Transfer):"); + TextField senderReceiverField = new TextField(); + + // Layout + GridPane grid = new GridPane(); + grid.setHgap(10); + grid.setVgap(10); + + grid.add(typeLabel, 0, 0); + grid.add(typeComboBox, 1, 0); + + grid.add(amountLabel, 0, 1); + grid.add(amountField, 1, 1); + + grid.add(descriptionLabel, 0, 2); + grid.add(descriptionField, 1, 2); + + grid.add(senderReceiverLabel, 0, 3); + grid.add(senderReceiverField, 1, 3); + + dialog.getDialogPane().setContent(grid); + + // OK-Button Validation + Node okBtnNode = dialog.getDialogPane().lookupButton(okButton); + okBtnNode.addEventFilter(ActionEvent.ACTION, event -> { + // Validierung + if (!validateTransactionInput(typeComboBox, amountField, descriptionField, senderReceiverField)) { + event.consume(); // Verhindere schließen des Dialogs + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("Ungültige Eingabe"); + alert.setHeaderText("Bitte alle Felder korrekt ausfüllen."); + alert.setContentText("Betrag muss eine Zahl sein, Beschreibung darf nicht leer sein.\n" + + "Für Transfer muss ein gültiges Partner-Konto angegeben werden."); + alert.showAndWait(); + } + }); + + dialog.setResultConverter(dialogButton -> { + if (dialogButton == okButton) { + try { + String type = typeComboBox.getValue(); + double amount = Double.parseDouble(amountField.getText()); + String description = descriptionField.getText().trim(); + String date = LocalDate.now().toString(); + + if (type.equals("Payment")) { + return new bank.Payment(date, amount, description); + } else { + String partnerAccount = senderReceiverField.getText().trim(); + if (partnerAccount.isEmpty()) return null; + + if (!partnerAccount.equals(currentAccount)) { + // OutgoingTransfer: currentAccount -> partnerAccount + return new bank.OutgoingTransfer(date, amount, description, currentAccount, partnerAccount); + } else { + // IncomingTransfer: partnerAccount -> currentAccount + return new bank.IncomingTransfer(date, amount, description, partnerAccount, currentAccount); + } + } + + } catch (NumberFormatException e) { + // Sollte nie hier landen, da oben schon abgefangen, aber falls doch: + return null; + } + } + return null; + }); + + return dialog.showAndWait(); + } + + @FXML + private void onNewTransactionClicked() { + Optional transactionOpt = showNewTransactionDialog(); + if (transactionOpt.isPresent()) { + Transaction transaction = transactionOpt.get(); + try { + privateBank.addTransaction(currentAccount, transaction); + loadTransactions(); // Liste neu laden, um neue Transaktion anzuzeigen + updateAccountInfo(); // Kontostand aktualisieren + } catch (Exception e) { + // Fehler beim Hinzufügen anzeigen + Alert errorAlert = new Alert(Alert.AlertType.ERROR); + errorAlert.setTitle("Fehler"); + errorAlert.setHeaderText("Transaktion konnte nicht hinzugefügt werden."); + errorAlert.setContentText("Überprüfen Sie Ihre Eingaben oder versuchen Sie es später erneut."); + errorAlert.showAndWait(); + } + } + } + } diff --git a/src/main/java/ui/MainviewController.java b/src/main/java/ui/MainviewController.java index 0277c70..228a63d 100644 --- a/src/main/java/ui/MainviewController.java +++ b/src/main/java/ui/MainviewController.java @@ -2,12 +2,15 @@ package ui; import bank.PrivateBank; +import bank.exceptions.AccountAlreadyExistsException; +import bank.exceptions.IOException; import javafx.fxml.*; import javafx.scene.Parent; import javafx.scene.control.*; import javafx.scene.input.MouseButton; import javafx.stage.Stage; +import java.awt.event.ActionEvent; import java.util.List; import java.util.Optional; @@ -19,61 +22,53 @@ public class MainviewController { private PrivateBank privateBank; // Referenz auf Ihr Bankobjekt + /** + * + */ public void initialize() { - // Bank initialisieren oder übergeben lassen - this.privateBank = new PrivateBank( - "Bank1", - 0, - 0, - "accountdata" - ); - - List accounts = List.of( - "Konto1", "Konto2", "Konto3" - ); - - for (String account : accounts) { - try { - privateBank.createAccount(account); - privateBank.writeAccount(account); - } catch (Exception e) { - } - } + // Bank initialisieren + this.privateBank = main.getPrivateBank(); + // Zeige alle vorhandenen Konten an accountListView.getItems().addAll(privateBank.getAllAccounts()); // Kontextmenü definieren ContextMenu contextMenu = new ContextMenu(); + + // Kontextmenü-Items definieren MenuItem selectItem = new MenuItem("Auswählen"); MenuItem deleteItem = new MenuItem("Löschen"); - // Aktionen definieren - selectItem.setOnAction(event -> { - String selectedAccount = accountListView.getSelectionModel().getSelectedItem(); - if (selectedAccount != null) { - switchToAccountView(selectedAccount); - } - }); + // Kontextmenü-Item Aktion: Konto auswählen + selectItem.setOnAction( + event -> { + String selectedAccount = accountListView.getSelectionModel().getSelectedItem(); + if (selectedAccount != null) + switchToAccountView(selectedAccount); + } + ); + // Kontextmenü-Item Aktion: Konto löschen deleteItem.setOnAction( event -> { String selectedAccount = accountListView.getSelectionModel().getSelectedItem(); if (selectedAccount != null) { boolean confirmed = showDeleteConfirmation(selectedAccount); if (confirmed) { - // Account aus der Bank entfernen + // Account löschen try { privateBank.deleteAccount(selectedAccount); // ListView aktualisieren accountListView.getItems().remove(selectedAccount); } catch (Exception e) { e.printStackTrace(); - // Fehlerbehandlung falls nötig } } } - }); + } + ); + // Kontextmenü-Items dem Kontextmenü hinzufügen contextMenu.getItems().addAll(selectItem, deleteItem); // Kontextmenü an die ListView binden @@ -92,6 +87,9 @@ public class MainviewController { ); } + /** + * @param accountName + */ private void switchToAccountView(String accountName) { try { // Laden der zweiten FXML @@ -102,7 +100,7 @@ public class MainviewController { AccountviewController accountController = loader.getController(); accountController.setAccount(accountName, privateBank); - // Scene in der selben Stage wechseln + // Scene in derselben Stage wechseln Stage stage = (Stage) accountListView.getScene().getWindow(); stage.getScene().setRoot(root); @@ -111,6 +109,10 @@ public class MainviewController { } } + /** + * @param accountName + * @return + */ private boolean showDeleteConfirmation(String accountName) { Alert alert = new Alert(Alert.AlertType.CONFIRMATION); alert.setTitle("Account löschen"); @@ -126,4 +128,54 @@ public class MainviewController { return result.isPresent() && result.get() == yesButton; } + + @FXML + private void onNewAccountClicked() { + // Dialog zum Eingeben eines neuen Account-Namens + TextInputDialog dialog = new TextInputDialog(); + dialog.setTitle("Neuen Account erstellen"); + dialog.setHeaderText("Bitte geben Sie den Namen des neuen Accounts ein:"); + dialog.setContentText("Account-Name:"); + + Optional result = dialog.showAndWait(); + if (result.isPresent()) { + String newAccountName = result.get().trim(); + if (!newAccountName.isEmpty()) { + Alert errorAlert = new Alert(Alert.AlertType.ERROR); + errorAlert.setTitle("Fehler"); + try { + // Account erstellen + privateBank.createAccount(newAccountName); + privateBank.writeAccount(newAccountName); + + // neuen Account der Listview hinzufügen + if (!accountListView.getItems().contains(newAccountName)) + accountListView.getItems().add(newAccountName); + + } catch (AccountAlreadyExistsException e) { + errorAlert.setHeaderText("Account existiert bereits"); + errorAlert.setContentText("Der Account \"" + newAccountName + "\" wurde bereits angelegt."); + errorAlert.showAndWait(); + } catch (IOException e) { + errorAlert.setHeaderText("Account JSON Fehler"); + errorAlert.setContentText("Die JSON des Accounts \"" + newAccountName + "\" konnte nicht bearbeitet werden."); + errorAlert.showAndWait(); + } catch (Exception e) { + e.printStackTrace(); + + errorAlert.setHeaderText("Account konnte nicht erstellt werden."); + errorAlert.setContentText("Überprüfen Sie, ob der Name bereits existiert oder ein anderer Fehler vorliegt."); + errorAlert.showAndWait(); + } + } else { + // Leeren Namen nicht akzeptieren + Alert alert = new Alert(Alert.AlertType.WARNING); + alert.setTitle("Warnung"); + alert.setHeaderText("Ungültiger Account-Name"); + alert.setContentText("Bitte geben Sie einen gültigen Namen ein."); + alert.showAndWait(); + } + } + } + } \ No newline at end of file diff --git a/src/main/java/ui/main.java b/src/main/java/ui/main.java index 766848f..3595a81 100644 --- a/src/main/java/ui/main.java +++ b/src/main/java/ui/main.java @@ -1,11 +1,17 @@ package ui; +import bank.PrivateBank; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; public class main extends Application { + /** + * Starting point + * @param primaryStage + * @throws Exception + */ @Override public void start(Stage primaryStage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("/Mainview.fxml")); @@ -17,4 +23,11 @@ public class main extends Application { public static void main(String[] args) { launch(args); } + + private static PrivateBank privateBank = new PrivateBank("Bank1", 0, 0, "accountdata"); + + public static PrivateBank getPrivateBank() { + return privateBank; + } + } diff --git a/src/main/resources/Accountview.fxml b/src/main/resources/Accountview.fxml index f4bac5e..2e11f22 100644 --- a/src/main/resources/Accountview.fxml +++ b/src/main/resources/Accountview.fxml @@ -11,21 +11,24 @@