From 20d5c48bdd0d278699f48a6d91ab71370033c3ad Mon Sep 17 00:00:00 2001 From: Harry Linrui XU <xulr0820@hotmail.com> Date: Fri, 31 Mar 2023 13:01:17 +0200 Subject: [PATCH] "Implemented add, edit and delete functionalities. Synch piecharts to register" --- .../controller/IncomeExpenseController.java | 226 ++++++++++++++++-- .../resources/view/IncomeAndExpenses.fxml | 137 +++++------ 2 files changed, 277 insertions(+), 86 deletions(-) diff --git a/src/main/java/no/ntnu/idatt1002/demo/controller/IncomeExpenseController.java b/src/main/java/no/ntnu/idatt1002/demo/controller/IncomeExpenseController.java index e51d3b3a..53d9223d 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/controller/IncomeExpenseController.java +++ b/src/main/java/no/ntnu/idatt1002/demo/controller/IncomeExpenseController.java @@ -3,7 +3,6 @@ package no.ntnu.idatt1002.demo.controller; import java.awt.event.ActionEvent; import java.io.IOException; import java.util.Optional; -import javafx.beans.binding.Bindings; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -14,16 +13,21 @@ import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.chart.PieChart; import javafx.scene.chart.PieChart.Data; +import javafx.scene.control.Alert; +import javafx.scene.control.Alert.AlertType; import javafx.scene.control.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.DatePicker; +import javafx.scene.control.Dialog; import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; import javafx.scene.control.ProgressBar; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.text.Text; +import javafx.stage.Modality; import javafx.stage.Stage; import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudget; import no.ntnu.idatt1002.demo.data.Budget.GeneralBudget; @@ -80,7 +84,10 @@ public class IncomeExpenseController implements FinanceController { private Text expSum; @FXML - private Button addBtn; + private MenuItem addExpense; + + @FXML + private MenuItem addIncome; @FXML private Button deleteBtn; @@ -105,8 +112,6 @@ public class IncomeExpenseController implements FinanceController { @FXML private Label title; - - private FinanceMode financeMode; private IncomeRegister incomeRegister; private ExpenseRegister expenseRegister; @@ -141,12 +146,10 @@ public class IncomeExpenseController implements FinanceController { expenses = FXCollections.observableArrayList(expenseRegister.getItems()); expenseTableView.setItems(expenses); - incomePieChart.getData().addAll(createIncomePyChart()); - incomePieChart.setTitle("Income"); + refreshPieCharts(); //TODO THIS IS FUCKED. DISPLAYS EXPENSE CATEGORIES incomePieChart.setLegendSide(Side.RIGHT); - expensePieChart.setData(createExpensePyChart()); - expensePieChart.setTitle("Expenses"); + refreshPieCharts(); expensePieChart.setLegendSide(Side.RIGHT); expensePieChart.setLabelLineLength(10); @@ -169,7 +172,7 @@ public class IncomeExpenseController implements FinanceController { expRecurringCol.setCellValueFactory(new PropertyValueFactory<Expense, Boolean>("recurring")); } - private ObservableList<PieChart.Data> createExpensePyChart() { + private ObservableList<PieChart.Data> createExpensePieChart() { return FXCollections.observableArrayList( new Data("Food", expenseRegister.getExpenseByCategory(ExpenseCategory.FOOD).getTotalSum()), new Data("Books", expenseRegister.getExpenseByCategory(ExpenseCategory.BOOKS).getTotalSum()), @@ -178,10 +181,11 @@ public class IncomeExpenseController implements FinanceController { ); } - private ObservableList<PieChart.Data> createIncomePyChart() { + private ObservableList<PieChart.Data> createIncomePieChart() { return FXCollections.observableArrayList( - new Data("Food", incomeRegister.getIncomeByCategory(IncomeCategory.STUDENT_LOAN).getTotalSum()), - new Data("Books", incomeRegister.getIncomeByCategory(IncomeCategory.SALARY).getTotalSum()) + new Data("Loans", incomeRegister.getIncomeByCategory(IncomeCategory.GIFT).getTotalSum()), + new Data("Salary", incomeRegister.getIncomeByCategory(IncomeCategory.SALARY).getTotalSum()), + new Data("Salary", incomeRegister.getIncomeByCategory(IncomeCategory.STUDENT_LOAN).getTotalSum()) ); } @@ -190,8 +194,12 @@ public class IncomeExpenseController implements FinanceController { * @param event A button click on the add button. */ @Override - public void handleAddBtn(ActionEvent event) { - handleEditBtn(event); + public void handleAddBtn(javafx.event.ActionEvent event) { + if (event.getSource() == addIncome) { + handleAddIncome(); + } else if (event.getSource() == addExpense){ + handleAddExpense(); + } } /** @@ -200,8 +208,15 @@ public class IncomeExpenseController implements FinanceController { * @param event A button click on the edit button. */ @Override - public void handleEditBtn(ActionEvent event) { - + public void handleEditBtn(javafx.event.ActionEvent event) { + Income chosenIncome = incomeTableView.getSelectionModel().getSelectedItem(); + Expense chosenExpense = expenseTableView.getSelectionModel().getSelectedItem(); + + if (chosenIncome!= null) { + handleEditIncome(chosenIncome); + } else if (chosenExpense != null) { + handleEditExpense(chosenExpense); + } } /** @@ -211,7 +226,15 @@ public class IncomeExpenseController implements FinanceController { * @param event A button click on the delete button */ @Override - public void handleDeleteBtn(ActionEvent event) { + public void handleDeleteBtn(javafx.event.ActionEvent event) { + Income chosenIncome = incomeTableView.getSelectionModel().getSelectedItem(); + Expense chosenExpense = expenseTableView.getSelectionModel().getSelectedItem(); + + if (chosenIncome != null) { + handleDeleteIncome(chosenIncome); + } else if (chosenExpense != null) { + handleDeleteExpense(chosenExpense); + } } /** @@ -227,8 +250,168 @@ public class IncomeExpenseController implements FinanceController { this.expenses.setAll(expenseRegister.getItems()); //this.sum.setText(String.valueOf(incomeRegister.getTotalSum())); } + + private void refreshPieCharts() { + this.refreshPieCharts(); + this.refreshPieCharts(); + } - /** + @FXML + private void handleAddIncome() { + //Instantiate FXML loader and loads the popup for adding income + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource("/view/AddIncome.fxml")); + + Income newIncome = null; + String dialogTitle = "Add income"; + // Load the FXML file for your dialog box + Dialog<Income> dialog = new Dialog<>(); + dialog.initModality(Modality.APPLICATION_MODAL); + + try { + // Set the Dialog's content to the loaded FXML file + dialog.getDialogPane().setContent(loader.load()); + } catch (IOException e) { + e.printStackTrace(); + } + + // Get the controller for the loaded FXML file + AddIncomeController dialogController = loader.getController(); + //Sets the title of the dialog box + dialog.setTitle(dialogTitle); + // Show the Dialog and wait for the user to close it + dialog.showAndWait(); + //Get the newly created income from the dialog pane + newIncome = dialogController.getNewIncome(); + + //Adds the new item to the register + if (newIncome != null) { + incomeRegister.addItem(newIncome); + } + //Updates the tableview using the register + refreshTableView(); + refreshPieCharts(); + } + + @FXML + private void handleAddExpense() { + //Instantiate FXML loader and loads the popup for adding expense + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource("/view/AddExpense.fxml")); + + Expense newExpense = null; + String dialogTitle = "Add expense"; + // Load the FXML file for your dialog box + Dialog<Expense> dialog = new Dialog<>(); + dialog.initModality(Modality.APPLICATION_MODAL); + + try { + // Set the Dialog's content to the loaded FXML file + dialog.getDialogPane().setContent(loader.load()); + } catch (IOException e) { + e.printStackTrace(); + } + + // Get the controller for the loaded FXML file + AddExpenseController dialogController = loader.getController(); + + dialog.setTitle(dialogTitle); + // Show the Dialog and wait for the user to close it + dialog.showAndWait(); + + //Get the newly created expense from the dialog pane + newExpense = dialogController.getNewExpense(); + + //Adds the new item to the register + if (newExpense != null) { + expenseRegister.addItem(newExpense); + } + //Updates the tableview using the register + refreshTableView(); + refreshPieCharts(); + } + + @FXML + private void handleEditIncome(Income chosenIncome) { + //Instantiate FXML loader and loads the popup for adding income + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource("/view/AddIncome.fxml")); + + String dialogTitle = "Edit income"; + // Load the FXML file for your dialog box + Dialog<Income> dialog = new Dialog<>(); + dialog.initModality(Modality.APPLICATION_MODAL); + + try { + // Set the Dialog's content to the loaded FXML file + dialog.getDialogPane().setContent(loader.load()); + } catch (IOException e) { + e.printStackTrace(); + } + + // Get the controller for the loaded FXML file + AddIncomeController dialogController = loader.getController(); + //Binds the selected item to another item which is defined in the ItemController + dialogController.setIncome(chosenIncome); + + dialog.setTitle(dialogTitle); + // Show the Dialog and wait for the user to close it + dialog.showAndWait(); + //Updates the tableview using the register + refreshTableView(); + refreshPieCharts(); + } + + @FXML + private void handleEditExpense(Expense chosenExpense) { + //Instantiate FXML loader and loads the popup for adding expense + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(getClass().getResource("/view/AddExpense.fxml")); + + String dialogTitle = "Edit expense"; + // Load the FXML file for your dialog box + Dialog<Expense> dialog = new Dialog<>(); + dialog.initModality(Modality.APPLICATION_MODAL); + + try { + // Set the Dialog's content to the loaded FXML file + dialog.getDialogPane().setContent(loader.load()); + } catch (IOException e) { + e.printStackTrace(); + } + + // Get the controller for the loaded FXML file + AddExpenseController dialogController = loader.getController(); + //Binds the selected item to another item which is defined in the ItemController + dialogController.setExpense(chosenExpense); + dialog.setTitle(dialogTitle); + // Show the Dialog and wait for the user to close it + dialog.showAndWait(); + //Updates the tableview using the register + refreshTableView(); + refreshPieCharts(); + } + + @FXML + private void handleDeleteIncome(Income chosenIncome) { + Optional<ButtonType> isConfirmed = showConfirmationDialog(); + if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) { + incomeRegister.removeItem(chosenIncome); + refreshTableView(); + + } + } + + @FXML + private void handleDeleteExpense(Expense chosenExpense) { + Optional<ButtonType> isConfirmed = showConfirmationDialog(); + if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) { + expenseRegister.removeItem(chosenExpense); + refreshTableView(); + } + + } + /** * Returns an optional, which is a popup alert box, asking for confirmation for deleting an * entry. * @@ -236,7 +419,12 @@ public class IncomeExpenseController implements FinanceController { */ @Override public Optional<ButtonType> showConfirmationDialog() { - return Optional.empty(); + Alert alert = new Alert(AlertType.CONFIRMATION); + alert.setTitle("Confirm Delete"); + alert.setHeaderText("Delete Confirmation"); + alert.setContentText("Are you sure you would like to delete the selected entry?"); + + return alert.showAndWait(); } /** diff --git a/src/main/resources/view/IncomeAndExpenses.fxml b/src/main/resources/view/IncomeAndExpenses.fxml index 33e54922..480b937c 100644 --- a/src/main/resources/view/IncomeAndExpenses.fxml +++ b/src/main/resources/view/IncomeAndExpenses.fxml @@ -8,6 +8,7 @@ <?import javafx.scene.control.ContextMenu?> <?import javafx.scene.control.DatePicker?> <?import javafx.scene.control.Label?> +<?import javafx.scene.control.MenuButton?> <?import javafx.scene.control.MenuItem?> <?import javafx.scene.control.ProgressBar?> <?import javafx.scene.control.TableColumn?> @@ -23,6 +24,7 @@ <?import javafx.scene.layout.RowConstraints?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.text.Font?> +<?import javafx.scene.text.Text?> <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="695.0" prefWidth="1130.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.IncomeExpenseController"> <children> @@ -75,10 +77,11 @@ <left> <HBox prefHeight="100.0" prefWidth="200.0" spacing="10.0" BorderPane.alignment="CENTER"> <children> - <Button fx:id="addBtn" mnemonicParsing="false" prefHeight="25.0" prefWidth="60.0"> - <font> - <Font name="Lucida Console" size="12.0" /> - </font> + <MenuButton mnemonicParsing="false" prefHeight="25.0" prefWidth="50.0"> + <items> + <MenuItem fx:id="addIncome" mnemonicParsing="false" onAction="#handleAddBtn" text="Income" /> + <MenuItem fx:id="addExpense" mnemonicParsing="false" onAction="#handleAddBtn" text="Expense" /> + </items> <graphic> <ImageView fitHeight="30.0" fitWidth="50.0" pickOnBounds="true" preserveRatio="true"> <image> @@ -86,16 +89,8 @@ </image> </ImageView> </graphic> - <contextMenu> - <ContextMenu> - <items> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - </items> - </ContextMenu> - </contextMenu> - </Button> - <Button fx:id="editBtn" mnemonicParsing="false" prefHeight="25.0" prefWidth="60.0"> + </MenuButton> + <Button fx:id="editBtn" mnemonicParsing="false" onAction="#handleEditBtn" prefHeight="25.0" prefWidth="60.0"> <font> <Font name="Lucida Console" size="12.0" /> </font> @@ -106,16 +101,8 @@ </image> </ImageView> </graphic> - <contextMenu> - <ContextMenu> - <items> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - </items> - </ContextMenu> - </contextMenu> </Button> - <Button fx:id="deleteBtn" mnemonicParsing="false" prefHeight="25.0" prefWidth="50.0"> + <Button fx:id="deleteBtn" mnemonicParsing="false" prefHeight="25.0" prefWidth="60.0"> <font> <Font name="Lucida Console" size="12.0" /> </font> @@ -126,14 +113,6 @@ </image> </ImageView> </graphic> - <contextMenu> - <ContextMenu> - <items> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - <MenuItem mnemonicParsing="false" text="Unspecified Action" /> - </items> - </ContextMenu> - </contextMenu> </Button> </children> <BorderPane.margin> @@ -166,17 +145,19 @@ </Pane> </center> </BorderPane> - <GridPane prefHeight="473.0" prefWidth="1100.0"> + <GridPane prefHeight="473.0" prefWidth="1055.0"> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> </columnConstraints> <rowConstraints> + <RowConstraints minHeight="10.0" percentHeight="5.0" prefHeight="30.0" vgrow="SOMETIMES" /> <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" percentHeight="4.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> </rowConstraints> <children> - <GridPane> + <GridPane GridPane.rowIndex="1"> <columnConstraints> <ColumnConstraints hgrow="ALWAYS" maxWidth="485.3333231608073" minWidth="10.0" prefWidth="427.33335367838544" /> </columnConstraints> @@ -197,6 +178,13 @@ <columnResizePolicy> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> </columnResizePolicy> + <contextMenu> + <ContextMenu> + <items> + <MenuItem mnemonicParsing="false" text="Unspecified Action" /> + </items> + </ContextMenu> + </contextMenu> </TableView> <Label text="Sum: "> <font> @@ -207,45 +195,60 @@ </VBox> </children> </GridPane> - <GridPane GridPane.rowIndex="1"> - <columnConstraints> - <ColumnConstraints hgrow="ALWAYS" maxWidth="485.3333231608073" minWidth="10.0" prefWidth="427.33335367838544" /> - </columnConstraints> - <rowConstraints> - <RowConstraints maxHeight="298.66665744781494" minHeight="10.0" prefHeight="214.00004069010413" vgrow="SOMETIMES" /> - </rowConstraints> + <Pane GridPane.columnIndex="1" GridPane.rowIndex="1"> <children> - <VBox> - <children> - <TableView fx:id="expenseTableView" maxHeight="175.0" prefHeight="172.0" prefWidth="545.0"> - <columns> - <TableColumn fx:id="expDateCol" prefWidth="75.0" text="Date" /> - <TableColumn fx:id="expAmountCol" prefWidth="75.0" text="Amount" /> - <TableColumn fx:id="expCategoryCol" prefWidth="75.0" text="Category" /> - <TableColumn fx:id="expDescriptionCol" prefWidth="75.0" text="Description" /> - <TableColumn fx:id="expRecurringCol" prefWidth="75.0" text="Recurring" /> - </columns> - <columnResizePolicy> - <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> - </columnResizePolicy> - </TableView> - <Label text="Sum: "> - <font> - <Font name="Lucida Console" size="14.0" /> - </font> - </Label> - </children> - </VBox> + <PieChart fx:id="incomePieChart" layoutX="4.0" layoutY="-41.0" legendSide="RIGHT" maxHeight="244.0" maxWidth="512.0" prefHeight="244.0" prefWidth="350.0" title="Income" /> </children> - </GridPane> - <Pane GridPane.columnIndex="1"> + </Pane> + <Pane GridPane.columnIndex="1" GridPane.rowIndex="3"> <children> - <PieChart fx:id="incomePieChart" layoutX="4.0" layoutY="-18.0" legendSide="RIGHT" maxHeight="226.0" maxWidth="512.0" prefHeight="214.0" prefWidth="350.0" title="Income" /> + <PieChart fx:id="expensePieChart" layoutX="-2.0" layoutY="-37.0" legendSide="RIGHT" maxHeight="261.0" maxWidth="519.0" prefHeight="237.0" prefWidth="350.0" title="Expenses" /> </children> </Pane> - <Pane GridPane.columnIndex="1" GridPane.rowIndex="1"> + <Pane prefHeight="20.0" prefWidth="1046.0"> <children> - <PieChart fx:id="expensePieChart" layoutX="-2.0" layoutY="-27.0" legendSide="RIGHT" maxHeight="247.0" maxWidth="519.0" prefHeight="227.0" prefWidth="350.0" title="Expenses" /> + <Text layoutY="16.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Income" textAlignment="CENTER"> + <font> + <Font name="Lucida Console" size="14.0" /> + </font> + </Text> + </children> + </Pane> + <VBox GridPane.rowIndex="3"> + <children> + <TableView fx:id="expenseTableView" maxHeight="175.0" maxWidth="490.0" prefHeight="172.0" prefWidth="264.0"> + <columns> + <TableColumn fx:id="expDateCol" prefWidth="75.0" text="Date" /> + <TableColumn fx:id="expAmountCol" prefWidth="75.0" text="Amount" /> + <TableColumn fx:id="expCategoryCol" prefWidth="75.0" text="Category" /> + <TableColumn fx:id="expDescriptionCol" prefWidth="75.0" text="Description" /> + <TableColumn fx:id="expRecurringCol" prefWidth="75.0" text="Recurring" /> + </columns> + <columnResizePolicy> + <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> + </columnResizePolicy> + <contextMenu> + <ContextMenu> + <items> + <MenuItem mnemonicParsing="false" text="Unspecified Action" /> + </items> + </ContextMenu> + </contextMenu> + </TableView> + <Label text="Sum: "> + <font> + <Font name="Lucida Console" size="14.0" /> + </font> + </Label> + </children> + </VBox> + <Pane prefHeight="200.0" prefWidth="200.0" GridPane.rowIndex="2"> + <children> + <Text layoutY="14.0" strokeType="OUTSIDE" strokeWidth="0.0" text="Expenses" textAlignment="CENTER"> + <font> + <Font name="Lucida Console" size="14.0" /> + </font> + </Text> </children> </Pane> </children> -- GitLab