Forked from
Surya Bahadur Kathayat / idatt1002
This fork has diverged from the upstream repository.
-
Harry Linrui XU authoredHarry Linrui XU authored
BudgetController.java 11.00 KiB
package no.ntnu.idatt1002.demo.controller;
import java.time.LocalDate;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;
import javafx.scene.chart.PieChart.Data;
import javafx.scene.control.*;
import javafx.scene.control.Alert.AlertType;
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.BudgetItem;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudget;
import no.ntnu.idatt1002.demo.data.Budget.GeneralBudget;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory;
import java.io.IOException;
import java.util.Optional;
import no.ntnu.idatt1002.demo.data.Economics.IncomeCategory;
/**
* Controller for budget scene in the application. This controller manages all actions that relates to the budget tableview (add, edit and delete), the switching
* of scenes from the budget scene to another scene, and the saving of the table, whenever the user switches to another scene.
*
* @author Anders Emil Bergan
* @since 24.3.2023
*/
public class BudgetController implements FinanceController {
private GeneralBudget general;
@FXML
private Button addBtn;
@FXML
private Button editBtn;
@FXML
private Button returnBtn;
@FXML
private TableColumn<BudgetItem, Double> amountCol;
@FXML
private TableView<BudgetItem> budgetTableView = new TableView<>();
@FXML
private TableColumn<BudgetItem, ExpenseCategory> categoryCol;
@FXML
private TableColumn<BudgetItem, String> descriptionCol;
@FXML
private Text sum;
@FXML
private DatePicker date;
@FXML
private TableColumn<BudgetItem, Double> percentageColumn;
@FXML
private ObservableList<BudgetItem> budgetList;
/**
* Initializes the budget register, the observable budget list and the tableview, along with the values of the dropbox used for filtering the tableview.
* @throws IOException If there occurs any exception when loading the budget register from a file.
*/
@FXML
public void initialize() throws IOException {
//TODO if budget is not empty - disable
//Initialize table columns
categoryCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, ExpenseCategory>("budgetCategory"));
amountCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, Double>("budgetAmount"));
descriptionCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, String>("budgetDescription"));
//Initialize registers and tableview
general = loadBudgetDataFromFile("Budget");
budgetList = FXCollections.observableArrayList(general.getBudgetItems());
budgetTableView.setItems(budgetList);
formatDatePicker();
//createBudgetPieChart();
//Initialize sum field under the tableview
//sum.setText(String.valueOf(general.totalSum()));
}
private ObservableList<PieChart.Data> createBudgetPieChart() { //TODO DOESNT WORK IF BUDGETITEM HAS NO BUDGET
return FXCollections.observableArrayList(
new Data("Food", general.getBudgetItem(ExpenseCategory.FOOD).getBudgetAmount()),
new Data("Books", general.getBudgetItem(ExpenseCategory.BOOKS).getBudgetAmount()),
new Data("Clothes", general.getBudgetItem(ExpenseCategory.CLOTHES).getBudgetAmount()),
new Data("Other", general.getBudgetItem(ExpenseCategory.OTHER).getBudgetAmount())
);
}
/**
* Method for disabling the date picker, yet having its opacity at max.
*/
private void formatDatePicker() {
date.setValue(LocalDate.now());
date.setDisable(true);
date.setStyle("-fx-opacity: 1");
date.getEditor().setStyle("-fx-opacity: 1");
}
@Override
public void handleAddBtn(ActionEvent event) {
handleEditBtn(event);
}
/**
* Adds or edits a budget item, depending on what mode the DialogMode enum is at. The method brings up a dialog box popup in which the user can fill and choose
* values that the budget item will have. Open exiting the popup, the changes the saved to the tableview.
* @param event A button click on either the add or delete button.
*/
@Override
public void handleEditBtn(ActionEvent event) {
BudgetItem item = null;
String dialogTitle = "";
DialogMode dialogMode;
FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/AddBudget.fxml"));
Dialog<BudgetItem> dialog = new Dialog<>();
dialog.initModality(Modality.APPLICATION_MODAL);
//Try to load the FXML file onto another dialogPane
try{
dialog.getDialogPane().setContent(loader.load());
} catch(IOException e) {
e.printStackTrace();
}
//Loads the controller for the dialog box that appears whenever one adds or edits a budget item
AddBudgetController budgetController = loader.getController();
//Sets the title of the dialog box
if(event.getSource().equals(addBtn)){
dialogMode = DialogMode.ADD;
dialogTitle = "New Budget";
}
else if (event.getSource().equals(editBtn) && budgetTableView.getSelectionModel().getSelectedItem() != null) {
dialogMode = DialogMode.EDIT;
dialogTitle = "Edit expense";
//Gets the selected item from the table
item = budgetTableView.getSelectionModel().getSelectedItem();
//Binds the selected item to another item which is defined in the budgetcontroller
budgetController.setBudget(item);
} else {
return;
}
dialog.setTitle(dialogTitle);
// Show the Dialog and wait for the user to close it
dialog.showAndWait();
//Adds the new item to the register
item = budgetController.getNewBudgetItem();
if(item != null && dialogMode == DialogMode.ADD){
try {
general.addToBudgetBudgetItem(item);
} catch(IllegalArgumentException e) {
showIllegalBudgetItemDialog();
}
}
//Updates the tableview using the register
refreshTableView();
}
/**
* Deletes an entry from the tableview, if an entry has been selected. The method brings up a popup window, asking for confirmation for deleting the entry.
* @param event A button click on the delete button
*/
@FXML
public void handleDeleteBtn(ActionEvent event) {
//Gets the selected item from the tableview
BudgetItem item = budgetTableView.getSelectionModel().getSelectedItem();
//Exits the method if nothing is selected
if (item == null) {
return;
}
//Brings up a confirmation popup
Optional<ButtonType> isConfirmed = showConfirmationDialog();
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
general.deleteItemFromBudget(item.getBudgetCategory());
refreshTableView();
}
}
/**
* Method for synching the register with the tableview. The observable list to which the tableview is set, is being refilled with all the entries
* in the register, keeping it updated with new changes.
*/
public void refreshTableView(){
this.budgetList.setAll(general.getBudgetItems());
//Refreshing the sum of the amounts of the budget
//this.sum.setText(String.valueOf(general.totalSum()));
}
/**
* Returns an optional, which is a popup alert box, asking for confirmation for deleting an entry.
* @return An alert box, asking for confirmation for deleting the selected entry of the tableview.
*/
@Override
public Optional<ButtonType> showConfirmationDialog() {
Alert alert = new Alert(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();
}
/**
* Saves the changes made to the tableview by writing the information to a file.
*
* @throws IOException If an error occurs while writing to the file.
*/
@Override
public void saveDataToFile() throws IOException {
FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
fileHandlingBudget.writeGeneralBudgetToFile("Budget", general);
}
/**
* Returns an optional, which is a popup alert box, informing that either the budget amount has
* been exceeded or that the same category has been entered twice in the budget tableview.
*/
private void showIllegalBudgetItemDialog() {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Budget amount exceeded/Category already exists");
alert.setHeaderText("Your budget exceeds the max limit OR a budget item of the same category already exists in the table");
alert.setContentText("The total budget sum must be below " + general.getMaxAmount() + " OR Each category can only have one entry in the budget table");
alert.showAndWait();
}
/**
* Method that either reads data from a file with which it fills a budget register, if this is an old budget, or instantiates a budget register if this is a new budget.
* @param fileName The name of the file that is being read from.
* @return An object of type GeneralBudget.
* @throws IOException If an error occurs while reading from the file.
*/
public GeneralBudget loadBudgetDataFromFile(String fileName) throws IOException {
FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
//Instantiate new budget
if (fileHandlingBudget.isEmpty(fileName)) {
general = new GeneralBudget(31, 1000);
} else { //Load previous budget
try {
general = fileHandlingBudget.readGeneralBudgetFromFile(fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
return general;
}
/**
* Switches scenes back to main menu, by loading a new FXML file and setting the scene to this location.
* @param event A button click on the return to main menu button
* @throws IOException If an error occurs with loading any of the FXML files.
*/
@FXML
public void returnToMainMenu(ActionEvent event) throws IOException {
//Always saving the data when switching scenes
saveDataToFile();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/view/MainMenuNew.fxml"));
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}