Forked from
Surya Bahadur Kathayat / idatt1002
This fork has diverged from the upstream repository.
-
Harry Linrui XU authored
Created and implemented getChosenBudgetCategories method + Disabled/Removed buttons depending on which budget window is shown
Harry Linrui XU authoredCreated and implemented getChosenBudgetCategories method + Disabled/Removed buttons depending on which budget window is shown
BudgetController.java 13.00 KiB
package no.ntnu.idatt1002.demo.controller;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
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.Expense;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory;
import java.io.IOException;
import java.util.Optional;
/**
* 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 deleteBtn;
@FXML
private Button returnBtn;
@FXML
private Button backBtn;
@FXML
private Button continueBtn;
@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 ObservableList<BudgetItem> budgetList;
@FXML
private PieChart budgetPieChart;
/**
* Initializes the budget register, the observable budget list and the tableview, along with the values of the dropbox used for filtering the tableview.
*/
@FXML
public void initialize() {
//TODO specify error messgage for when amount is exceeded / duplicate exists
//todo properly close screen so things are saved
//Initialize table columns
categoryCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, ExpenseCategory>("budgetCategory"));
amountCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, Double>("budgetAmount"));
descriptionCol.setCellValueFactory(new PropertyValueFactory<BudgetItem, String>("budgetDescription"));
try {
general = loadBudgetDataFromFile("Budget");
budgetList = FXCollections.observableArrayList(general.getBudgetItems());
budgetTableView.setItems(budgetList);
if (FileHandlingBudget.isNewBudget("Budget")) {
returnBtn.setOpacity(0);
returnBtn.setDisable(true);
} else {
refreshPieChart();
//addBtn.setDisable(true);
//editBtn.setDisable(true);
//deleteBtn.setDisable(true);
backBtn.setDisable(true);
continueBtn.setDisable(true);
backBtn.setOpacity(0);
continueBtn.setOpacity(0);
}
} catch(IOException ioe) {
showErrorDialogBox("File reading error", "Error in reading file", "Could not"
+ "read from the Budget file");
}
formatDatePicker();
}
private ObservableList<PieChart.Data> createBudgetPieChart() throws IllegalArgumentException { //
ObservableList<PieChart.Data> budgetData = FXCollections.observableArrayList();
List<ExpenseCategory> chosenCategories = general.getChosenBudgetCategories();
//Only adds the budget data for chosen categories to the pie chart
for (ExpenseCategory category : chosenCategories) {
budgetData.add(new Data(category.toString().substring(0, 1).toUpperCase().
concat(category.toString().substring(1)),
general.getBudgetItem(category).getBudgetAmount()));
}
return budgetData;
}
/*private ObservableList<PieChart.Data> createBudgetPieChart() {
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())
);
}*/
private void refreshPieChart() {
this.budgetPieChart.setData(createBudgetPieChart());
}
/**
* 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/AddBudgetNew.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) {
showErrorDialogBox("Loading error", "Error in loading dialog", "An error occurred"
+ "when loading the AddBudget window");
}
//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) {
showErrorDialogBox(e.getMessage(), e.getMessage(), e.getMessage());
}
}
//Updates the tableview using the register
refreshTableView();
refreshPieChart();
}
/**
* 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
String title = "Confirm Delete" ;
String header = "Delete Confirmation";
String content = "Are you sure you would like to delete the selected entry?";
Optional<ButtonType> isConfirmed = showConfirmationDialog(title, header, content);
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
general.deleteItemFromBudget(item.getBudgetCategory());
refreshTableView();
refreshPieChart();
}
}
/**
* 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(String title, String header, String content) {
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.writeGeneralBudgetToFile("Budget", general);
}
/**
* Displays an alert box of type error, informing of a custom error.
*/
private void showErrorDialogBox(String title, String header, String content) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(content);
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 {
//Instantiate new budget
if (FileHandlingBudget.isEmpty(fileName)) {
general = new GeneralBudget(1000);
//throws new IOException("Not valid budget")
} else { //Load previous budget
try {
general = FileHandlingBudget.readGeneralBudgetFromFile(fileName);
} catch (IOException e) {
showErrorDialogBox("File error", "Error in reading from fil", "An error occurred"
+ "when reading GeneralBudget from the file");
}
}
return general;
}
/**
* Switches scene, 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
*/
@FXML
public void switchScene(ActionEvent event) {
FXMLLoader loader = new FXMLLoader();
try {
if (event.getSource() == returnBtn || event.getSource() == continueBtn) {
//Adds unused categories to the table
general.addUnusedCategories();
//Always saving the data when switching scenes
saveDataToFile();
loader.setLocation(getClass().getResource("/view/MainMenuNew.fxml"));
} else if (event.getSource() == backBtn) {
loader.setLocation(getClass().getResource("/view/dualList.fxml"));
}
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(Exception ioe) {
showErrorDialogBox("Loading error", "Error in loading", "Could load"
+ "to FXML file");
}
}
}