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; import javafx.fxml.FXMLLoader; import javafx.geometry.Side; 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.Button; import javafx.scene.control.ButtonType; import javafx.scene.control.ComboBox; import javafx.scene.control.DatePicker; import javafx.scene.control.Label; 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.Stage; 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 no.ntnu.idatt1002.demo.data.Economics.ExpenseRegister; import no.ntnu.idatt1002.demo.data.Economics.FileHandling; import no.ntnu.idatt1002.demo.data.Economics.Income; import no.ntnu.idatt1002.demo.data.Economics.IncomeCategory; import no.ntnu.idatt1002.demo.data.Economics.IncomeRegister; public class IncomeExpenseController implements FinanceController { @FXML private TableColumn<Expense, Double> expAmountCol; @FXML private TableColumn<Expense, ExpenseCategory> expCategoryCol; @FXML private TableColumn<Expense, String> expDateCol; @FXML private TableColumn<Expense, String> expDescriptionCol; @FXML private TableColumn<Expense, Boolean> expRecurringCol; @FXML private TableColumn<Income, Double> inAmountCol; @FXML private TableColumn<Income, IncomeCategory> inCategoryCol; @FXML private TableColumn<Income, String> inDateCol; @FXML private TableColumn<Income, String> inDescriptionCol; @FXML private TableColumn<Income, Boolean> inRecurringCol; @FXML private TableView<Expense> expenseTableView; @FXML private TableView<Income> incomeTableView; @FXML private Text inSum; @FXML private Text expSum; @FXML private Button addBtn; @FXML private Button deleteBtn; @FXML private Button editBtn; @FXML private ProgressBar budgetProgress; @FXML private DatePicker date; @FXML private Label daysLeftLbl; @FXML private ComboBox<?> filter; @FXML private Button returnBtn; @FXML private Label title; private FinanceMode financeMode; private IncomeRegister incomeRegister; private ExpenseRegister expenseRegister; private GeneralBudget generalBudget; private ObservableList<Income> income; private ObservableList<Expense> expenses; @FXML private PieChart expensePieChart; @FXML private PieChart incomePieChart; FileHandling fileHandling; @FXML public void initialize() throws IOException { fileHandling = new FileHandling(); //Initialize columns setColumns(); //Initialize registers and tableview incomeRegister = loadIncomeDataFromFile("Income"); income = FXCollections.observableArrayList(incomeRegister.getItems()); incomeTableView.setItems(income); expenseRegister = loadExpenseDataFromFile("Expense"); expenses = FXCollections.observableArrayList(expenseRegister.getItems()); expenseTableView.setItems(expenses); incomePieChart.getData().addAll(createIncomePyChart()); incomePieChart.setTitle("Income"); incomePieChart.setLegendSide(Side.RIGHT); expensePieChart.setData(createExpensePyChart()); expensePieChart.setTitle("Expenses"); expensePieChart.setLegendSide(Side.RIGHT); expensePieChart.setLabelLineLength(10); //Initialize sum field under the tableview // inSum.setText(String.valueOf(incomeRegister.getTotalSum())); //expSum.setText(String.valueOf(expenseRegister.getTotalSum())); } private void setColumns() { inDateCol.setCellValueFactory(new PropertyValueFactory<Income, String>("date")); inAmountCol.setCellValueFactory(new PropertyValueFactory<Income, Double>("amount")); inCategoryCol.setCellValueFactory(new PropertyValueFactory<Income, IncomeCategory>("category")); inDescriptionCol.setCellValueFactory(new PropertyValueFactory<Income, String>("description")); inRecurringCol.setCellValueFactory(new PropertyValueFactory<Income, Boolean>("recurring")); expDateCol.setCellValueFactory(new PropertyValueFactory<Expense, String>("date")); expAmountCol.setCellValueFactory(new PropertyValueFactory<Expense, Double>("amount")); expCategoryCol.setCellValueFactory(new PropertyValueFactory<Expense, ExpenseCategory>("category")); expDescriptionCol.setCellValueFactory(new PropertyValueFactory<Expense, String>("description")); expRecurringCol.setCellValueFactory(new PropertyValueFactory<Expense, Boolean>("recurring")); } private ObservableList<PieChart.Data> createExpensePyChart() { return FXCollections.observableArrayList( new Data("Food", expenseRegister.getExpenseByCategory(ExpenseCategory.FOOD).getTotalSum()), new Data("Books", expenseRegister.getExpenseByCategory(ExpenseCategory.BOOKS).getTotalSum()), new Data("Clothes", expenseRegister.getExpenseByCategory(ExpenseCategory.CLOTHES).getTotalSum()), new Data("Other", expenseRegister.getExpenseByCategory(ExpenseCategory.OTHER).getTotalSum()) ); } private ObservableList<PieChart.Data> createIncomePyChart() { return FXCollections.observableArrayList( new Data("Food", incomeRegister.getIncomeByCategory(IncomeCategory.STUDENT_LOAN).getTotalSum()), new Data("Books", incomeRegister.getIncomeByCategory(IncomeCategory.SALARY).getTotalSum()) ); } /** * Method for handling the adding of new entries in the tableview. * @param event A button click on the add button. */ @Override public void handleAddBtn(ActionEvent event) { handleEditBtn(event); } /** * Method for handling the editing of a chosen entry in the tableview. * * @param event A button click on the edit button. */ @Override public void handleEditBtn(ActionEvent event) { } /** * 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 */ @Override public void handleDeleteBtn(ActionEvent event) { } /** * 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. */ @Override public void refreshTableView() { this.income.setAll(incomeRegister.getItems()); //this.sum.setText(String.valueOf(incomeRegister.getTotalSum())); this.expenses.setAll(expenseRegister.getItems()); //this.sum.setText(String.valueOf(incomeRegister.getTotalSum())); } /** * 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() { return Optional.empty(); } /** * 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 { fileHandling.writeItemRegisterToFile(incomeRegister, "Income"); fileHandling.writeItemRegisterToFile(expenseRegister, "Expense"); } /** * Method that either reads data from a file with which it fills an income register, if older changes exist, or instantiates an income register if the file is empty. * @param fileName The name of the file that is being read from. * @return An object of type IncomeRegister. * @throws IOException If an error occurs while reading from the file. */ public IncomeRegister loadIncomeDataFromFile(String fileName) throws IOException { //Instantiate new incomeRegister if (fileHandling.isEmpty(fileName)) { incomeRegister = new IncomeRegister(); } else { //Load previous income register try { incomeRegister = fileHandling.readIncomeRegisterFromFile(fileName); } catch (IOException e) { e.printStackTrace(); } } return incomeRegister; } /** * Method that either reads data from a file with which it fills an expense register, if older changes exist, or instantiates an expense register if the file is empty. * @param fileName The name of the file that is being read from. * @return An object of type IncomeRegister. * @throws IOException If an error occurs while reading from the file. */ public ExpenseRegister loadExpenseDataFromFile(String fileName) throws IOException { //ItemRegister<T extends Item> if (fileHandling.isEmpty(fileName)) { expenseRegister = new ExpenseRegister(); } else { try { expenseRegister = fileHandling.readExpenseRegisterFromFile(fileName); } catch (IOException e) { e.printStackTrace(); } } return expenseRegister; } /** * 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)) { generalBudget = new GeneralBudget(31, 1000); } else { //Load previous budget try { generalBudget = fileHandlingBudget.readGeneralBudgetFromFile(fileName); } catch (IOException e) { e.printStackTrace(); } } return generalBudget; } /** * Switches the scene to the Main Menu scene. */ @FXML private void returnToMainMenu(javafx.event.ActionEvent event) throws IOException { 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(); } }