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 (401)
Showing
with 1620 additions and 64 deletions
############################## ##############################
## Java ## Java
############################## ##############################
.mtj.tmp/ .mtj.tmp/
*.class *.class
*.jar *.jar
*.war *.war
*.ear *.ear
*.nar *.nar
############################## ##############################
## Maven ## Maven
############################## ##############################
target/ target/
pom.xml.tag pom.xml.tag
pom.xml.releaseBackup pom.xml.releaseBackup
pom.xml.versionsBackup pom.xml.versionsBackup
pom.xml.next pom.xml.next
pom.xml.bak pom.xml.bak
release.properties release.properties
dependency-reduced-pom.xml dependency-reduced-pom.xml
buildNumber.properties buildNumber.properties
.mvn/timing.properties .mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar .mvn/wrapper/maven-wrapper.jar
############################## ##############################
## IntelliJ ## IntelliJ
############################## ##############################
out/ out/
.idea/* .idea/*
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
############################## ##############################
## Database ## Database
############################## ##############################
*.db *.db
*.DS_Store *.DS_Store
...@@ -88,7 +88,7 @@ loadScripts(document, 'script');</script> ...@@ -88,7 +88,7 @@ loadScripts(document, 'script');</script>
<h1 title="Class MyApp" class="title">Class MyApp</h1> <h1 title="Class MyApp" class="title">Class MyApp</h1>
</div> </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" 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> </div>
<section class="class-description" id="class-description"> <section class="class-description" id="class-description">
<hr> <hr>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<!-- Generated by javadoc (19) on Thu Feb 02 10:19:17 CET 2023 --> <!-- 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 name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="dc.created" content="2023-02-02"> <meta name="dc.created" content="2023-02-02">
...@@ -50,9 +50,9 @@ loadScripts(document, 'script');</script> ...@@ -50,9 +50,9 @@ loadScripts(document, 'script');</script>
<div class="flex-content"> <div class="flex-content">
<main role="main"> <main role="main">
<div class="header"> <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> </div>
No usage of no.ntnu.idatt1002.demo.MyApp</main> No usage of no.ntnu.idatt1002.demo.view.MyApp</main>
<footer role="contentinfo"> <footer role="contentinfo">
<hr> <hr>
<p class="legal-copy"><small>Copyright &#169; 2023. All rights reserved.</small></p> <p class="legal-copy"><small>Copyright &#169; 2023. All rights reserved.</small></p>
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.8.1</junit.version> <junit.version>5.8.1</junit.version>
<javafx.version>17.0.1</javafx.version> <javafx.version>19.0.2.1</javafx.version>
</properties> </properties>
<repositories> <repositories>
...@@ -152,7 +152,7 @@ ...@@ -152,7 +152,7 @@
<archive> <archive>
<manifest> <manifest>
<mainClass> <mainClass>
no.ntnu.idatt1002.demo.MyApp no.ntnu.idatt1002.demo.view.MyApp
</mainClass> </mainClass>
</manifest> </manifest>
</archive> </archive>
...@@ -172,7 +172,7 @@ ...@@ -172,7 +172,7 @@
<!-- Default configuration for running with: mvn clean javafx:run --> <!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id> <id>default-cli</id>
<configuration> <configuration>
<mainClass>no.ntnu.idatt1002.demo/no.ntnu.idatt1002.demo.MyApp</mainClass> <mainClass>no.ntnu.idatt1002.demo.view.MyApp</mainClass>
<launcher>app</launcher> <launcher>app</launcher>
<jlinkZipName>app</jlinkZipName> <jlinkZipName>app</jlinkZipName>
<jlinkImageName>app</jlinkImageName> <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 javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import no.ntnu.idatt1002.demo.data.recipes.FileHandler;
import no.ntnu.idatt1002.demo.data.recipes.FoodItem;
import no.ntnu.idatt1002.demo.data.recipes.IngredientsAtHand;
/**
* The AddIngredientController manages a dialog pane used to display a search-field along with a list of all the
* possible food types in the application according to the FoodItem enum class. The food types in the list may be
* selected and added to an up-to-date IngredientsAtHand object that is then written to file. The user may add
* several food types before pressing 'close' and exit the dialog. The food types that are not already contained
* in the IngredientsAtHand are listed underneath the list so that the user can keep track of the newly added
* food types. Upon opening the dialog, the search field is already selected and the user can start typing a search.
* When pressing 'Enter' on the keyboard, the search is performed and matches are displayed in the list. If the search
* field is left blank upon search, all food types are listed again.
*/
public class AddIngredientController implements Initializable {
private ObservableList<String> ingredients;
private String[] ingredientsList;
@FXML
private Button addBtn;
@FXML
private ListView<String> listView;
@FXML
private TextField searchBar;
@FXML
private Button searchBtn;
@FXML
private Label status;
private String statusText = "Added: ";
/**
* The initialize method of the controller takes in a URL (location) and ResourceBundle(resources) to
* initialize the controller once its root element has been processed.
* The method then sets the list items of the list, sets the focus on the search-field and makes sure that the
* label underneath the list that states the added food types to the user can wrap if it fills the full width
* of the window.
* @param url The location to resolve the relative paths to the root object.
* @param resourceBundle Resources used to localize the root object.
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
listView.setItems(FXCollections.observableArrayList(Arrays.stream(FoodItem.values()).map(value -> value.label).toList()));
Platform.runLater(() -> searchBar.requestFocus());
status.setWrapText(true);
}
/**
* The addToFridge method reads an up-to-date instance of the IngredientsAtHand object from file and
* gets hold of the FoodItem constant that is currently selected in the list. If the selected FoodItem is not
* already at hand, it is added and the IngredientAtHand object is written to file. The label beneath the
* list is also updated with the name of the food type to keep track of what has been added. If the
* selected food type was already at hand, it is not added again and the label is not updated.
*
* @throws IOException If the method fails to write or read the Ingredients at hand object to/from file.
*/
@FXML
void addToFridge() throws IOException {
IngredientsAtHand ingredientsAtHand = FileHandler.readIngredientsAtHand("Fridge");
FoodItem item = FoodItem.valueOf(listView.getSelectionModel().getSelectedItem().replace(" ", "_").toUpperCase());
if(item != null && ingredientsAtHand!= null ) {
if(!ingredientsAtHand.atHand(item)) {
ingredientsAtHand.addIngredient(item);
FileHandler.writeIngredientsAtHand(ingredientsAtHand, "Fridge");
if(status.isVisible() && status.getText().isBlank()) {
statusText += String.format("%s", item.label);
} else if (status.isVisible()){
statusText += String.format(", %s", item.label);
}
status.setText(statusText);
}
}
}
/**
* The search method is fired whenever the 'Search' button is pressed by the user. It clears the list and then
* refills it by adding all the resulting values from the call to the method 'searchList'.
*/
@FXML
void search() {
listView.getItems().clear();
listView.getItems().addAll(searchList(searchBar.getText(),
Arrays.stream(FoodItem.values()).toList().stream().map(value -> value.label).toArray(String[]::new)));
}
/**
* The searchList method takes in a string of what the user enetered in the search field and an array of
* Strings that represents every label of the FoodItem enum class. The search word from the user is
* trimmed and split by space and matched against all the constants of the FoodItem enums. Any matches are then
* to a List of strings and returned.
* @param searchWords A String of what the user wrote in the search field.
* @param listOfStrings A list of strings, in this case, each representing a constant of the FoodItem enum class.
* @return A list of strings food types of FoodItem that match the se search word(s).
*/
private List<String> searchList(String searchWords, String[] listOfStrings) {
String[] searchWordsArray = searchWords.trim().split(" ");
return Arrays.stream(listOfStrings).filter((in) -> {
return Arrays.stream(searchWordsArray).allMatch((word) ->
in.toLowerCase().contains(word.toLowerCase()));
}).collect(Collectors.toList());
}
}
package no.ntnu.idatt1002.demo.controller;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.recipes.*;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
/**
* The AllRecipesController manages the view named AllRecipes.fxml that displays a scrollable list of all the
* recipes that are stored in the recipe register at 'src/main/resources/recipes/Recipes.register'. The controller
* holds an instance of the IngredientsAtHand class and the RecipeRegister class and combines the two to
* fill the list with recipes sorted by the number of ingredients that are not currently in the 'fridge' of the
* user. Each recipe is also lister with a percentage value that shows how many percent of the recipe's
* ingredients are actually in the fridge. This information is included so that recipes with a lower number of
* ingredients are not given an unfair advantage over others where the user may have a significant number of
* the ingredients available. Each listed recipe may be clicked on by the user to open it in a new view in full
* detail.
*
* @author hannesofie
*/
public class AllRecipesController implements Initializable {
IngredientsAtHand ingredientsAtHand;
RecipeRegister recipeRegister;
@FXML
private ListView<String> allList;
private String selectedRecipeName;
/**
* The initialize method of the controller takes in a URL (location) and ResourceBundle(resources) to
* initialize the controller once its root element has been processed. The method then reads and creates
* an object of the IngredientsAtHand class and one of the RecipesRegister class.
* If the recipe register exists, the list is filled with Strings for each recipe at the format:
* <Recipe name> - X missing ingredients (XX%)
* Finally, a MouseClick event and handler is attached to the list that gets the recipe name of the clicked
* list item and runs the method showRecipe() with that name as input to show the recipe in detail in the
* view Recipe.fxml.
*
* @param url The location to resolve the relative paths to the root object.
* @param resourceBundle Resources used to localize the root object.
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
ingredientsAtHand = FileHandler.readIngredientsAtHand("Fridge");
recipeRegister = FileHandler.readRecipeRegister("Recipes");
ObservableList<String> recipes;
if(recipeRegister == null) {
recipes = FXCollections.observableArrayList(new ArrayList<>());
} else {
int numberOfRecipes = recipeRegister.getRecipes().size();
ArrayList<Recipe> sortedRecipes = recipeRegister.pickBestFits(numberOfRecipes, ingredientsAtHand);
recipes = FXCollections.observableArrayList(sortedRecipes.stream().map(recipe -> {
return String.format("# %s - %d missing ingredients (%2.0f %%)", recipe.getName(), recipe.getMissingIngredients(), percent(recipe.getIngredientList().size() - recipe.getMissingIngredients(), recipe.getIngredientList().size()));
}).toList());
}
allList.setItems(recipes);
allList.setOnMouseClicked(new EventHandler<MouseEvent>() {
/**
* The handler method takes a MouseEvent(Mouse Click) and uses the list item that was subjected to the
* mouse click and extracts the recipe name. That name as a String is then passed to the method
* 'showRecipe' that loads the view Recipe.fxml to display this particular recipe in full detail.
* @param mouseEvent A mouse event, in this case a MouseClicked event.
*/
@Override
public void handle(MouseEvent mouseEvent) {
selectedRecipeName = allList.getSelectionModel()
.getSelectedItem().split("-|#")[1].strip();
try {
showRecipe(selectedRecipeName);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
/**
* The goBack method is fired whenever the user presses the button 'Back To Suggestions'. It loads the location
* of the SuggestRecipes.fxml view and sets the new stage.
* @param event Action event that triggers this method, in this case a button click.
* @throws IOException If the method fails to load the location at the given file path.
*/
@FXML
private void goBack(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/view/SuggestRecipes.fxml"));
Parent root = loader.load();
Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* The showRecipe method takes in a recipe name as a String and navigates to the view Recipe.fxml after having
* the RecipeController set the data of the view according to this particular recipe.
* @param recipeName A case-sensitive string representation of the recipe to open in detail.
* @throws IOException If the method fails to load the location of the Recipe.fxml view.
*/
private void showRecipe(String recipeName) throws IOException {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/view/Recipe.fxml"));
Recipe recipeOfInterest = recipeRegister.getRecipe(recipeName);
Parent root = loader.load();
RecipeController recipeController = loader.getController();
if(recipeOfInterest != null) {
recipeController.setData(recipeOfInterest);
Stage stage = (Stage)allList.getParent().getScene().getWindow();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} else {
System.out.println("The selected recipe is null.");
}
}
/**
* The percent method takes in two integers(a, b) and performs float-division(a/b) on then and multiplies the
* answer by 100 to get the percentage 'a' makes of the total 'b'. If either 'a' or 'b' is zero, zero is returned.
* In the current context; 'a' is an int representing a number of ingredients at hand and part of a recipe and 'b'
* is an int representing the total number of ingredients in the same recipe.
* @param a An int to divide by b and multiply by 100.
* @param b An int by which to divide 'a'.
* @return A float value presenting the percentage value of 'a' out of 'b'.
*/
private float percent(int a, int b) {
if (b != 0 && a != 0) {
return (a * 100f / b);
} else {
return 0;
}
}
}
package no.ntnu.idatt1002.demo.controller;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import no.ntnu.idatt1002.demo.data.Budget.BudgetItem;
import java.net.URL;
import java.util.ResourceBundle;
/**
* The BudgetBarController manages the component view BudgetBar.fxml that may be dynamically loaded to other views.
* The view consists of a HBox containing three elements; a label stating the name of the budget post (BudgetItem class),
* a progress bar showing how much money is left at this post according to the budget and the user's recorded expenses
* and a label stating how much money are left on the particular budget.
*
* @author hannesofie
*/
public class BudgetBarController {
@FXML
private Label nameTag;
@FXML
private Label leftoverTag;
@FXML
private ProgressBar miniBar;
/**
* The setData method is called to fill the BudgetBar instance with information of a particular Budget
* post (BudgetItem), that is the name of the budget, it's progress bar and money left. The information needed
* for this are taken in as two parameters; the BudgetItem object to represent and a double value representing
* the money left of this budget.
*
* @param budgetItem A BudgetItem object to represent in the BudgetBar instance.
* @param leftovers A double value representing the money the user has left on this particular BudgetItem.
*/
public void setData(BudgetItem budgetItem, double leftovers) {
nameTag.setText(budgetItem.getBudgetCategory().label.substring(0,1).toUpperCase()
+ budgetItem.getBudgetCategory().label.substring(1));
leftoverTag.setText(String.format("Left: %.0f", leftovers));
double progress = 1+(leftovers-budgetItem.getBudgetAmount())/ budgetItem.getBudgetAmount();
if(progress < 0.25) {
miniBar.setStyle("-fx-accent: #ffb000;");
if(progress < -0.00) {
miniBar.setProgress(1.0);
miniBar.setStyle("-fx-accent: #fa5959;");
} else {
miniBar.setProgress(progress);
}
} else {
miniBar.setStyle("-fx-accent: rgba(48,222,109,0.8);");
miniBar.setProgress(progress);
}
}
}
package no.ntnu.idatt1002.demo.controller;
import java.time.LocalDate;
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.geometry.Rectangle2D;
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.cell.PropertyValueFactory;
import javafx.scene.text.Text;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.Budget.BudgetItem;
import no.ntnu.idatt1002.demo.data.Budget.BudgetRegister;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudget;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudgetArchive;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingSelectedBudget;
import no.ntnu.idatt1002.demo.data.Budget.GeneralBudget;
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 extends FinanceController {
private GeneralBudget general;
@FXML
private Button addBtn;
@FXML
private Button editBtn;
@FXML
private Button deleteBtn;
@FXML
private Button returnToMainMenuBtn;
@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;
@FXML
private Label daysLeftLbl;
BudgetRegister budgetRegister = new BudgetRegister();
/**
* 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 {
System.out.println("Just in budget try");
general = loadBudgetDataFromFile(
"budgets/" + FileHandlingSelectedBudget.readSelectedBudget() + "/Budget");
budgetList = FXCollections.observableArrayList(general.getBudgetItems());
budgetTableView.setItems(budgetList);
System.out.println("After loading general");
if (FileHandlingBudgetArchive.isBudgetRegisterEmpty()) {
budgetRegister = new BudgetRegister();
} else {
budgetRegister = FileHandlingBudgetArchive.readBudgetArchive("");
}
if (FileHandlingBudget.isNewBudget(
"budgets/" + FileHandlingSelectedBudget.readSelectedBudget() + "/Budget")) {
returnToMainMenuBtn.setOpacity(0);
returnToMainMenuBtn.setDisable(true);
daysLeftLbl.setOpacity(0);
} 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) {
ioe.printStackTrace();
showErrorDialogBox(ioe.getMessage(), ioe.getMessage(), ioe.getMessage());
}
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(
"budgets/" + FileHandlingSelectedBudget.readSelectedBudget() + "/Budget", general);
}
public void updateBudgetRegister(String budgetFolderName) {
try {
budgetRegister.addBudgetName(budgetFolderName);
FileHandlingBudgetArchive.writeBudgetRegisterToArchive(budgetRegister);
} catch(IOException ioe) {
showErrorDialogBox(ioe.getMessage(), ioe.getMessage(), ioe.getMessage());
}
}
/**
* 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() == returnToMainMenuBtn) {
//Adds unused categories to the table
general.addUnusedCategories();
loader.setLocation(getClass().getResource("/view/MainMenuNew.fxml"));
//Always saving the data when switching scenes
saveDataToFile();
} else if (event.getSource() == continueBtn) {
general.addUnusedCategories();
updateBudgetRegister(FileHandlingSelectedBudget.readSelectedBudget());
loader.setLocation(getClass().getResource("/view/MainMenuNew.fxml"));
//Always saving the data when switching scenes
saveDataToFile();
} 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);
//Centralize the new screen
Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds();
stage.setX((primScreenBounds.getWidth() - stage.getWidth()) / 2);
stage.setY((primScreenBounds.getHeight() - stage.getHeight()) / 2);
stage.show();
} catch(Exception ioe) {
ioe.printStackTrace();
showErrorDialogBox("Loading error", "Error in loading", "Could not load"
+ " FXML file in: " + loader.getLocation());
}
}
}
package no.ntnu.idatt1002.demo.controller;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Optional;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
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.Label;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingBudget;
import no.ntnu.idatt1002.demo.data.Budget.FileHandlingSelectedBudget;
import no.ntnu.idatt1002.demo.data.Economics.Expense;
public class CreateBudgetController {
public Button okBtn;
public Button cancelBtn;
private String currentMonth;
private Expense expense;
private String budgetName;
@FXML
private TextField nameField;
@FXML
private Label errorMsg;
@FXML
public void initialize() {
currentMonth = String.valueOf(LocalDate.now().getMonth());
okBtn.addEventFilter(
ActionEvent.ACTION, event -> {
if(nameField.getText().equals("")) {
errorMsg.setOpacity(1);
event.consume();
}
});
okBtn.addEventFilter(
ActionEvent.ACTION, event -> {
//if(hasDuplicate() { //TODO MAYBE THIS IN THE START BUDGET FILE
//errorMsg.setText("Budget for this month already exist")
}
);
}
@FXML
public void pressOkBtn(ActionEvent event) {
String title = "Confirm name";
String header = "Are you sure you to use this name?";
String content = "The name cannot be changed later";
budgetName = nameField.getText();
System.out.println(budgetName);
if(!createNewFiles(budgetName)) {
updateCurrentFile("", "");
errorMsg.setText("A budget of the same name already exists");
errorMsg.setOpacity(1);
return;
}
Optional<ButtonType> isConfirmed = showConfirmationDialog(title, header, content);
if (isConfirmed.isPresent() && isConfirmed.get() == ButtonType.OK) {
updateCurrentFile(currentMonth, budgetName);
} else {
updateCurrentFile("", "");
}
final Node source = (Node) event.getSource();
((Stage) source.getScene().getWindow()).close();
}
@FXML
public void pressCancelBtn(ActionEvent event) {
updateCurrentFile("", "");
final Node source = (Node) event.getSource();
((Stage) source.getScene().getWindow()).close();
}
/**
* 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.
*/
@FXML
private 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();
}
private void showErrorMsgBox(String title, String header, String content) {
Alert alert = new Alert(AlertType.ERROR);
alert.setTitle(title);
alert.setHeaderText(header);
alert.setContentText(content);
alert.showAndWait();
}
public boolean createNewFiles(String budgetName) {
boolean empty;
try {
empty = FileHandlingSelectedBudget.createBudgetDirectory(currentMonth + budgetName);
FileHandlingSelectedBudget.createNewIncomeFile(currentMonth + budgetName, "Income");
FileHandlingSelectedBudget.createNewExpenseFile(currentMonth + budgetName, "Expense");
FileHandlingSelectedBudget.createNewBudgetFile(currentMonth + budgetName, "Budget");
} catch (IOException ioe) {
empty = false;
System.out.println(ioe.getMessage());
ioe.printStackTrace();
showErrorMsgBox(ioe.getMessage(), ioe.getMessage(), ioe.getMessage());
}
return empty;
}
public void updateCurrentFile(String currentMonth, String budgetName) {
try {
FileHandlingSelectedBudget.updateSelectedBudget(currentMonth + budgetName);
} catch (IOException ioe) {
showErrorMsgBox(ioe.getMessage(), ioe.getMessage(), ioe.getMessage());
}
}
}
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.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)) {
System.out.println("Creating new income register");
incomeRegister = new IncomeRegister();
} else { //Load previous income register
System.out.println("Loading old income register");
incomeRegister = FileHandling.readIncomeRegisterFromFile(fileName);
}
} catch (IOException ioe) {
ioe.printStackTrace();
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();
System.out.println("Creaging new expense register");
} else { //Load previous income register
expenseRegister = FileHandling.readExpenseRegisterFromFile(fileName);
System.out.println("Loading saved expense register");
}
} 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);
}