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 (303)
Showing
with 2491 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;
/**
* 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"));
/*FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
try {
if (fileHandlingBudget.isEmpty("Budget")) {
returnBtn.setOpacity(0);
} else {
addBtn.setDisable(true);
editBtn.setDisable(true);
deleteBtn.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");
}*/
try { //Initialize registers, tableview and pie charts
//if (FileHandlingBudget.hasBudgetSet - from line 4/5, so after the general amount and such) {
//add, edit and delete buttons are removed.
//hvis linje fire er tom, instansier et nytt register, hvis ikke, last ned fra fil
general = loadBudgetDataFromFile("Budget");
budgetList = FXCollections.observableArrayList(general.getBudgetItems());
budgetTableView.setItems(budgetList);
refreshPieChart();
} catch(IOException ioe) {
showErrorDialogBox("File reading error", "Error in reading from file", "Could not read"
+ " registers from file");
}
setButtons();
formatDatePicker();
//Initialize sum field under the tableview
//sum.setText(String.valueOf(general.totalSum()));
}
/**
* Method that disables or removes button, based on where the budget window
* is being used.
*/
private void setButtons() {
FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
try {
if (fileHandlingBudget.isEmpty("Budget")) {
returnBtn.setOpacity(0);
} else {
addBtn.setDisable(true);
editBtn.setDisable(true);
deleteBtn.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");
}
}
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) {
String title = "Budget amount exceeded/Category already exists";
String header = "Your budget exceeds the max limit OR a budget item of the same category already exists in the table";
String content = "The total budget sum must be below " + general.getMaxAmount() + " OR Each category can only have one entry in the budget table";
showErrorDialogBox(title, header, content);
}
}
//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 fileHandlingBudget = new FileHandlingBudget();
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 {
FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
//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");
}
}
}
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.util.Optional;
import javafx.scene.control.ButtonType;
/**
* Interface for controllers for scenes with finance tableviews.
*
* @author Harry Linrui Xu
* @since 29.3.2023
*/
public interface FinanceController {
/**
* Method for handling the adding of new entries in the tableview.
* @param event A button click on the add button.
*/
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.
*/
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
*/
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.
*/
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.
*/
Optional<ButtonType> showConfirmationDialog(String title, String header, String content);
/**
* 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.
*/
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
*/
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.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;
FileHandling fileHandling;
Overview overview;
@FXML
public void initialize() {
fileHandling = new FileHandling();
//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 {
FileHandlingBudget fileHandlingBudget = new FileHandlingBudget();
//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();
}
}