Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • team13/tdat1006
  • eivindrt/tdat1006
  • alexholt/idatt1002
  • elinang/idatt1002
  • surya/idatt1002
  • kjellit/idata-1002-demo-project
  • eskillr/idatt1002
  • G1-06/idatt-1002-2022-1-06
  • emillaa/idatt1002
  • andreksv/idatt-1002-2023-9
  • melane/idatt-1002-2023-5
  • ramtinfs/idatt1002
  • surya/idatx1005
  • itatt1005_2024_group15/purchase-planner
  • systemutvikling-gruppe-19/idatt-1005-2024-group-19
15 results
Show changes
Commits on Source (311)
Showing
with 2419 additions and 64 deletions
##############################
## Java
##############################
.mtj.tmp/
*.class
*.jar
*.war
*.ear
*.nar
##############################
## Maven
##############################
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
pom.xml.bak
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
##############################
## IntelliJ
##############################
out/
.idea/*
*.iml
*.ipr
*.iws
##############################
## Database
##############################
*.db
*.DS_Store
##############################
## Java
##############################
.mtj.tmp/
*.class
*.jar
*.war
*.ear
*.nar
##############################
## Maven
##############################
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
pom.xml.bak
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
##############################
## IntelliJ
##############################
out/
.idea/*
*.iml
*.ipr
*.iws
##############################
## Database
##############################
*.db
*.DS_Store
......@@ -88,7 +88,7 @@ loadScripts(document, 'script');</script>
<h1 title="Class MyApp" class="title">Class MyApp</h1>
</div>
<div class="inheritance" title="Inheritance Tree"><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html" title="class or interface in java.lang" class="external-link">java.lang.Object</a>
<div class="inheritance">no.ntnu.idatt1002.demo.MyApp</div>
<div class="inheritance">no.ntnu.idatt1002.demo.view.MyApp</div>
</div>
<section class="class-description" id="class-description">
<hr>
......
......@@ -2,7 +2,7 @@
<html lang="en">
<head>
<!-- Generated by javadoc (19) on Thu Feb 02 10:19:17 CET 2023 -->
<title>Uses of Class no.ntnu.idatt1002.demo.MyApp (demo 1.0-SNAPSHOT API)</title>
<title>Uses of Class no.ntnu.idatt1002.demo.view.MyApp (demo 1.0-SNAPSHOT API)</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="dc.created" content="2023-02-02">
......@@ -50,9 +50,9 @@ loadScripts(document, 'script');</script>
<div class="flex-content">
<main role="main">
<div class="header">
<h1 title="Uses of Class no.ntnu.idatt1002.demo.MyApp" class="title">Uses of Class<br>no.ntnu.idatt1002.demo.MyApp</h1>
<h1 title="Uses of Class no.ntnu.idatt1002.demo.view.MyApp" class="title">Uses of Class<br>no.ntnu.idatt1002.demo.view.MyApp</h1>
</div>
No usage of no.ntnu.idatt1002.demo.MyApp</main>
No usage of no.ntnu.idatt1002.demo.view.MyApp</main>
<footer role="contentinfo">
<hr>
<p class="legal-copy"><small>Copyright &#169; 2023. All rights reserved.</small></p>
......
......@@ -15,7 +15,7 @@
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.8.1</junit.version>
<javafx.version>17.0.1</javafx.version>
<javafx.version>19.0.2.1</javafx.version>
</properties>
<repositories>
......@@ -152,7 +152,7 @@
<archive>
<manifest>
<mainClass>
no.ntnu.idatt1002.demo.MyApp
no.ntnu.idatt1002.demo.view.MyApp
</mainClass>
</manifest>
</archive>
......@@ -172,7 +172,7 @@
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>no.ntnu.idatt1002.demo/no.ntnu.idatt1002.demo.MyApp</mainClass>
<mainClass>no.ntnu.idatt1002.demo.view.MyApp</mainClass>
<launcher>app</launcher>
<jlinkZipName>app</jlinkZipName>
<jlinkImageName>app</jlinkImageName>
......
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CheckStyle-IDEA" serialisationVersion="2">
<checkstyleVersion>10.6.0</checkstyleVersion>
<scanScope>JavaOnly</scanScope>
<option name="thirdPartyClasspath" />
<option name="activeLocationIds" />
<option name="locations">
<list>
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
</list>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/main/main.iml" filepath="$PROJECT_DIR$/main/main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/src.iml" filepath="$PROJECT_DIR$/.idea/src.iml" />
<module fileurl="file://$PROJECT_DIR$/test/test.iml" filepath="$PROJECT_DIR$/test/test.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
\ No newline at end of file
package no.ntnu.idatt1002.demo;
import no.ntnu.idatt1002.demo.view.MyWindow;
/**
* Use this class to start the application
* @author nilstes
*/
public class MyApp {
/**
* Main method for my application
*/
public static void main(String[] args) throws Exception {
MyWindow window = new MyWindow("The Window");
window.setVisible(true);
}
}
package no.ntnu.idatt1002.demo.controller;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.Budget.BudgetItem;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory;
/**
* Class that represents the popup dialog box that appears whenever a budget item is to be added or edited.
* The dialog contains various fields that are used to create a new item or edit an existing item.
* @author Anders Emil Bergan
* @since 24.3.2023
*
*/
public class AddBudgetController {
BudgetItem newBudgetItem = null;
BudgetItem chosenBudgetItem = null;
@FXML
private ComboBox<ExpenseCategory> categoryVariable;
@FXML
private TextField amountVariable;
@FXML
private TextField descriptionVariable;
@FXML
private Button okBtn;
@FXML
private Button cancelBtn;
/**
* Initializes the category drop box by filling it with all the values from the ExpenseCategory enum.
* It then sets a prompt text on the box.
*/
@FXML
private Text errorMsg;
/**
* Initializes the category drop box by filling it with all the values from the ExpenseCategory enum.
* It then sets a prompt text on the box.
*/
@FXML
public void initialize(){
//Set the possible values in a list.
ObservableList<ExpenseCategory> expenseCategories = FXCollections.observableArrayList(
ExpenseCategory.values());
//Set the values inside the dropbox
categoryVariable.setItems(expenseCategories);
//Set default value
categoryVariable.setValue(ExpenseCategory.FOOD);
addEventFilters();
}
public ExpenseCategory getCategory(){
return categoryVariable.getValue();
}
public BudgetItem getNewBudgetItem(){
return this.newBudgetItem;
}
/**
* Binds the item that is taken in as the argument with a budget item declared in this class. The item of this class is instantiated
* as a deep copy of the argument. Each attribute of their attributes are then bounded. The text fields and category boxes
* in the dialog window are then set to the values of the chosen item, as to not display empty values.
* @param item The item that is chosen to be edited.
*/
@FXML
public void setBudget(BudgetItem item){
//Deep copying item and then binding the two items
chosenBudgetItem = new BudgetItem(item.getBudgetAmount(), item.getBudgetDescription(), item.getBudgetCategory());
chosenBudgetItem.getAmountProperty().bindBidirectional(item.getAmountProperty());
chosenBudgetItem.getDescriptionProperty().bindBidirectional(item.getDescriptionProperty());
chosenBudgetItem.getCategoryProperty().bindBidirectional(item.getCategoryProperty());
//Set the values of the input fields of the dialog box
amountVariable.textProperty().set(String.valueOf(item.getBudgetAmount()));
descriptionVariable.textProperty().set(item.getBudgetDescription());
categoryVariable.setValue(item.getBudgetCategory());
}
/**
* Adds a new to the budget tableview or edits an existing entry in table if the OK button is pressed.
* An entry is edited as the selected entry of the table is bounded to another budget item in this class. If this budget item
* is altered, the budget item in the tableview will automatically respond with the same changes.
* @param event If the OK button is pressed.
*/
@FXML
private void pressOkBtn(ActionEvent event) {
//Instantiates a new budget item
if(newBudgetItem == null){
ExpenseCategory category = getCategory();
double amount = Double.parseDouble(amountVariable.getText());
String description = descriptionVariable.getText();
newBudgetItem = new BudgetItem(amount, description, category);
}
//Sets the value of the budget(chosenBudgetItem) that is bounded to the chosen budget item (not chosenBudgetItem) in the tableview
if(chosenBudgetItem != null){
chosenBudgetItem.setBudgetAmount(Double.parseDouble(amountVariable.getText()));
chosenBudgetItem.setBudgetDescription(descriptionVariable.getText());
chosenBudgetItem.setBudgetCategory(categoryVariable.getValue());
}
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
private void addEventFilters() {
okBtn.addEventFilter(
ActionEvent.ACTION, event -> {
try {
validateInputs();
} catch(IllegalArgumentException e) {
event.consume();
errorMsg.setOpacity(1);
}
}
);
}
private boolean validateInputs() {
try {
BudgetItem item = new BudgetItem(
Double.parseDouble(amountVariable.getText()),
descriptionVariable.getText(),
categoryVariable.getValue());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid inputs. Cannot instantiate item", e);
}
return true;
}
/**
* Closes the dialog box.
* @param actionEvent A button click on the close button.
*/
@FXML
private void pressCancelBtn(ActionEvent actionEvent) {
final Node source = (Node) actionEvent.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
package no.ntnu.idatt1002.demo.controller;
import java.text.NumberFormat;
import java.time.LocalDate;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.Budget.BudgetItem;
import no.ntnu.idatt1002.demo.data.Economics.Expense;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory;
import no.ntnu.idatt1002.demo.data.Economics.Expense;
/**
* Class that represents the popup dialog box that appears whenever an expense is to be added or edited.
* The dialog contains various fields that are used to create a new expense or edit an existing expense.
* @author Harry Linrui Xu
* @since 13.3.2023
*/
public class AddExpenseController {
Expense newExpense = null; //the expense that is chosen when editing or the expense that is created when adding
Expense chosenExpense = null; //an expense that is meant to track the old state of an expense before editing, in case cancel bugtton is clicked
@FXML
private Button cancelBtn;
@FXML
private Button okBtn;
@FXML
private TextField dateField;
@FXML
private Text errorMsg;
@FXML
private DatePicker datePicker;
@FXML
private TextField descriptionField;
@FXML
private TextField amountField;
@FXML
private ComboBox<ExpenseCategory> categoryBox;
@FXML
private ComboBox<Boolean> recurringBox;
/**
* Initializes the category and recurring drop boxes by filling them with all the values from the ExpenseCategory enum,
* and the boolean values respectively, and the datepicker calendar.
* It then sets them to the default values of GIFT, false and today respectively.
*/
@FXML
public void initialize() {
//Set the possible values in a list.
ObservableList<ExpenseCategory> expenseCategories = FXCollections.observableArrayList(
ExpenseCategory.values());
//Set the values inside the dropbox
categoryBox.setItems(expenseCategories);
//Set default value
categoryBox.setValue(ExpenseCategory.FOOD);
ObservableList<Boolean> recurring = FXCollections.observableArrayList(true, false);
recurringBox.setItems(recurring);
recurringBox.setValue(false);
//Set date to today
datePicker.setValue(LocalDate.now());
//Adding event filter to okBtn
addEventFilters();
}
public ExpenseCategory getCategory() {
return categoryBox.getValue();
}
public boolean isRecurring() {
return recurringBox.getValue();//.equals("Yes");
}
public Expense getNewExpense() {
return this.newExpense;
}
/**
* Binds the expense that is taken in as the argument with an expense declared in this class. The expense of this class is instantiated
* as a deep copy of the argument. Each attribute of their attributes are then bounded. The text fields and category boxes
* in the dialog window are then set to the values of the chosen expense, as to not display empty values.
* @param expense The expense that is chosen to be edited.
*/
public void setExpense(Expense expense) {
//Deep copying expense and then binding the two expenses
chosenExpense = new Expense(expense.getDescription(), expense.getAmount(), expense.isRecurring(), expense.getCategory(), expense.getDate());
chosenExpense.descriptionProperty().bindBidirectional(expense.descriptionProperty());
chosenExpense.amountProperty().bindBidirectional(expense.amountProperty());
chosenExpense.recurringProperty().bindBidirectional(expense.recurringProperty());
chosenExpense.expenseCategoryObjectProperty().bindBidirectional(expense.expenseCategoryObjectProperty());
chosenExpense.dateProperty().bindBidirectional(expense.dateProperty());
//Set the values of the input fields of the dialog box
descriptionField.textProperty().set(expense.getDescription());
amountField.textProperty().setValue(String.valueOf(expense.getAmount()));
recurringBox.setValue(expense.isRecurring());
datePicker.setValue(expense.getDate());
categoryBox.setValue(expense.getCategory());
}
/**
* Adds a new to the tableview or edits an existing entry in table if the OK button is pressed.
* An entry is edited as the selected entry of the table is bounded to another expense in this class. If this expense
* is altered, the expense in the tableview will automatically respond with the same changes.
* @param event If the OK button is pressed.
*/
@FXML
public void pressOkBtn(ActionEvent event) {
//Instantiates a new expense
if (newExpense == null) {
LocalDate date = datePicker.getValue();
double amount = Double.parseDouble(amountField.getText());
String description = descriptionField.getText();
ExpenseCategory category = getCategory();
boolean recurring = isRecurring();
newExpense = new Expense(description, amount, recurring, category, date);
}
//Sets the value of the expense(chosen) that is bounded to the chosen expense (not chosenExpense) in the tableview
if (chosenExpense != null) {
chosenExpense.setDescription((descriptionField.getText()));
chosenExpense.setAmount(Double.parseDouble(amountField.getText()));
chosenExpense.setRecurring(recurringBox.getValue());
chosenExpense.setCategory(categoryBox.getValue());
chosenExpense.setDate(datePicker.getValue());
}
errorMsg.setOpacity(0);
final Node source = (Node) event.getSource();
((Stage) source.getScene().getWindow()).close();
}
/**
* Closes the dialog box and cancels any pending changes.
* @param event A button click on the cancel button.
*/
@FXML
public void pressCancelBtn(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
private void addEventFilters() {
okBtn.addEventFilter(
ActionEvent.ACTION, event -> {
try {
validateInputs();
} catch(IllegalArgumentException e) {
event.consume();
errorMsg.setOpacity(1);
}
});
}
private boolean validateInputs() {
try {
Expense expense = new Expense(
Double.parseDouble(amountField.getText()), recurringBox.getValue(),
categoryBox.getValue(), datePicker.getValue());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid input. Cannot instantiate expense", e);
}
return true;
}
}
\ No newline at end of file
package no.ntnu.idatt1002.demo.controller;
import java.text.NumberFormat;
import java.time.LocalDate;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.Economics.Expense;
import no.ntnu.idatt1002.demo.data.Economics.Income;
import no.ntnu.idatt1002.demo.data.Economics.IncomeCategory;
/**
* Class that represents the popup dialog box that appears whenever an income is to be added or edited.
* The dialog contains various fields that are used to create a new income or edit an existing income.
* @author Harry Linrui Xu
* @since 24.3.2023
*/
public class AddIncomeController {
Income newIncome = null;
Income chosenIncome = null;
@FXML
private Button cancelBtn;
@FXML
private Button okBtn;
@FXML
private Text errorMsg;
@FXML
private DatePicker datePicker;
@FXML
private TextField descriptionField;
@FXML
private TextField amountField;
@FXML
private ComboBox<IncomeCategory> categoryBox;
@FXML
private ComboBox<Boolean> recurringBox;
/**
* Initializes the category and recurring drop boxes by filling them with all the values from the IncomeCategory enum,
* and the boolean values respectively, and the datepicker calendar.
* It then sets them to the default values of GIFT, false and today respectively.
*/
@FXML
public void initialize() {
//Set the possible values in a list.
ObservableList<IncomeCategory> incomeCategories = FXCollections.observableArrayList(
IncomeCategory.values());
//Set the values inside the dropbox
categoryBox.setItems(incomeCategories);
//Set default value
categoryBox.setValue(IncomeCategory.GIFT);
ObservableList<Boolean> recurring = FXCollections.observableArrayList(true, false);
recurringBox.setItems(recurring);
recurringBox.setValue(false);
//Set date to today
datePicker.setValue(LocalDate.now());
addEventFilters();
}
public IncomeCategory getCategory() {
return categoryBox.getValue();
}
public boolean isRecurring() {
return recurringBox.getValue();//.equals("Yes");
}
public Income getNewIncome() {
return this.newIncome;
}
/**
* Binds the income that is taken in as the argument with an income declared in this class. The income of this class is instantiated
* as a deep copy of the argument. Each attribute of their attributes are then bounded. The text fields and category boxes
* in the dialog window are then set to the values of the chosen income, as to not display empty values.
* @param income The income that is chosen to be edited.
*/
public void setIncome(Income income) {
//Deep copying income and then binding the two incomes
chosenIncome = new Income(income.getDescription(), income.getAmount(), income.isRecurring(), income.getCategory(), income.getDate());
chosenIncome.descriptionProperty().bindBidirectional(income.descriptionProperty());
chosenIncome.amountProperty().bindBidirectional(income.amountProperty());
chosenIncome.recurringProperty().bindBidirectional(income.recurringProperty());
chosenIncome.incomeCategoryObjectProperty().bindBidirectional(income.incomeCategoryObjectProperty());
chosenIncome.dateProperty().bindBidirectional(income.dateProperty());
//Set the values of the input fields of the dialog box
descriptionField.textProperty().set(income.getDescription());
amountField.textProperty().setValue(String.valueOf(income.getAmount()));
recurringBox.setValue(income.isRecurring());
datePicker.setValue(income.getDate());
categoryBox.setValue(income.getCategory());
}
/**
* Adds a new to the tableview or edits an existing entry in table if the OK button is pressed.
* An entry is edited as the selected entry of the table is bounded to another income in this class. If this income
* is altered, the income in the tableview will automatically respond with the same changes.
* @param event If the OK button is pressed.
*/
@FXML
public void pressOkBtn(ActionEvent event) {
//Instantiates a new income
if (newIncome == null) {
LocalDate date = datePicker.getValue();
double amount = Double.parseDouble(amountField.getText());
String description = descriptionField.getText();
IncomeCategory category = getCategory();
boolean recurring = isRecurring();
newIncome = new Income(description, amount, recurring, category, date);
}
//Sets the value of the income(chosenIncome) that is bounded to the chosen income (not chosenIncome) in the tableview
if (chosenIncome != null) {
chosenIncome.setDescription((descriptionField.getText()));
chosenIncome.setAmount(Double.parseDouble(amountField.getText()));
chosenIncome.setRecurring(recurringBox.getValue());
chosenIncome.setCategory(categoryBox.getValue());
chosenIncome.setDate(datePicker.getValue());
}
final Node source = (Node) event.getSource();
((Stage) source.getScene().getWindow()).close();
}
private void addEventFilters() {
okBtn.addEventFilter(
ActionEvent.ACTION, event -> {
try {
validateInputs();
} catch(IllegalArgumentException e) {
event.consume();
errorMsg.setOpacity(1);
}
});
}
private boolean validateInputs() {
try {
Income income = new Income(
Double.parseDouble(amountField.getText()), recurringBox.getValue(),
categoryBox.getValue(), datePicker.getValue());
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Invalid inputs. Cannot instantiate income", e);
}
return true;
}
/**
* Closes the dialog box and cancels any pending changes.
* @param event A button click on the cancel button.
*/
@FXML
public void pressCancelBtn(ActionEvent event) {
final Node source = (Node) event.getSource();
final Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
\ No newline at end of file
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;
import org.apache.commons.compress.compressors.zstandard.ZstdUtils;
/**
* 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 extends 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();
}
public ObservableList<PieChart.Data> createPieChart() 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())
);
}*/
@Override
public void refreshPieChart() {
this.budgetPieChart.setData(createPieChart());
}
/**
* Method for disabling the date picker, yet having its opacity at max.
*/
@Override
public 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.
*/
@Override
public void refreshTableView(){
this.budgetList.setAll(general.getBudgetItems());
//Refreshing the sum of the amounts of the budget
//this.sum.setText(String.valueOf(general.totalSum()));
}
/**
* 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);
}
/**
* 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
*/
@Override
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
loader.setLocation(getClass().getResource("/view/MainMenuNew.fxml"));
} else if (event.getSource() == backBtn) {
loader.setLocation(getClass().getResource("/view/dualList.fxml"));
}
saveDataToFile();
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");
}
}
}
package no.ntnu.idatt1002.demo.controller;
/**
* Enum for distinguishing between adding or editing an item in a tableview
*
* @author Harry Linrui Xu
* @since 11.3.2023
*/
enum DialogMode {
ADD, EDIT
}
package no.ntnu.idatt1002.demo.controller;
import java.io.IOException;
import java.util.Optional;
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.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.Dialog;
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.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.IncomeRegister;
import no.ntnu.idatt1002.demo.data.Economics.Item;
import no.ntnu.idatt1002.demo.data.Economics.ItemRegister;
/**
* Controller for expense scene in the application. This controller manages all actions that relates to the expense tableview (add, edit and delete), the switching
* of scenes from the expense scene to another scene, and the saving of the table, whenever the user switches to another scene.
*
* @author Harry Linrui Xu
* @since 13.3.2023
*/
public class ExpensesController {
@FXML
private Button addBtn;
@FXML
private Button editBtn;
@FXML
private Button deleteBtn;
@FXML
private ComboBox<String> show;
@FXML
private Button incomeBtn;
@FXML
private Text sum;
@FXML
private Button budgetBtn;
@FXML
private Button returnBtn;
@FXML
private TableColumn<Expense, Double> amountColumn;
@FXML
private TableColumn<Expense, ExpenseCategory> categoryColumn;
@FXML
private TableColumn<Expense, String> dateColumn;
@FXML
private TableColumn<Expense, String> descriptionColumn;
@FXML
private TableColumn<Expense, Boolean> recurringColumn;
@FXML
private TableView<Expense> expenseTableView;
@FXML
ExpenseRegister expenseRegister;
ObservableList<Expense> expenses;
ObservableList<String> filter;
/**
* Initializes the expense register, the observable expense list and the tableview, along values of the dropbox used for filtering the tableview.
* The method is called each time the FXML of this scene is loaded.
* @throws IOException If there occurs any exception when loading the budget register from a file.
*/
@FXML
public void initialize() throws IOException {
//Initialize table columns
dateColumn.setCellValueFactory(new PropertyValueFactory<Expense, String>("date"));
amountColumn.setCellValueFactory(new PropertyValueFactory<Expense, Double>("amount"));
categoryColumn.setCellValueFactory(new PropertyValueFactory<Expense, ExpenseCategory>("category"));
descriptionColumn.setCellValueFactory(new PropertyValueFactory<Expense, String>("description"));
recurringColumn.setCellValueFactory(new PropertyValueFactory<Expense, Boolean>("recurring"));
//Initialize the filter box
filter = FXCollections.observableArrayList("All", "Food", "Clothes", "Books", "Other",
"Fixed expense");
show.setItems(filter);
show.setValue("All");
//Initialize registers and tableview
expenseRegister = loadExpenseDataFromFile("Expense");
expenses = FXCollections.observableArrayList(expenseRegister.getItems());
expenseTableView.setItems(expenses);
//Initialize sum field under the tableview
sum.setText(String.valueOf(expenseRegister.getTotalSum()));
}
/**
* Method for handling the adding of new entries in the tableview.
* @param event A button click on the add button.
*/
@FXML
protected void handleAddButton(ActionEvent event) {
handleEditButton(event);
}
/**
* Method for handling the editing of a chosen entry in the tableview.
* @param event A button click on the edit button.
*/
@FXML
protected void handleEditButton(ActionEvent event) {
//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 = "";
// 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();
/**
* The mode of the dialog. NEW if new contact, EDIT if edit existing contact.
*/
DialogMode dialogMode;
//Sets the title of the dialog box
if (event.getSource().equals(addBtn)) {
dialogMode = DialogMode.ADD;
dialogTitle = "Add expense";
} else if (event.getSource().equals(editBtn)
&& expenseTableView.getSelectionModel().getSelectedItem() != null) {
dialogMode = DialogMode.EDIT;
dialogTitle = "Edit expense";
//Gets the selected item from the table
newExpense = expenseTableView.getSelectionModel().getSelectedItem();
//Binds the selected item to another item which is defined in the ItemController
dialogController.setExpense(newExpense);
} else {
return;
}
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 && dialogMode == DialogMode.ADD) {
expenseRegister.addItem(newExpense);
}
//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) {
Expense chosenExpense = expenseTableView.getSelectionModel().getSelectedItem();
if (chosenExpense == null) {
return;
}
Optional<ButtonType> isConfirmed = showConfirmationDialog();
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
expenseRegister.removeItem(chosenExpense);
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.
*/
protected void refreshTableView() {
this.expenses.setAll(expenseRegister.getItems());
this.sum.setText(String.valueOf(expenseRegister.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.
*/
private Optional<ButtonType> showConfirmationDialog() {
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();
}
/**
* 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>
FileHandling fileHandling = new FileHandling();
if (fileHandling.isEmpty(fileName)) {
expenseRegister = new ExpenseRegister();
} else {
try {
expenseRegister = fileHandling.readExpenseRegisterFromFile(fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
return expenseRegister;
}
/**
* Saves the changes made to the expense tableview by writing the information to a file.
* @param fileName The name of the file that is written to.
* @throws IOException If an error occurs while writing to the file.
*/
public void saveDataToFile(String fileName) throws IOException {
FileHandling fileHandling = new FileHandling();
fileHandling.writeItemRegisterToFile(expenseRegister, fileName);
}
/**
* Switches scenes from the expense scene to another, by loading a new FXML file and setting the scene to this location.
* The destination depends entirely on which button is pressed.
* @param event A button click on the buttons on the buttonbar or the next button
* @throws IOException If an error occurs with loading any of the FXML files.
*/
@FXML
public void switchScene(ActionEvent event) throws IOException {
saveDataToFile("Expense");
FXMLLoader loader = new FXMLLoader();
if (event.getSource() == incomeBtn) {
loader.setLocation(SceneController.class.getResource("/view/Income.fxml"));
} else if (event.getSource() == returnBtn) {
loader.setLocation(SceneController.class.getResource("/view/FirstMenu.fxml"));
} else if (event.getSource() == budgetBtn) {
loader.setLocation(SceneController.class.getResource("/view/BudgetNew.fxml"));
}
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
package no.ntnu.idatt1002.demo.controller;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Optional;
import javafx.collections.ObservableList;
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.ButtonType;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudget;
import no.ntnu.idatt1002.demo.data.Budget.GeneralBudget;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseRegister;
import no.ntnu.idatt1002.demo.data.Economics.FileHandling;
import no.ntnu.idatt1002.demo.data.Economics.IncomeRegister;
/**
* Interface for controllers for scenes with finance tableviews.
*
* @author Harry Linrui Xu
* @since 29.3.2023
*/
public abstract class FinanceController {
private ExpenseRegister expenseRegister;
private IncomeRegister incomeRegister;
private GeneralBudget general;
/**
* Method for handling the adding of new entries in the tableview.
* @param event A button click on the add button.
*/
abstract void handleAddBtn(javafx.event.ActionEvent event);
/**
* Method for handling the editing of a chosen entry in the tableview.
* @param event A button click on the edit button.
*/
abstract void handleEditBtn(javafx.event.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
*/
abstract void handleDeleteBtn(javafx.event.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.
*/
abstract void refreshTableView();
/**
* 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.
*/
public Optional<ButtonType> showConfirmationDialog(String title, String header, String content) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(content);
return alert.showAndWait();
}
abstract void refreshPieChart();
/**
* Method for disabling the date picker, yet having its opacity at max.
*/
abstract void formatDatePicker();
/**
* Displays an alert box of type error, informing of a custom error.
*/
public 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;
}
/**
* 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.
*/
public IncomeRegister loadIncomeDataFromFile(String fileName) {
//Instantiate new incomeRegister
try {
if (FileHandling.isEmpty(fileName)) {
incomeRegister = new IncomeRegister();
} else { //Load previous income register
incomeRegister = FileHandling.readIncomeRegisterFromFile(fileName);
}
} catch (IOException ioe) {
showErrorDialogBox("File reading error", "Error in reading from file", "Could not"
+ "read the IncomeRegister from file");
}
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.
*/
public ExpenseRegister loadExpenseDataFromFile(String fileName) {
//Instantiate expense register
try {
if (FileHandling.isEmpty(fileName)) {
expenseRegister = new ExpenseRegister();
} else { //Load previous income register
expenseRegister = FileHandling.readExpenseRegisterFromFile(fileName);
}
} catch (IOException ioe) {
showErrorDialogBox("File reading error", "Error in reading from file", "Could not"
+ "read the ExpenseRegister from file");
}
return expenseRegister;
}
/**
* 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.
*/
abstract void saveDataToFile() throws IOException;
/**
* Switches scenes, 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
*/
abstract void switchScene(javafx.event.ActionEvent event);
}
package no.ntnu.idatt1002.demo.controller;
import java.io.IOException;
import java.util.Optional;
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.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.Dialog;
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.Economics.Income;
import no.ntnu.idatt1002.demo.data.Economics.IncomeCategory;
import no.ntnu.idatt1002.demo.data.Economics.IncomeRegister;
import no.ntnu.idatt1002.demo.data.Economics.FileHandling;
/**
* Controller for income scene in the application. This controller manages all actions that relates to the income tableview (add, edit and delete), the switching
* of scenes from the income scene to another scene, and the saving of the table, whenever the user switches to another scene.
*
* @author Harry Linrui Xu
* @since 24.3.2023
*/
public class IncomeController {
@FXML
private Button addBtn;
@FXML
private Button editBtn;
@FXML
private Button deleteBtn;
@FXML
private ComboBox<String> show;
@FXML
private Button expenseBtn;
@FXML
private Button overviewBtn;
@FXML
private Button budgetBtn;
@FXML
private Button returnBtn;
@FXML
private Text sum;
@FXML
private TableColumn<Income, Double> amountColumn;
@FXML
private TableColumn<Income, IncomeCategory> categoryColumn;
@FXML
private TableColumn<Income, String> dateColumn;
@FXML
private TableColumn<Income, String> descriptionColumn;
@FXML
private TableColumn<Income, Boolean> recurringColumn;
@FXML
private TableView<Income> incomeTableView;
IncomeRegister incomeRegister;
ObservableList<Income> income;
ObservableList<String> filter;
/**
* Initializes the income register, the observable income list and the tableview, along values of the dropbox used for filtering the tableview.
* The method is called each time the FXML of this scene is loaded.
* @throws IOException If there occurs any exception when loading the budget register from a file.
*/
@FXML
public void initialize() throws IOException {
//Initialize table columns
dateColumn.setCellValueFactory(new PropertyValueFactory<Income, String>("date"));
amountColumn.setCellValueFactory(new PropertyValueFactory<Income, Double>("amount"));
categoryColumn.setCellValueFactory(new PropertyValueFactory<Income, IncomeCategory>("category"));
descriptionColumn.setCellValueFactory(new PropertyValueFactory<Income, String>("description"));
recurringColumn.setCellValueFactory(new PropertyValueFactory<Income, Boolean>("recurring"));
//Initialize the filter box
filter = FXCollections.observableArrayList("All", "Gift", "Salary", "Student loan", "Fixed income");
show.setItems(filter);
show.setValue("All");
//Initialize registers and tableview
incomeRegister = loadIncomeDataFromFile("Income");
income = FXCollections.observableArrayList(incomeRegister.getItems());
incomeTableView.setItems(income);
//Initialize sum field under the tableview
sum.setText(String.valueOf(incomeRegister.getTotalSum()));
//if budget.register isEmpty -> disable expense
}
/**
* Method for handling the adding of new entries in the tableview.
* @param event A button click on the add button.
*/
@FXML
protected void handleAddButton(ActionEvent event) {
handleEditButton(event);
}
/**
* Method for handling the editing of a chosen entry in the tableview.
* @param event A button click on the edit button.
*/
@FXML
protected void handleEditButton(ActionEvent event) {
//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 = "";
// 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();
/**
* The mode of the dialog. NEW if new contact, EDIT if edit existing contact.
*/
DialogMode dialogMode;
//Sets the title of the dialog box
if (event.getSource().equals(addBtn)) {
dialogMode = DialogMode.ADD;
dialogTitle = "Add income";
}
else if (event.getSource().equals(editBtn) && incomeTableView.getSelectionModel().getSelectedItem() != null) {
dialogMode = DialogMode.EDIT;
dialogTitle = "Edit income";
//Gets the selected item from the table
newIncome = incomeTableView.getSelectionModel().getSelectedItem();
//Binds the selected item to another item which is defined in the ItemController
dialogController.setIncome(newIncome);
}
else {
return;
}
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 && dialogMode == DialogMode.ADD) {
incomeRegister.addItem(newIncome);
}
//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
Income chosenIncome = incomeTableView.getSelectionModel().getSelectedItem();
//Exits the method if nothing is selected
if (chosenIncome == null) {
return;
}
//Brings up a confirmation popup
Optional<ButtonType> isConfirmed = showConfirmationDialog();
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
incomeRegister.removeItem(chosenIncome);
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.
*/
protected void refreshTableView() {
this.income.setAll(incomeRegister.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.
*/
private Optional<ButtonType> showConfirmationDialog() {
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();
}
/**
* 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 {
FileHandling fileHandling = new FileHandling();
//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;
}
/**
* Saves the changes made to the income tableview by writing the information to a file.
* @param fileName The name of the file that is written to.
* @throws IOException If an error occurs while writing to the file.
*/
public void saveDataToFile(String fileName) throws IOException {
FileHandling fileHandling = new FileHandling();
fileHandling.writeItemRegisterToFile(incomeRegister, fileName);
}
/**
* Switches scenes from the income scene to another, by loading a new FXML file and setting the scene to this location.
* The destination depends entirely on which button is pressed.
* @param event A button click on the buttons on the buttonbar or the next button
* @throws IOException If an error occurs with loading any of the FXML files.
*/
@FXML
public void switchScene(ActionEvent event) throws IOException {
//Always saving the data when switching scenes
saveDataToFile("Income");
FXMLLoader loader = new FXMLLoader();
if (event.getSource() == overviewBtn) {
loader.setLocation(SceneController.class.getResource("/view/Overview.fxml"));
} else if (event.getSource() == returnBtn) {
loader.setLocation(SceneController.class.getResource("/view/FirstMenu.fxml"));
} else if (event.getSource() == budgetBtn) {
loader.setLocation(SceneController.class.getResource("/view/BudgetNewest.fxml"));
}
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
package no.ntnu.idatt1002.demo.controller;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Optional;
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.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.stage.Modality;
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;
/**
* Class for representing an overview of the income and expenses of the users budget.
* Displays information in tables and pie charts. It is possible to add, edit and delete
* income and expenses. The difference of the expense and income sum contribute to
* the monthly budget progress.
* @author Harry Linrui Xu
* @since 30.03.2023
*/
public class IncomeExpenseController extends FinanceController {
private final static String sumText = "Sum: ";
@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 Label inSum;
@FXML
private Label expSum;
@FXML
private MenuItem addExpense;
@FXML
private MenuItem addIncome;
@FXML
private DatePicker date;
@FXML
private Label daysLeftLbl;
@FXML
private ComboBox<?> filter;
@FXML
private Button returnBtn;
@FXML
private Button continueBtn;
@FXML
private Label title;
@FXML
private Label errorMsg;
@FXML
private MenuItem editIncomeMenu;
@FXML
private MenuItem deleteIncomeMenu;
@FXML
private MenuItem editExpenseMenu;
@FXML
private MenuItem deleteExpenseMenu;
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;
@FXML
public void initialize() {
//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);
//Setting pie chart values to correspond with the registers
incomePieChart.setLegendSide(Side.RIGHT);
incomePieChart.setLabelLineLength(10);
expensePieChart.setLegendSide(Side.RIGHT);
expensePieChart.setLabelLineLength(10);
refreshPieChart();
formatDatePicker();
//Initialize sum field under the tableview
inSum.setText(sumText + String.valueOf(incomeRegister.getTotalSum()));
expSum.setText(sumText + String.valueOf(expenseRegister.getTotalSum()));
}
private void setColumns() {
inDateCol.setCellValueFactory(new PropertyValueFactory<>("date"));
inAmountCol.setCellValueFactory(new PropertyValueFactory<>("amount"));
inCategoryCol.setCellValueFactory(new PropertyValueFactory<>("category"));
inDescriptionCol.setCellValueFactory(new PropertyValueFactory<>("description"));
inRecurringCol.setCellValueFactory(new PropertyValueFactory<>("recurring"));
expDateCol.setCellValueFactory(new PropertyValueFactory<>("date"));
expAmountCol.setCellValueFactory(new PropertyValueFactory<>("amount"));
expCategoryCol.setCellValueFactory(new PropertyValueFactory<>("category"));
expDescriptionCol.setCellValueFactory(new PropertyValueFactory<>("description"));
expRecurringCol.setCellValueFactory(new PropertyValueFactory<>("recurring"));
}
public ObservableList<PieChart.Data> createExpensePieChart() {
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> createIncomePieChart() {
return FXCollections.observableArrayList(
new Data("Gift", incomeRegister.getIncomeByCategory(IncomeCategory.GIFT).getTotalSum()),
new Data("Salary", incomeRegister.getIncomeByCategory(IncomeCategory.SALARY).getTotalSum()),
new Data("Loans", incomeRegister.getIncomeByCategory(IncomeCategory.STUDENT_LOAN).getTotalSum())
);
}
/**
* Method for disabling the date picker, yet having its opacity at max.
*/
@Override
public void formatDatePicker() {
date.setValue(LocalDate.now());
date.setDisable(true);
date.setStyle("-fx-opacity: 1");
date.getEditor().setStyle("-fx-opacity: 1");
}
/**
* Method for handling the adding of new entries in the tableview.
* @param event A button click on the add button.
*/
@Override
public void handleAddBtn(javafx.event.ActionEvent event) {
int sizeBf = (expenseRegister.getItems().size() + incomeRegister.getItems().size());
if (event.getSource() == addIncome) {
handleAddIncome();
} else if (event.getSource() == addExpense){
handleAddExpense();
}
int sizeAf = (expenseRegister.getItems().size() + incomeRegister.getItems().size());
if (sizeAf != sizeBf) {
refreshTableView();
}
}
/**
* 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(javafx.event.ActionEvent event) {
System.out.println(event.getSource());
Income chosenIncome = incomeTableView.getSelectionModel().getSelectedItem();
Expense chosenExpense = expenseTableView.getSelectionModel().getSelectedItem();
boolean isEditIncome = event.getSource() == editIncomeMenu;
boolean isDeleteIncome = event.getSource() == deleteIncomeMenu;
boolean isEditExpense = event.getSource() == editExpenseMenu;
boolean isDeleteExpense = event.getSource() == deleteExpenseMenu;
if (isEditIncome) {
handleEditIncome(chosenIncome);
} else if (isDeleteIncome) {
handleDeleteIncome(chosenIncome);
} else if (isEditExpense) {
handleEditExpense(chosenExpense);
} else if (isDeleteExpense) {
handleDeleteExpense(chosenExpense);
} else return;
//Updates the tableview and pie chart 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
*/
@Override
public void handleDeleteBtn(javafx.event.ActionEvent event) {
handleEditBtn(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.inSum.setText("Sum: " + String.valueOf(incomeRegister.getTotalSum()));
this.expenses.setAll(expenseRegister.getItems());
this.expSum.setText("Sum: " + String.valueOf(expenseRegister.getTotalSum()));
}
@Override
public void refreshPieChart() {
this.incomePieChart.setData(createIncomePieChart());
this.expensePieChart.setData(createExpensePieChart());
}
@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;
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) {
showErrorDialogBox("Loading", "Error in loading dialog box", "Could not load"
+ "the AddIncome window");
}
// 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);
incomePieChart.setData(createIncomePieChart());
}
}
@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;
String dialogTitle = "Add expense";
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) {
showErrorDialogBox("Loading", "Error in loading dialog box", "Could not load"
+ "the AddExpense window");
}
// 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);
expensePieChart.setData(createExpensePieChart());
}
}
@FXML
private void handleEditIncome(Income chosenIncome) {
//Create copy of chosenIncome before changes
//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) {
showErrorDialogBox("Loading", "Error in loading dialog box", "Could not load"
+ "the EditIncome window");
}
// 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();
incomePieChart.setData(createIncomePieChart());
}
@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) {
showErrorDialogBox("Loading", "Error in loading dialog box", "Could not"
+ "load the EditExpense window");
}
// 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();
this.expensePieChart.setData(createExpensePieChart());
}
@FXML
private void handleDeleteIncome(Income chosenIncome) {
String title = "Confirm Delete" ;
String header = "Delete Confirmation";
String content = "Are you sure you would like to delete the selected income?";
Optional<ButtonType> isConfirmed = showConfirmationDialog(title, header, content);
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
incomeRegister.removeItem(chosenIncome);
}
this.incomePieChart.setData(createIncomePieChart());
}
@FXML
private void handleDeleteExpense(Expense chosenExpense) {
String title = "Confirm Delete" ;
String header = "Delete Confirmation";
String content = "Are you sure you would like to delete the selected expense?";
Optional<ButtonType> isConfirmed = showConfirmationDialog(title, header, content);
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
expenseRegister.removeItem(chosenExpense);
}
this.expensePieChart.setData(createExpensePieChart());
}
/**
* 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");
}
/**
* 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
*/
@FXML
public void switchScene(javafx.event.ActionEvent event) {
try {
saveDataToFile();
FXMLLoader loader = new FXMLLoader();
if (event.getSource() == returnBtn) {
loader.setLocation(getClass().getResource("/view/FirstMenu.fxml"));
} else if (event.getSource() == continueBtn) {
loader.setLocation(getClass().getResource("/view/newBudgetBudgert.fxml"));
} else if (event.getSource() == returnBtn) {
//wipe the whole direcotyr with in the currentFile.txt
}
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(IOException ioe) {
showErrorDialogBox("Loading error", "Error in loading", "Could not save"
+ "to file");
}
}
}
package no.ntnu.idatt1002.demo.controller;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
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.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
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.ExpenseCategory;
import no.ntnu.idatt1002.demo.data.Economics.ExpenseRegister;
import no.ntnu.idatt1002.demo.data.Economics.FileHandling;
import no.ntnu.idatt1002.demo.data.Economics.IncomeRegister;
import no.ntnu.idatt1002.demo.data.Economics.Overview;
public class MainMenu {
@FXML
private Label balanceLbl;
@FXML
private ProgressBar bookBar;
@FXML
private Label bookLbl;
@FXML
private Button budgetBtn;
@FXML
private ProgressBar clothesBar;
@FXML
private Label clothesLbl;
@FXML
private DatePicker date;
@FXML
private Button expenseBtn;
@FXML
private ProgressBar foodBar;
@FXML
private Button foodBtn;
@FXML
private Label foodLbl;
@FXML
private Button incomeBtn;
@FXML
private ProgressBar mainBar;
@FXML
private ProgressBar otherBar;
@FXML
private Label otherLbl;
@FXML
private Button returnBtn;
@FXML
private Label title;
@FXML
private Label usageLbl;
@FXML
private AnchorPane root;
@FXML
private Label daysLeftLbl;
GeneralBudget generalBudget;
ExpenseRegister expenseRegister;
IncomeRegister incomeRegister;
Overview overview;
@FXML
public void initialize() {
//Initialize all registers + overview
try {
incomeRegister = loadIncomeDataFromFile("Income");
expenseRegister = loadExpenseDataFromFile("Expense");
generalBudget = loadBudgetDataFromFile("Budget");
} catch (IOException ioe) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle("Could not load register data");
alert.setHeaderText("Could not load register data");
alert.setContentText("There was an error loading in the registers");
alert.showAndWait();
}
overview = new Overview(incomeRegister, expenseRegister, generalBudget);
mainBar.setStyle("-fx-accent: green;");
refreshProgressBars();
refreshLabels();
//Set progress when opening scene
double maxAmount = generalBudget.getMaxAmount();
double expenseSum = expenseRegister.getTotalSum();
//Displaying month
title.setText("BUDGET " + (LocalDate.now().getMonth()));
double balance = maxAmount - expenseSum;
//Set balance
balanceLbl.setText("Balance: " + (balance));
//Displaying how much of the monthly budget has been spent.
usageLbl.setText("Used " + expenseSum + " out of " + generalBudget.getMaxAmount());
if (balance < 0) {
balanceLbl.setTextFill(Color.RED);
}
//Make calendar uneditable
formatDatePicker();
daysLeftLbl.setText("Days left: 31");
//date.restrict
}
private void refreshLabels() {
}
/**
* Sets the progress of the progress bars to their most updated data.
*/
private void refreshProgressBars() {
mainBar.setProgress(expenseRegister.getTotalSum()/generalBudget.getMaxAmount());
foodBar.setProgress((generalBudget.getBudgetItem(ExpenseCategory.FOOD).getBudgetAmount() - overview.getBudgetItemMinusExpense(ExpenseCategory.FOOD))/generalBudget.getBudgetItem(ExpenseCategory.FOOD).getBudgetAmount());
clothesBar.setProgress((generalBudget.getBudgetItem(ExpenseCategory.CLOTHES).getBudgetAmount() - overview.getBudgetItemMinusExpense(ExpenseCategory.CLOTHES))/generalBudget.getBudgetItem(ExpenseCategory.CLOTHES).getBudgetAmount());
bookBar.setProgress((generalBudget.getBudgetItem(ExpenseCategory.BOOKS).getBudgetAmount() - overview.getBudgetItemMinusExpense(ExpenseCategory.BOOKS))/generalBudget.getBudgetItem(ExpenseCategory.BOOKS).getBudgetAmount());
otherBar.setProgress((generalBudget.getBudgetItem(ExpenseCategory.OTHER).getBudgetAmount() - overview.getBudgetItemMinusExpense(ExpenseCategory.OTHER))/generalBudget.getBudgetItem(ExpenseCategory.OTHER).getBudgetAmount());
}
/**
* 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 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 {
//Instantiate expense register
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 {
//Instantiate new budget
if (FileHandlingBudget.isEmpty(fileName)) {
generalBudget = new GeneralBudget(1000);
} else { //Load previous budget
try {
generalBudget = FileHandlingBudget.readGeneralBudgetFromFile(fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
return generalBudget;
}
/**
* 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");
}
@FXML
private void switchScene(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
if (event.getSource() == foodBtn) {
System.out.println("Food button pressed");
} else if (event.getSource() == expenseBtn) {
loader.setLocation(getClass().getResource("/view/IncomeAndExpenses.fxml"));
} else if (event.getSource() == incomeBtn) {
loader.setLocation(getClass().getResource("/view/IncomeAndExpenses.fxml"));
} else if (event.getSource() == budgetBtn) {
loader.setLocation(getClass().getResource("/view/BudgetNewest.fxml"));
} else if (event.getSource() == returnBtn) {
loader.setLocation(getClass().getResource("/view/FirstMenu.fxml"));
}
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setResizable(false);
stage.show();
}
}