diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1a41058717dcc468df58f61939aa040efb18396c..0000000000000000000000000000000000000000 --- a/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -############################## -## 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 diff --git a/src/.idea/.gitignore b/src/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4 --- /dev/null +++ b/src/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/src/.idea/checkstyle-idea.xml b/src/.idea/checkstyle-idea.xml new file mode 100644 index 0000000000000000000000000000000000000000..d943f1e37d5235c2df7fcbd989aee7431ce859b8 --- /dev/null +++ b/src/.idea/checkstyle-idea.xml @@ -0,0 +1,15 @@ +<?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 diff --git a/src/.idea/misc.xml b/src/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..639900d13c6182e452e33a3bd638e70a0146c785 --- /dev/null +++ b/src/.idea/misc.xml @@ -0,0 +1,6 @@ +<?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 diff --git a/src/.idea/modules.xml b/src/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..31eaf94db822d9dffbe5b05956af61106a7a1790 --- /dev/null +++ b/src/.idea/modules.xml @@ -0,0 +1,10 @@ +<?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 diff --git a/src/.idea/vcs.xml b/src/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..6c0b8635858dc7ad44b93df54b762707ce49eefc --- /dev/null +++ b/src/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?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 diff --git a/src/main/java/no/ntnu/idatt1002/demo/controller/AddBudgetController.java b/src/main/java/no/ntnu/idatt1002/demo/controller/AddBudgetController.java new file mode 100644 index 0000000000000000000000000000000000000000..600d4a370a321d8d144c7d9edb121b5fb81a75d3 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/controller/AddBudgetController.java @@ -0,0 +1,85 @@ +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.TextField; + +import javafx.stage.Stage; +import no.ntnu.idatt1002.demo.data.Budget.BudgetItem; +import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory; + +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 addButton; + + @FXML + private Button cancelButton; + + @FXML + public void initialize(){ + ObservableList<ExpenseCategory> expenseCategories = FXCollections.observableArrayList( + ExpenseCategory.values()); + categoryVariable.setItems(expenseCategories); + categoryVariable.setPromptText("Category"); + } + + public ExpenseCategory getCategory(){ + return categoryVariable.getValue(); + } + + public BudgetItem getNewBudgetItem(){ + return this.newBudgetItem; + } + + @FXML + public void addBudget(ActionEvent event) { + if(newBudgetItem == null){ + ExpenseCategory category = getCategory(); + double amount = Double.parseDouble(amountVariable.getText()); + String description = descriptionVariable.getText(); + newBudgetItem = new BudgetItem(amount, description, category); + } + 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(); + } + + @FXML + public void setBudget(BudgetItem item){ + chosenBudgetItem = new BudgetItem(item.getBudgetAmount(), item.getBudgetDescription(), item.getBudgetCategory()); + chosenBudgetItem.getAmountProperty().bindBidirectional(item.getAmountProperty()); + chosenBudgetItem.getDescriptionProperty().bindBidirectional(item.getDescriptionProperty()); + chosenBudgetItem.getCategoryProperty().bindBidirectional(item.getCategoryProperty()); + amountVariable.textProperty().set(String.valueOf(item.getBudgetAmount())); + descriptionVariable.textProperty().set(item.getBudgetDescription()); + categoryVariable.setValue(item.getBudgetCategory()); + } + + public void closeButton(ActionEvent actionEvent) { + final Node source = (Node) actionEvent.getSource(); + final Stage stage = (Stage) source.getScene().getWindow(); + stage.close(); + } +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/controller/AddExpenseController.java b/src/main/java/no/ntnu/idatt1002/demo/controller/AddExpenseController.java new file mode 100644 index 0000000000000000000000000000000000000000..378929b027298692df0589fd7271c2608b732ab1 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/controller/AddExpenseController.java @@ -0,0 +1,100 @@ +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.TextField; +import javafx.stage.Stage; +import no.ntnu.idatt1002.demo.data.Economics.Expense; +import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory; +public class AddExpenseController { + Expense newExpense = null; //the expense that is chosen when editing or the expense that is created when adding + + Expense oldExpense = 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 TextField descriptionField; + + @FXML + private TextField amountField; + + @FXML + private ComboBox<ExpenseCategory> categoryBox; + + @FXML + private ComboBox<Boolean> recurringBox; + + @FXML + public void initialize() { + ObservableList<ExpenseCategory> expenseCategories = FXCollections.observableArrayList( + ExpenseCategory.values()); + categoryBox.setItems(expenseCategories); + categoryBox.setValue(ExpenseCategory.FOOD); + + ObservableList<Boolean> recurring = FXCollections.observableArrayList(true, false); + recurringBox.setItems(recurring); + recurringBox.setValue(false); + + System.out.print("This is in initialize"); + System.out.println(descriptionField); + } + + public ExpenseCategory getCategory() { + return categoryBox.getValue(); + } + + public boolean isRecurring() { + return recurringBox.getValue();//.equals("Yes"); + } + + public void setExpense(Expense expense) { //TODO NEED CANCEL BUTTON TO REMOVE THE CHANGES IF CANCEL IS PRESSED + dateField.textProperty().bindBidirectional(new SimpleStringProperty(expense.getDate().toString())); + amountField.textProperty().bindBidirectional(expense.amountProperty(), NumberFormat.getNumberInstance()); //TODO AMOUNT IS STORED WITH COMMA, WHICH IS NOT ALLOWED + descriptionField.textProperty().bindBidirectional(expense.descriptionProperty()); + //categoryBox.valueProperty().bindBidirectional(expense.getCategory()); + recurringBox.valueProperty().bindBidirectional(expense.recurringProperty()); + } + + @FXML + public void pressOkBtn(ActionEvent event) { + LocalDate date = LocalDate.parse(dateField.getText()); + double amount = Double.parseDouble(amountField.getText()); + String description = descriptionField.getText(); + ExpenseCategory category = getCategory(); + boolean recurring = isRecurring(); + newExpense = new Expense(description, amount, recurring, category, date); + System.out.println(date + " " + amount + " " + description + " " + category + " " + recurring); + + final Node source = (Node) event.getSource(); + ((Stage) source.getScene().getWindow()).close(); + } + + @FXML + public void pressCancelBtn(ActionEvent event) { + final Node source = (Node) event.getSource(); + final Stage stage = (Stage) source.getScene().getWindow(); + + stage.close(); + } + + public Expense getNewExpense() { + return this.newExpense; + } +} \ No newline at end of file diff --git a/src/main/java/no/ntnu/idatt1002/demo/controller/MainMenuController.java b/src/main/java/no/ntnu/idatt1002/demo/controller/MainMenuController.java new file mode 100644 index 0000000000000000000000000000000000000000..556801954739fd49b84564d1f4c6b1de3806f968 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/controller/MainMenuController.java @@ -0,0 +1,70 @@ +package no.ntnu.idatt1002.demo.controller; +import java.io.IOException; +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.Button; +import javafx.scene.control.DatePicker; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.image.ImageView; +import javafx.stage.Stage; + +public class MainMenuController { + + @FXML + private Button addExpenseButton; + + @FXML + private Button foodButton; + + @FXML + private Button overviewButton; + + @FXML + private ProgressBar progressbar; + + @FXML + private DatePicker date; + + @FXML + private ImageView progressMarker; + + @FXML + private Label today; + + + //ExpenseRepository expenseRepository; + @FXML + public void initialize() { + progressbar.setProgress(0.5); + //progressbar.setProgress((ExpenseRepository.getSum())/5000); + System.out.println(progressbar.getProgress()); + progressMarker.setTranslateX(-275 + progressbar.getProgress()); + today.setTranslateX(-275 + progressbar.getProgress()); + } + + @FXML + public void switchExpenses(ActionEvent event) throws IOException { + FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/Expenses.fxml")); + Parent root = loader.load(); + Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.show(); + } + + @FXML + public void switchOverview(ActionEvent event) throws IOException { + FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/Overview.fxml")); + Parent root = loader.load(); + Stage stage = (Stage) ((Node) event.getSource()).getScene().getWindow(); + Scene scene = new Scene(root); + stage.setScene(scene); + stage.show(); + } + +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/controller/SceneController.java b/src/main/java/no/ntnu/idatt1002/demo/controller/SceneController.java index 9e5479227f6955c6f9bf2bd36b07c39379cbcf2b..9d70b03508cdc080c48962db303a8c59cbae45ba 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/controller/SceneController.java +++ b/src/main/java/no/ntnu/idatt1002/demo/controller/SceneController.java @@ -1,10 +1,8 @@ package no.ntnu.idatt1002.demo.controller; -import java.awt.event.InputEvent; import java.io.IOException; import javafx.event.ActionEvent; -import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Node; import javafx.scene.Parent; @@ -12,49 +10,14 @@ import javafx.scene.Scene; import javafx.stage.Modality; import javafx.stage.Stage; -public class SceneController /*implements Initializable*/ { +public class SceneController { private Stage stage; private Scene scene; - private Parent root; - - /*@FXML - private Button add; - - @FXML - private ComboBox<?> show; - - @FXML - private TableColumn<Expense, Double> amount; - - @FXML - private TableColumn<Expense, ExpenseCategory> category; - - @FXML - private TableColumn<Expense, String> date; - - @FXML - private TableColumn<Expense, String> description; - - @FXML - private TableView<Expense> expenseTableView; - - ObservableList<Expense> expenses = FXCollections.observableArrayList( - new Expense("", 1000.00, true, ExpenseCategory.FOOD, "1/1/23") - ); - @Override - public void initialize(URL url, ResourceBundle resourceBundle) { - amount.setCellValueFactory(new PropertyValueFactory<Expense, Double>("amount")); - category.setCellValueFactory(new PropertyValueFactory<Expense, ExpenseCategory>("category")); - date.setCellValueFactory(new PropertyValueFactory<Expense, String>("date")); - description.setCellValueFactory(new PropertyValueFactory<Expense, String>("description")); - - expenseTableView.setItems(expenses); - }*/ public void switchStartMenu(ActionEvent event) throws IOException { FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/FirstMenu.fxml")); - root = loader.load(); + Parent root = loader.load(); stage = (Stage)((Node)event.getSource()).getScene().getWindow(); scene = new Scene(root); stage.setScene(scene); @@ -96,16 +59,15 @@ public class SceneController /*implements Initializable*/ { stage.show(); } - public void addExpense(ActionEvent event) throws IOException { - FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/addExpense.fxml")); - Scene newScene = new Scene(loader.load()); - Stage newStage = new Stage(); - newStage.setScene(newScene); - newStage.setResizable(false); - newStage.initModality(Modality.APPLICATION_MODAL); - - newStage.show(); + public void switchMainMenu(ActionEvent event) throws IOException { + FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/MainMenu.fxml")); + Parent root = loader.load(); + stage = (Stage)((Node)event.getSource()).getScene().getWindow(); + scene = new Scene(root); + stage.setScene(scene); + stage.show(); } + public void addIncome(ActionEvent event) throws IOException { FXMLLoader loader = new FXMLLoader(SceneController.class.getResource("/view/addIncome.fxml")); Scene newScene = new Scene(loader.load()); diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/BudgetItem.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/BudgetItem.java index e3fa2d52b304f4e7350acc95495c0a4ab48a709d..bd4860bc8650b3e94e8c9c7c81892e786127ca4d 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/BudgetItem.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/BudgetItem.java @@ -1,16 +1,19 @@ package no.ntnu.idatt1002.demo.data.Budget; +import javafx.beans.property.*; import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory; +import java.util.Objects; + /** * This class represents a budgetItem * * @author Adele */ public class BudgetItem { - private double budgetAmount; - private ExpenseCategory category; - private String description; + private DoubleProperty budgetAmount; + private ObjectProperty<ExpenseCategory> budgetCategory; + private StringProperty budgetDescription; /** * The constructor of a new Budgetitem. @@ -21,9 +24,9 @@ public class BudgetItem { * */ public BudgetItem(double budgetAmount, String description, ExpenseCategory category){ - this.budgetAmount = budgetAmount; - this.description = description; - this.category = category; + this.budgetAmount = new SimpleDoubleProperty(budgetAmount); + this.budgetDescription = new SimpleStringProperty(description); + this.budgetCategory = new SimpleObjectProperty<ExpenseCategory>(category); } /** @@ -33,7 +36,13 @@ public class BudgetItem { * */ public double getBudgetAmount() { - return budgetAmount; + return budgetAmount.get(); + } + + public DoubleProperty getAmountProperty(){ return budgetAmount;} + + public void setBudgetAmount(double amount){ + this.budgetAmount.set(amount); } /** @@ -42,8 +51,13 @@ public class BudgetItem { * @return the category as one of the categories in ExpenseCategory * */ - public ExpenseCategory getCategory() { - return category; + public ExpenseCategory getBudgetCategory() { + return budgetCategory.get(); + } + public ObjectProperty<ExpenseCategory> getCategoryProperty(){ return budgetCategory; } + + public void setBudgetCategory(ExpenseCategory category){ + this.budgetCategory.set(category); } /** @@ -52,7 +66,31 @@ public class BudgetItem { * @return the description as a String * */ - public String getDescription() { - return description; + public String getBudgetDescription() { + return budgetDescription.get(); + } + public StringProperty getDescriptionProperty(){ return budgetDescription; } + + public void setBudgetDescription(String description){ + this.budgetDescription.set(description); + } + + @Override + public String toString() { + return "budgetAmount=" + getBudgetAmount() + + "\nbudgetCategory=" + getBudgetCategory() + + "\nbudgetDescription=" + getBudgetDescription(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BudgetItem that)) return false; + return Objects.equals(budgetAmount.get(), that.budgetAmount.get()) && Objects.equals(budgetCategory.get(), that.budgetCategory.get()) && Objects.equals(budgetDescription.get(), that.budgetDescription.get()); + } + + @Override + public int hashCode() { + return Objects.hash(budgetAmount, budgetCategory, budgetDescription); } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudget.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudget.java new file mode 100644 index 0000000000000000000000000000000000000000..1d0826230f350682487f1ed9d8ef774d634fad55 --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudget.java @@ -0,0 +1,89 @@ +package no.ntnu.idatt1002.demo.data.Budget; + +import no.ntnu.idatt1002.demo.data.Economics.*; + +import java.io.*; +import java.time.LocalDate; +import java.util.ArrayList; + +/** + * FileHandling is a class for writing and reading + * Budgets to and from a file. + * + * @author andreas + */ +public class FileHandlingBudget { + private static final String filePath = "src/main/resources/Budget/"; + private static final String fileType = ".budget"; + private static final String budgetPeriod = "budgetPeriod="; + private static final String maxAmount = "maxAmount="; + private static final String budgetAmount = "budgetAmount="; + private static final String budgetCategory = "budgetCategory="; + private static final String budgetDescription = "budgetDescription="; + + /** + * Method for writing (adding) a budget to a file. + * + * @param generalBudget the budget you want to write to a file. + * @param fileTitle the name of the file you want to check + * @throws IOException if an input or output exception occurred. + */ + public void writeGeneralBudgetToFile(String fileTitle, GeneralBudget generalBudget) throws IOException { + try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath + fileTitle + fileType))) { + bw.write(generalBudget.toString()); + } catch (IOException ex) { + throw new IOException("Error writing story to file: " + ex.getMessage()); + } + } + + /** + * Method for reading (getting) a Budget from a file. + * + * @param fileTitle the name of the file you want to read from. + * @return the GeneralBudget from the file. + * @throws IOException if an input or output exception occurred. + */ + public GeneralBudget readGeneralBudgetFromFile(String fileTitle) throws IOException { + GeneralBudget generalBudget = null; + int budgetPeriod = 0; + double maxAmount = 0; + ArrayList<BudgetItem> budgetItems = new ArrayList<>(); + double budgetAmount = 0; + ExpenseCategory expenseCategory = null; + String budgetDescription = null; + + try (BufferedReader br = new BufferedReader(new FileReader(filePath + fileTitle + fileType))) { + String line; + String nextLine = br.readLine(); + while ((line = nextLine) != null) { + nextLine = br.readLine(); + if(line.startsWith(FileHandlingBudget.budgetPeriod)) { + budgetPeriod = Integer.parseInt(line.replace(FileHandlingBudget.budgetPeriod, "")); + } else if (line.startsWith(FileHandlingBudget.maxAmount)) { + maxAmount = Double.parseDouble(line.replace(FileHandlingBudget.maxAmount,"")); + } else if (line.startsWith(FileHandlingBudget.budgetAmount)) { + budgetAmount = Double.parseDouble(line.replace(FileHandlingBudget.budgetAmount,"")); + } else if (line.startsWith(FileHandlingBudget.budgetCategory)) { + line = line.replace(FileHandlingBudget.budgetCategory, ""); + expenseCategory = switch (line) { + case "FOOD" -> ExpenseCategory.FOOD; + case "CLOTHES" -> ExpenseCategory.CLOTHES; + case "BOOKS" -> ExpenseCategory.BOOKS; + default -> ExpenseCategory.OTHER; + }; + } else if (line.startsWith(FileHandlingBudget.budgetDescription)) { + budgetDescription = line.replace(FileHandlingBudget.budgetDescription,""); + } + if ((line.isEmpty() || (nextLine == null)) && (expenseCategory!=null)) { + if(generalBudget == null){ + generalBudget = new GeneralBudget(budgetPeriod,maxAmount); + generalBudget.addToBudget(budgetAmount,budgetDescription,expenseCategory); + } else{ + generalBudget.addToBudget(budgetAmount,budgetDescription,expenseCategory); + } + } + } + } + return generalBudget; + } +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java index 84e77940b0ce588dd468e63d253c8676d18773ea..6a4e46adbe1b2ba8f282341931c8dae900e6c59c 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudget.java @@ -8,8 +8,10 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.time.temporal.Temporal; +import java.util.ArrayList; import java.util.Calendar; import java.util.List; +import java.util.Objects; /** * Class that represents GeneralBudget. @@ -18,35 +20,55 @@ import java.util.List; */ public class GeneralBudget { - private int budgetPeriod; - private List<BudgetItem> listOfItems; - private double maxAmount; + private final int budgetPeriod; + private final List<BudgetItem> budgetItems; + private final double maxAmount; /** - * The constructor of a new GeneralBudget. + * Class constructor. * - * @param budgetPeriod The period the budget are going to last for - * @param listOfItems A list of BudgetItems - * @param maxAmount The maxAmount of the generalBudget as a double + * @param budgetPeriod the period the budget is going to last for. + * @param budgetItems a List of BudgetItems. + * @param maxAmount the max amount of the budget. * */ - public GeneralBudget(int budgetPeriod, List<BudgetItem> listOfItems, double maxAmount){ - if (budgetPeriod < 0) { - throw new IllegalArgumentException("The period cant be under zero days"); + public GeneralBudget(int budgetPeriod, List<BudgetItem> budgetItems, double maxAmount) { + if (budgetPeriod <= 0) { + throw new IllegalArgumentException("The period can´t be under zero days"); + } else if (maxAmount < 0) { + throw new IllegalArgumentException("The max amount of the budget cant be less than zero"); + } else { + this.budgetPeriod = budgetPeriod; + this.maxAmount = maxAmount; + this.budgetItems = budgetItems; } + } + /** + * Class constructor that creates an empty + * ArrayList for storing BudgetItems + * + * @param budgetPeriod the period the budget is going to last for. + * @param maxAmount the max amount of the budget. + */ + public GeneralBudget(int budgetPeriod, double maxAmount) { + if (budgetPeriod <= 0) { + throw new IllegalArgumentException("The period can´t be under zero days"); + } if (maxAmount < 0) { - throw new IllegalArgumentException("The maxamount of the budget cant be under zero"); + throw new IllegalArgumentException("The max amount of the budget cant be less than zero"); + } else { + this.budgetPeriod = budgetPeriod; + this.maxAmount = maxAmount; + this.budgetItems = new ArrayList<>(); } - this.budgetPeriod = budgetPeriod; - this.maxAmount = maxAmount; - this.listOfItems = listOfItems; } + /** - * This method returns the amount of days the budget should last for. + * This method returns the amount of days the budget will last for. * - * @return amount of days the budget lasts + * @return amount of days the budget lasts. * */ public int getBudgetPeriod() { @@ -54,7 +76,41 @@ public class GeneralBudget { } /** - * This method returns the amount of days left in the period as a string. + * Method for getting the maxAmount of the GeneralBudget + * @return the GeneralBudget´s + */ + public double getMaxAmount() { + return maxAmount; + } + + /** + * Method for getting budgetItems + * + * @return an ArrayList of every BudgetItem + * @throws if budgetItems is empty + */ + public List<BudgetItem> getBudgetItems() throws IllegalArgumentException { + return budgetItems; + } + + /** + * Method for getting a Specific BudgetItem + * from budgetItems + * @param expenseCategory the ExpenseCategory of the BudgetItem you want to get + * @throws IllegalArgumentException if there is no BudgetItem with the given ExpenseCategory + * @return the BudgetItem with the expenseCategory + */ + public BudgetItem getBudgetItem(ExpenseCategory expenseCategory) throws IllegalArgumentException{ + for(BudgetItem budgetItem1 : budgetItems){ + if (budgetItem1.getBudgetCategory().equals(expenseCategory)) { + return budgetItem1; + } + } + throw new IllegalArgumentException("No BudgetItem for this ExpenseCategory"); + } + + /** + * This method returns the amount of days left in the budget period as a string. * * @return the amount of days left in the budget period * @@ -75,18 +131,35 @@ public class GeneralBudget { /** * This method adds a budgetItem to the list of budgetItems in the generalBudget * - * @param budgetAmount The amount of budget as a double - * @param description A description of the budget as a String - * @param category A category from ExpenseCategory + * @param budgetItem the budgetItem you want to add * */ - public void addToBudget(double budgetAmount, String description, ExpenseCategory category) { - if (totalSum() + budgetAmount > maxAmount ){ + public void addToBudgetBudgetItem(BudgetItem budgetItem) { + if (totalSum() + budgetItem.getBudgetAmount() > maxAmount) { throw new IllegalArgumentException("Amount to be added goes over the max value of the budget"); } - if (!checksListOfItemsContainsBudgetItem(category)) { - listOfItems.add(new BudgetItem(budgetAmount, description, category)); + if (!hasBudgetCategory(budgetItem.getBudgetCategory())) { + budgetItems.add(budgetItem); + } else { + throw new IllegalArgumentException("There is already a budget with this category"); + } + } + + /** + * This method takes in a double budgetAmount, String description + * and a String category to create and add a BudgetItem to budgetItems + * + * @param budgetAmount The amount of budget as a double + * @param description A description of the budget as a String + * @param category A category from ExpenseCategory + */ + public void addToBudget(double budgetAmount, String description, ExpenseCategory category) { + if ((totalSum() + budgetAmount) > maxAmount) { + throw new IllegalArgumentException("Amount to be added goes over the max value of the budget"); + } + if (!hasBudgetCategory(category)) { + budgetItems.add(new BudgetItem(budgetAmount, description, category)); } else { throw new IllegalArgumentException("There is already a budget with this category"); } @@ -96,28 +169,22 @@ public class GeneralBudget { * This method checks if the list in the generalBudget already contains a budgetItem with a specified category. * * @param category A category from ExpenseCategory - * * @return True if the list contains a budgetItem with this category and false if it does not * */ - public boolean checksListOfItemsContainsBudgetItem(ExpenseCategory category){ - for (BudgetItem item : listOfItems) { - if (item.getCategory() == category) { - return true; - } - } - return false; + public boolean hasBudgetCategory(ExpenseCategory category) { + return budgetItems.stream().anyMatch(budgetItem -> budgetItem.getBudgetCategory().equals(category)); } /** - * This method returns the totalSum of all budgetsItems in the list in the generalBudget + * This method returns the totalSum of all budgetItems in the generalBudget * * @return the sum of the budgetsItems as a double * */ - public double totalSum(){ + public double totalSum() { double sum = 0; - for (BudgetItem budgetItem : listOfItems) { + for (BudgetItem budgetItem : budgetItems) { sum += budgetItem.getBudgetAmount(); } return sum; @@ -129,7 +196,51 @@ public class GeneralBudget { * @param category A category from ExpenseCategory * */ - public void deleteItemFromBudget(ExpenseCategory category){ - listOfItems.removeIf(item -> item.getCategory() == category); + public void deleteItemFromBudget(ExpenseCategory category) { + budgetItems.removeIf(item -> item.getBudgetCategory() == category); + } + + @Override + public String toString() { + StringBuilder budgetItemsString = new StringBuilder(); + for(BudgetItem budgetItem : budgetItems){ + budgetItemsString.append(budgetItem+"\n\n"); + } + if(budgetItemsString.isEmpty()) { + return "budgetPeriod="+getBudgetPeriod()+"\nmaxAmount="+getMaxAmount()+"\n\n"; + } else { + return "budgetPeriod="+getBudgetPeriod()+"\nmaxAmount="+getMaxAmount()+"\n\n"+budgetItemsString; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof GeneralBudget that)) return false; + return budgetPeriod == that.budgetPeriod && Double.compare(that.maxAmount, maxAmount) == 0 && Objects.equals(budgetItems, that.budgetItems); + } + + @Override + public int hashCode() { + return Objects.hash(budgetPeriod, budgetItems, maxAmount); + } + + /** + * Check if there is a BudgetItem for + * a specific category + * + * @param category the category you want to check + * @return true or false depending on if there is a BudgetItem for category + */ + + /** + public boolean hasBudgetCategory(ExpenseCategory category){ + for (BudgetItem item : listOfItems) { + if (item.getCategory() == category) { + return true; + } + } + return false; } + */ } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Expense.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Expense.java index 078ec99f4e9bfdef73c76b8396026dac0cbd2a7e..11848b02acc76fa0c1959fef8e75342055e1ee65 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Expense.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Expense.java @@ -1,7 +1,13 @@ package no.ntnu.idatt1002.demo.data.Economics; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.time.LocalDate; +import java.util.Objects; + public class Expense extends Item{ - private ExpenseCategory category; + private ObjectProperty<ExpenseCategory> category; /** * This constructor uses the super constructor to set the fields for 'amount' and 'recurring' and then sets the @@ -13,13 +19,13 @@ public class Expense extends Item{ * @param category The category to which the Expense belongs to, provided as a value of ExpenseCategory. * @param date The date of the Expense at format "dd.mm.yy". */ - public Expense(double amount, boolean recurring, ExpenseCategory category, String date) { + public Expense(double amount, boolean recurring, ExpenseCategory category, LocalDate date) { super(amount, recurring, date); if(category == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = category; + this.category = new SimpleObjectProperty<>(category); } /** @@ -31,13 +37,12 @@ public class Expense extends Item{ * @param category The category to which the Expense belongs to, provided as a value of ExpenseCategory * @param date The date of the Expense at format "dd.mm.yy". */ - public Expense(String description, double amount, boolean recurring, ExpenseCategory category, String date) { + public Expense(String description, double amount, boolean recurring, ExpenseCategory category, LocalDate date) { super(description, amount, recurring, date); if(category == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = category; - + this.category = new SimpleObjectProperty<>(category); } /** @@ -45,7 +50,7 @@ public class Expense extends Item{ * @return The category the Expense belongs to as a value of the ExpenseCategory enum class. */ public ExpenseCategory getCategory() { - return category; + return category.get(); } /** @@ -56,7 +61,7 @@ public class Expense extends Item{ if(expenseCategory == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = expenseCategory; + this.category.set(expenseCategory); } /** @@ -66,6 +71,19 @@ public class Expense extends Item{ */ @Override public String toString() { - return super.toString()+"category="+category.toString()+"\n\n"; + return super.toString()+"category="+category.get()+"\n\n"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Expense expense)) return false; + if (!super.equals(o)) return false; + return category.get() == expense.category.get(); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), category); } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseCategory.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseCategory.java index c1043a4da811ab182cca75ef49972e44a218a6f2..f5af9a40e675e00a08149df7301e18b85d57b752 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseCategory.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseCategory.java @@ -2,9 +2,16 @@ package no.ntnu.idatt1002.demo.data.Economics; public enum ExpenseCategory { - FOOD, - CLOTHES, - BOOKS, - OTHER, + FOOD("food"), + CLOTHES("clothes"), + BOOKS("books"), + OTHER("other"); + + + public final String label; + + ExpenseCategory(String label) { + this.label = label; + } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegister.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegister.java index 1a279301d3d658581181a8b2b0bbcea2edbe56ee..0c2ed89cb66da3df755ef0732596ddd04e9e4782 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegister.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegister.java @@ -1,11 +1,15 @@ package no.ntnu.idatt1002.demo.data.Economics; +import java.time.YearMonth; import java.util.List; +import java.util.stream.Collectors; /** * ExpenseRegister is a class for * storing Expenses. Subclass of * ItemRegister. + * + * @author andreas */ public class ExpenseRegister extends ItemRegister<Expense> { @@ -30,9 +34,30 @@ public class ExpenseRegister extends ItemRegister<Expense> { * in a given ExpenseCategory. * * @param category the ExpenseCategory you want to get every Expense of. - * @return a List of every Expense with category. + * @return a new ExpenseRegister of every Expense with category. */ - public List<Expense> getExpenseByCategory(ExpenseCategory category){ - return this.items.stream().filter(expense -> expense.getCategory().compareTo( category) == 0).toList(); + public ExpenseRegister getExpenseByCategory(ExpenseCategory category){ + return new ExpenseRegister(this.items.stream().filter(expense -> expense.getCategory().compareTo( category) == 0).toList()); + } + + /** + * Get the Expenses that are registered with a date corresponding to the given month and year. + * @param yearMonth month and year for which to withdraw Expenses. + * @return list of Expenses for a certain month and year. + */ + public ExpenseRegister getExpenseByMonth(YearMonth yearMonth) { + return new ExpenseRegister(items.stream() + .filter(income -> YearMonth.from(income.getDate()).equals(yearMonth)) + .collect(Collectors.toList())); + } + + /** + * Get the Expenses that are recurring. + * + * @return a new ExpenseRegister of recurring Expenses. + */ + public ExpenseRegister getRecurringExpense(){ + return new ExpenseRegister(items.stream() + .filter(Item::isRecurring).toList()); } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/FileHandling.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/FileHandling.java index bfbe5ab7098c96ebeef9c33e614e14a8658f16b5..ce4e00ed260290b4e79207556604b7956c5b2344 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/FileHandling.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/FileHandling.java @@ -4,11 +4,14 @@ import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.*; +import java.time.LocalDate; /** * FileHandling is a class for writing and reading - * Item-objects to and from a file. + * ItemRegister-objects to and from a file. + * + * @author andreas */ public class FileHandling{ private static final String filePath = "src/main/resources/Economics/"; @@ -16,33 +19,55 @@ public class FileHandling{ private static final String date = "date="; private static final String description = "description="; private static final String amount = "amount="; - private static final String isReoccuring = "isReoccuring="; + private static final String isRecurring = "isRecurring="; private static final String category = "category="; /** * Method for writing (adding) an ItemRegister to a file. * * @param itemRegister the ItemRegister you want to write to a file. + * @param fileTitle the name of the file you want to check * @throws IOException if an input or output exception occurred. */ public <T extends Item>void writeItemRegisterToFile(final ItemRegister<T> itemRegister, String fileTitle) throws IOException { try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath + fileTitle + fileType))) { - bw.write(itemRegister.toString()); + if (itemRegister.isEmpty()){ + bw.write(""); + } else{ + bw.write(itemRegister.toString()); + } } catch (IOException ex) { throw new IOException("Error writing story to file: " + ex.getMessage()); } } /** + * Method for checking if a .register file is empty. + * + * @param fileTitle the name of the file you want to check + * @return true or false depending on if file is empty. + * @throws IOException if an input or output exception occurred. + */ + public boolean isEmpty(String fileTitle) throws IOException { + try (BufferedReader br = new BufferedReader(new FileReader(filePath + fileTitle + fileType))) { + if (br.readLine() == null) { + return true; + } else { + return false; + } + } + } + + /** * Method for reading (getting) an IncomeRegister from a file. * - * @param fileTitle the name of the file you want to read from + * @param fileTitle the name of the file you want to read from. * @return the IncomeRegister from the file. - * @throws IOException if an input or output exception occurred + * @throws IOException if an input or output exception occurred. */ public IncomeRegister readIncomeRegisterFromFile(String fileTitle) throws IOException { IncomeRegister incomeRegister = new IncomeRegister(); - String date = ""; + LocalDate date = null; String description = ""; double amount = 0; boolean reoccuring = false; @@ -53,13 +78,13 @@ public class FileHandling{ while ((line = nextLine) != null) { nextLine = br.readLine(); if(line.startsWith(FileHandling.date)) { - date = line.replace(FileHandling.date, ""); + date = LocalDate.parse(line.replace(FileHandling.date, "")); } else if (line.startsWith(FileHandling.description)) { description = line.replace(FileHandling.description,""); } else if (line.startsWith(FileHandling.amount)) { amount = Double.parseDouble(line.replace(FileHandling.amount,"")); - } else if (line.startsWith(FileHandling.isReoccuring)) { - reoccuring = line.replace(FileHandling.isReoccuring,"").equals("Reoccurring"); + } else if (line.startsWith(FileHandling.isRecurring)) { + reoccuring = line.replace(FileHandling.isRecurring,"").equals("Recurring"); } else if (line.startsWith(FileHandling.category)) { line = line.replace(FileHandling.category,""); incomeCategory = switch (line) { @@ -90,7 +115,7 @@ public class FileHandling{ */ public ExpenseRegister readExpenseRegisterFromFile(String fileTitle) throws IOException { ExpenseRegister expenseRegister = new ExpenseRegister(); - String date = ""; + LocalDate date = null; String description = ""; double amount = 0; boolean reoccuring = false; @@ -101,13 +126,13 @@ public class FileHandling{ while ((line = nextLine) != null) { nextLine = br.readLine(); if (line.startsWith(FileHandling.date)) { - date = line.replace(FileHandling.date, ""); + date = LocalDate.parse(line.replace(FileHandling.date, "")); } else if (line.startsWith(FileHandling.description)) { description = line.replace(FileHandling.description, ""); } else if (line.startsWith(FileHandling.amount)) { amount = Double.parseDouble(line.replace(FileHandling.amount, "")); - } else if (line.startsWith(FileHandling.isReoccuring)) { - reoccuring = line.replace(FileHandling.isReoccuring, "").equals("Reoccurring"); + } else if (line.startsWith(FileHandling.isRecurring)) { + reoccuring = line.replace(FileHandling.isRecurring, "").equals("Recurring"); } else if (line.startsWith(FileHandling.category)) { line = line.replace(FileHandling.category, ""); expenseCategory = switch (line) { @@ -129,4 +154,4 @@ public class FileHandling{ } return expenseRegister; } -} \ No newline at end of file +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Income.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Income.java index c07821dc0e79b6ec8ae934cb8ca4a1fadda78ea5..904ab935c2c23da4ef0f859c5a89aafe454a4997 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Income.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Income.java @@ -1,5 +1,11 @@ package no.ntnu.idatt1002.demo.data.Economics; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + +import java.time.LocalDate; +import java.util.Objects; + /** * The Income class inherits from the Item class. The Item class additionally has a private field for an * enum value of IncomeCategory. @@ -8,7 +14,7 @@ package no.ntnu.idatt1002.demo.data.Economics; */ public class Income extends Item{ - private IncomeCategory category; + private ObjectProperty<IncomeCategory> category; /** * This constructor uses the super constructor to set the fields for 'amount' and 'recurring' and then sets the @@ -20,13 +26,13 @@ public class Income extends Item{ * @param category The category to which the Income belongs to, provided as a value of IncomeCategory. * @param date The date of the Income at format "dd.mm.yy". */ - public Income(double amount, boolean recurring, IncomeCategory category, String date) { + public Income(double amount, boolean recurring, IncomeCategory category, LocalDate date) { super(amount, recurring, date); if(category == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = category; + this.category = new SimpleObjectProperty<>(category); } /** @@ -38,12 +44,12 @@ public class Income extends Item{ * @param category The category to which the income belongs to, provided as a value of IncomeCategory. * @param date The date of the Income at format "dd.mm.yy". */ - public Income(String description, double amount, boolean recurring, IncomeCategory category, String date) { + public Income(String description, double amount, boolean recurring, IncomeCategory category, LocalDate date) { super(description, amount, recurring, date); if(category == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = category; + this.category = new SimpleObjectProperty<>(category); } @@ -52,7 +58,7 @@ public class Income extends Item{ * @return The category to which the Income belongs to as a value of the IncomeCategory enum. */ public IncomeCategory getCategory() { - return category; + return category.get(); } /** @@ -63,7 +69,7 @@ public class Income extends Item{ if(category == null) { throw new IllegalArgumentException("The income must belong to a category."); } - this.category = category; + this.category.set(category); } /** @@ -73,6 +79,19 @@ public class Income extends Item{ */ @Override public String toString() { - return super.toString()+"category="+category.toString()+"\n\n"; + return super.toString()+"category="+category.get()+"\n\n"; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Income income)) return false; + if (!super.equals(o)) return false; + return Objects.equals(category.get(), income.category.get()); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), category); } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeCategory.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeCategory.java index 021d993c35000429f906ecbb8ae2d85f2c681eea..5c5ce82c812b64482def698c439beed1e7f0c34b 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeCategory.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeCategory.java @@ -1,7 +1,13 @@ package no.ntnu.idatt1002.demo.data.Economics; public enum IncomeCategory { - SALARY, - STUDENT_LOAN, - GIFT + SALARY("salary"), + STUDENT_LOAN("student loan"), + GIFT("gift"); + + public final String label; + + IncomeCategory(String label) { + this.label = label; + } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegister.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegister.java index 1a9c4a126700254f2e7cf60be624edcbf337e04b..2b4b6f9463a5c4fe2a7a36406e0b14a2c5cc8394 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegister.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegister.java @@ -1,11 +1,15 @@ package no.ntnu.idatt1002.demo.data.Economics; +import java.time.YearMonth; import java.util.List; +import java.util.stream.Collectors; /** * IncomeRegister is a class for * storing Income. Subclass of * ItemRegister. + * + * @author andreas */ public class IncomeRegister extends ItemRegister<Income>{ /** @@ -29,9 +33,32 @@ public class IncomeRegister extends ItemRegister<Income>{ * in a given IncomeCategory. * * @param category the IncomeCategory you want to get every Income of. - * @return a List of every Income with category. + * @return a new IncomeRegister of every Income with category. */ - public List<Income> getIncomeByCategory(IncomeCategory category){ - return items.stream().filter(income -> income.getCategory().compareTo(category) == 0).toList(); + public IncomeRegister getIncomeByCategory(IncomeCategory category){ + return new IncomeRegister(items.stream() + .filter(income -> income.getCategory().compareTo(category) == 0) + .toList()); + } + + /** + * Get the Income that are registered with a date corresponding to the given month and year. + * @param yearMonth month and year for which to withdraw T's=(Income or Expenses). + * @return list of Income for a certain month and year. + */ + public IncomeRegister getIncomeByMonth(YearMonth yearMonth) { + return new IncomeRegister(items.stream() + .filter(income -> YearMonth.from(income.getDate()).equals(yearMonth)) + .collect(Collectors.toList())); + } + + /** + * Get the Income that are recurring. + * + * @return a new IncomeRegister of recurring Income. + */ + public IncomeRegister getRecurringIncome(){ + return new IncomeRegister(items.stream() + .filter(Item::isRecurring).toList()); } } diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Item.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Item.java index 7bd8b00ee062e35ee5a51c94f359c168ef7d95ad..a04f0bcb7095db7974a2b917a30b08663d12ae0d 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Item.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Item.java @@ -1,7 +1,10 @@ package no.ntnu.idatt1002.demo.data.Economics; +import java.time.LocalDate; import java.util.Objects; +import javafx.beans.property.*; + /** * The Item class represents a good or service purchased in real life. The item belongs to a category and * has an amount, description and a date. The description may be left blank, but the Item must belong to a category and must @@ -10,23 +13,23 @@ import java.util.Objects; * */ public abstract class Item { - private String description = ""; - private double amount; - private boolean recurring; - private String date; // Format example: 09.08.23 + private StringProperty description = new SimpleStringProperty(""); + private final DoubleProperty amount; + private BooleanProperty recurring; + private ObjectProperty<LocalDate> date; // Format example: 09.08.23 /** * The constructor of a new Item object takes in an amount as a double. If the amount is left blank, an * IllegalArgumentException is thrown. * @param amount price of an Item as a float. */ - public Item (double amount, boolean recurring, String date){ - if(amount <= 1.0f || date.isBlank()) { + public Item (double amount, boolean recurring, LocalDate date){ + if(amount <= 1.0f || date.toString().isBlank()) { throw new IllegalArgumentException("Both amount and date must be provided."); } else { - this.amount = amount; - this.recurring = recurring; - this.date = date; + this.amount = new SimpleDoubleProperty(amount); + this.recurring = new SimpleBooleanProperty(recurring); + this.date = new SimpleObjectProperty<>(date); } } @@ -37,25 +40,33 @@ public abstract class Item { * @param description A description of the item as a String. * @param amount The price of the item as a float. */ - public Item (String description, double amount, boolean recurring, String date){ - this(amount, recurring, date); - this.description=description; + public Item (String description, double amount, boolean recurring, LocalDate date){ + this(amount, recurring, date); + this.description = new SimpleStringProperty(description); } + public StringProperty descriptionProperty() { + return this.description; + } /** * The method returns the description of the given Item object as a String. * @return The description of the Item as a String. */ public String getDescription() { - return description; + return description.get(); } + /** * The method sets the description of the Item object equal to the passed String. The String may be empty. * @param description The new description of the Item object as a String. */ public void setDescription(String description) { - this.description = description; + this.description.set(description); + } + + public DoubleProperty amountProperty() { + return this.amount; } /** @@ -63,7 +74,7 @@ public abstract class Item { * @return The amount of the Item as a float. */ public double getAmount() { - return amount; + return amount.get(); } /** @@ -74,7 +85,15 @@ public abstract class Item { if(amount <= 1.0f ) { throw new IllegalArgumentException("A positive amount must be provided"); } - this.amount = amount; + this.amount.set(amount); + } + + /** + * The method returns the BooleanProperty of recurring. + * @return BooleanProperty whose value is either true or false. + */ + public BooleanProperty recurringProperty() { + return this.recurring; } /** @@ -82,7 +101,7 @@ public abstract class Item { * @return True if the transaction is a recurring one, false otherwise. */ public boolean isRecurring() { - return recurring; + return recurring.get(); } /** @@ -90,33 +109,39 @@ public abstract class Item { * @param recurring A boolean value being true if the Item is recurring and false otherwise. */ public void setRecurring(boolean recurring) { - this.recurring = recurring; + this.recurring.set(recurring); } + public StringProperty dateProperty() { + return this.dateProperty(); + } + /** + public StringProperty dateProperty() { + return this.date; + } + */ /** * The method returns the date of the item object (income/expense). * @return The date of the transaction. */ - public String getDate() { - return date; + public LocalDate getDate() { + return this.date.get(); } /** - * Sets the date field of the Item object to a new String provided as an argument. + * Sets the date field of the Item object to a new LocalDate provided as an argument. + * * @param newDate The new date with which to record the Item. */ - public void setDate(String newDate) { - if(date.isBlank()) { - throw new IllegalArgumentException("A date must be provided."); - } - this.date = newDate; + public void setDate(LocalDate newDate) { + this.date.set(newDate); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Item item)) return false; - return Double.compare(item.amount, amount) == 0 && recurring == item.recurring && Objects.equals(description, item.description) && Objects.equals(date, item.date); + return Double.compare(item.amount.get(), amount.get()) == 0 && item.recurring.get() == recurring.get() && Objects.equals(description.get(), item.description.get()) && Objects.equals(date.get(), item.date.get()); } @Override @@ -130,18 +155,18 @@ public abstract class Item { */ @Override public String toString() { - String isReoccuring = ""; - if(recurring){ - isReoccuring = "Reoccurring"; + String isRecurring = ""; + if(recurring.get()){ + isRecurring = "Recurring"; } else{ - isReoccuring = "Not reoccurring"; + isRecurring = "Not recurring"; } - if(!description.isBlank()){ - return "date=" + date+"\ndescription=" + description+"\namount="+amount+"\nisReoccuring="+isReoccuring+"\n"; + if(!description.get().isBlank()){ + return "date=" + date.get() +"\ndescription=" + description.get()+"\namount="+amount.get()+"\nisRecurring="+isRecurring+"\n"; } else{ - return "date="+date+"\namount="+amount+"\nisReoccuring="+isReoccuring+"\n"; + return "date="+date.get() +"\namount="+amount.get()+"\nisRecurring="+isRecurring+"\n"; } } @@ -167,3 +192,4 @@ public abstract class Item { } + diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ItemRegister.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ItemRegister.java index dbe2cc95dd2ea265989e2981c4a159215a6844d7..9a38712eedada7b202fec8ee0266b5fdf89eea21 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ItemRegister.java +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/ItemRegister.java @@ -1,13 +1,17 @@ package no.ntnu.idatt1002.demo.data.Economics; +import java.time.Year; +import java.time.YearMonth; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * ItemRegister is a generic class used * for storing either Income or Expense. * * @param <T> Income or Expense + * @author andreas */ public abstract class ItemRegister<T extends Item>{ List<T> items; @@ -36,7 +40,6 @@ public abstract class ItemRegister<T extends Item>{ public List<T> getItems() { return items; } - /** * Add a new item to the register. * @@ -80,6 +83,7 @@ public abstract class ItemRegister<T extends Item>{ return items.stream().map(Item::getAmount).mapToDouble(Double::doubleValue).sum(); } + @Override public String toString() { StringBuilder stringItems = new StringBuilder(); diff --git a/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Overview.java b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Overview.java new file mode 100644 index 0000000000000000000000000000000000000000..ebf814a1e01dc31ed0bb215145a083aed79b58eb --- /dev/null +++ b/src/main/java/no/ntnu/idatt1002/demo/data/Economics/Overview.java @@ -0,0 +1,94 @@ +package no.ntnu.idatt1002.demo.data.Economics; + +import no.ntnu.idatt1002.demo.data.Budget.BudgetItem; +import no.ntnu.idatt1002.demo.data.Budget.GeneralBudget; + +/** + * Class for getting an overview + * on your total revenue. + * + * @author andreas + */ +public class Overview { + private final IncomeRegister incomeRegister; + private final ExpenseRegister expenseRegister; + private double balance; + private GeneralBudget budget; + /** + * Class constructor that creates an empty incomeRegister, expenseRegister + * and set totalRevenue to zero. + */ + public Overview(){ + this.incomeRegister = new IncomeRegister(); + this.expenseRegister = new ExpenseRegister(); + this.balance = 0; + } + + /** + * Class constructor that takes in an incomeRegister and + * expenseRegister and calculates total balance + * based on them. + * @param incomeRegister the incomeRegister you want to overview. + * @param expenseRegister the expenseRegister you want to overview. + */ + public Overview(IncomeRegister incomeRegister, ExpenseRegister expenseRegister){ + this.incomeRegister = incomeRegister; + this.expenseRegister = expenseRegister; + updateBalance(); + } + + /** + * Get the total revenue of overview + * @return the overview´s total revenue + */ + public double getTotalBalance(){ + return balance; + } + + /** + * Method for updating the total revenue + * by taking the total sum of the income register + * minus the total sum of the expense register. + */ + public void updateBalance(){ + balance = incomeRegister.getTotalSum() - expenseRegister.getTotalSum(); + } + + /** + * Method for getting a percentage + * of the total revenue + * @param percentage the percentage you want to get + * @return a percentage of total revenue + */ + public double getPercentageOfTotalBalance(double percentage){ + return Math.round(balance*(percentage/100)); + } + + /** + * Method for getting Expense subtracted from + * a BudgetItem for a specific ExpenseCategory. + * + * @param category the ExpenseCategory you want to use. + * @return Expense subtracted from BudgetItem for category. + */ + public double getBudgetItemMinusExpense(ExpenseCategory category){ + if(budget.hasBudgetCategory(category)){ + return budget.getBudgetItem(category).getBudgetAmount() - expenseRegister.getExpenseByCategory(category).getTotalSum(); + } else{ + throw new IllegalArgumentException("There is no Budget for the budget category"); + } + } + + /** + * Method for checking if you have used up + * a specific BudgetItem. + * + * @param category the ExpenseCategory you want to check. + * @return true or false depending on if you have used it up. + */ + public boolean hasUsedUpBudgetItem(ExpenseCategory category){ + return (getBudgetItemMinusExpense(category)<=0); + } + + +} diff --git a/src/main/java/no/ntnu/idatt1002/demo/view/ExpenseDialog.java b/src/main/java/no/ntnu/idatt1002/demo/view/ExpenseDialog.java deleted file mode 100644 index 147ef3e8d7aef00c5ac8f974cf910566b9ec344e..0000000000000000000000000000000000000000 --- a/src/main/java/no/ntnu/idatt1002/demo/view/ExpenseDialog.java +++ /dev/null @@ -1,167 +0,0 @@ -package no.ntnu.idatt1002.demo.view; - -import javafx.geometry.Insets; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; -import no.ntnu.idatt1002.demo.data.Economics.Expense; - -public class ExpenseDialog extends Dialog<Expense> { - - public enum Mode { - NEW, EDIT - } - - //private final Mode mode; - - /* - package edu.ntnu.idatt2001.mvc.contacts.views; - -import edu.ntnu.idatt2001.mvc.contacts.model.Contact; -import javafx.geometry.Insets; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Dialog; -import javafx.scene.control.Label; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; - - public class ContactDetailsDialog extends Dialog<Contact> { - - - public enum Mode { - NEW, EDIT, INFO - } - - - private final Mode mode; - - private Contact existingContact = null; - public ContactDetailsDialog() { - super(); - this.mode = Mode.NEW; - // Create the content of the dialog - createContent(); - - } - - public ContactDetailsDialog(Contact contact, boolean editable) { - super(); - if (editable) { - this.mode = Mode.EDIT; - } else { - this.mode = Mode.INFO; - } - this.existingContact = contact; - // Create the content of the dialog - createContent(); - } - - - private void createContent() { - // Set title depending upon mode... - switch (this.mode) { - case EDIT: - setTitle("Contact Details - Edit"); - break; - - case NEW: - setTitle("Contact Details - Add"); - break; - - case INFO: - setTitle("Contact Details"); - break; - - default: - setTitle("Contact Details - UNKNOWN MODE..."); - break; - - } - - // Set the button types. - getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); - - GridPane grid = new GridPane(); - grid.setHgap(10); - grid.setVgap(10); - grid.setPadding(new Insets(20, 150, 10, 10)); - - TextField name = new TextField(); - name.setPromptText("Name"); - - TextField address = new TextField(); - address.setPromptText("Address"); - - TextField phoneNumber = new TextField(); - phoneNumber.setPromptText("Phone number"); - - // Fill inn data from the provided Newspaper, if not null. - if ((mode == Mode.EDIT) || (mode == Mode.INFO)) { - name.setText(existingContact.getName()); - address.setText(existingContact.getAddress()); - phoneNumber.setText(existingContact.getPhone()); - // Set to non-editable if Mode.INFO - if (mode == Mode.INFO) { - name.setEditable(false); - address.setEditable(false); - phoneNumber.setEditable(false); - } - } - - grid.add(new Label("Name:"), 0, 0); - grid.add(name, 1, 0); - grid.add(new Label("Address:"), 0, 1); - grid.add(address, 1, 1); - grid.add(new Label("Phone number:"), 0, 2); - grid.add(phoneNumber, 1, 2); - - getDialogPane().setContent(grid); - - // Convert the result to ContactDetails-instance when the OK button is clicked. - // Check out: - // https://docs.oracle.com/javase/8/javafx/api/javafx/scene/control/Dialog.html#setResultConverter-javafx.util.Callback- - // and: https://docs.oracle.com/javase/8/javafx/api/javafx/util/Callback.html - setResultConverter((ButtonType button) -> { - Contact result = null; - if (button == ButtonType.OK) { - - if (mode == Mode.NEW) { - result = new Contact(name.getText(), phoneNumber.getText(), address.getText()); - } else if (mode == Mode.EDIT) { - existingContact.setName(name.getText()); - existingContact.setAddress(address.getText()); - existingContact.setPhone(phoneNumber.getText()); - - result = existingContact; - } - } - return result; - }); - } - } - - - - public ExpenseDialog() { - super(); - this.mode = Mode.NEW; - // Create the content of the dialog - createContent(); - } - - - public ExpenseDialog(Expense expense, boolean editable) { - super(); - if (editable) { - this.mode = Mode.EDIT; - } else { - this.mode = Mode.INFO; - } - this. = contact; - // Create the content of the dialog - createContent(); - }*/ - -} diff --git a/src/main/java/no/ntnu/idatt1002/demo/view/MyApp.java b/src/main/java/no/ntnu/idatt1002/demo/view/MyApp.java index 171e4e68702e7fe81de7206e458f8315e824b6ba..148b88524acd9271e95344e4c9c33dcd5a253981 100644 --- a/src/main/java/no/ntnu/idatt1002/demo/view/MyApp.java +++ b/src/main/java/no/ntnu/idatt1002/demo/view/MyApp.java @@ -22,4 +22,4 @@ public class MyApp extends Application { public static void main(String[] args) { launch(args); } -} \ No newline at end of file +} diff --git a/src/main/resources/Budget/multipleBudgetItem.budget b/src/main/resources/Budget/multipleBudgetItem.budget new file mode 100644 index 0000000000000000000000000000000000000000..99d8a34c324f73c0614113790af7db0fb7d74029 --- /dev/null +++ b/src/main/resources/Budget/multipleBudgetItem.budget @@ -0,0 +1,15 @@ +budgetPeriod=12 +maxAmount=1200.0 + +budgetAmount=500.0 +budgetCategory=FOOD +budgetDescription=description + +budgetAmount=200.0 +budgetCategory=BOOKS +budgetDescription=anotherDescription + +budgetAmount=150.0 +budgetCategory=CLOTHES +budgetDescription=anotheranotherdescription + diff --git a/src/main/resources/Budget/oneBudgetItemTest.budget b/src/main/resources/Budget/oneBudgetItemTest.budget new file mode 100644 index 0000000000000000000000000000000000000000..eaa80cf9eafc900e3419078665bc59ed14bc25a2 --- /dev/null +++ b/src/main/resources/Budget/oneBudgetItemTest.budget @@ -0,0 +1,7 @@ +budgetPeriod=12 +maxAmount=1200.0 + +budgetAmount=500.0 +budgetCategory=FOOD +budgetDescription=description + diff --git a/src/main/resources/Economics/expenseRegisterTest.itemRegister b/src/main/resources/Economics/expenseRegisterTest.itemRegister new file mode 100644 index 0000000000000000000000000000000000000000..7f98526b7b5d9fa27c8d5ec080a8b33f9fb0b143 --- /dev/null +++ b/src/main/resources/Economics/expenseRegisterTest.itemRegister @@ -0,0 +1,6 @@ + +date=03.03.23 +description=description +amount=59.900001525878906 +isReoccuring=Not reoccurring +category=CLOTHES diff --git a/src/main/resources/Economics/expenseRegisterTest.register b/src/main/resources/Economics/expenseRegisterTest.register index c7d084112c6de671e412d5e185da4f5aee5a0327..11dddf990a7aab151c18cf9e48c46836f288e508 100644 --- a/src/main/resources/Economics/expenseRegisterTest.register +++ b/src/main/resources/Economics/expenseRegisterTest.register @@ -1,6 +1,6 @@ -date=03.03.23 +date=2023-03-03 description=description amount=59.900001525878906 -isReoccuring=Not reoccurring +isRecurring=Not recurring category=CLOTHES diff --git a/src/main/resources/Economics/incomeRegisterTest.itemRegister b/src/main/resources/Economics/incomeRegisterTest.itemRegister new file mode 100644 index 0000000000000000000000000000000000000000..6bfe0943a9c759b6838d594b03262e3727212ce9 --- /dev/null +++ b/src/main/resources/Economics/incomeRegisterTest.itemRegister @@ -0,0 +1,6 @@ + +date=03.03.23 +description=description +amount=59.900001525878906 +isReoccuring=Not reoccurring +category=GIFT diff --git a/src/main/resources/Economics/incomeRegisterTest.register b/src/main/resources/Economics/incomeRegisterTest.register index 0b3082def4aa9d25e83b22a1dbc298bcb85459ba..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/main/resources/Economics/incomeRegisterTest.register +++ b/src/main/resources/Economics/incomeRegisterTest.register @@ -1,6 +0,0 @@ -date=03.03.23 -description=description -amount=59.900001525878906 -isReoccuring=Not reoccurring -category=GIFT - diff --git a/src/main/resources/Images/add_image 2.png b/src/main/resources/Images/add_image 2.png new file mode 100644 index 0000000000000000000000000000000000000000..f8fd29245588cf7264711402a4610b4a23e3bfeb Binary files /dev/null and b/src/main/resources/Images/add_image 2.png differ diff --git a/src/main/resources/Images/add_image.png b/src/main/resources/Images/add_image.png new file mode 100644 index 0000000000000000000000000000000000000000..f8fd29245588cf7264711402a4610b4a23e3bfeb Binary files /dev/null and b/src/main/resources/Images/add_image.png differ diff --git a/src/main/resources/Images/arrow 2.png b/src/main/resources/Images/arrow 2.png new file mode 100644 index 0000000000000000000000000000000000000000..9d65c03b2a4d3710c674655f1a3201935735c9f5 Binary files /dev/null and b/src/main/resources/Images/arrow 2.png differ diff --git a/src/main/resources/Images/arrow.png b/src/main/resources/Images/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..9d65c03b2a4d3710c674655f1a3201935735c9f5 Binary files /dev/null and b/src/main/resources/Images/arrow.png differ diff --git a/src/main/resources/Images/delete 2.png b/src/main/resources/Images/delete 2.png new file mode 100644 index 0000000000000000000000000000000000000000..b23937817cfa4976c74f73288a6c34451934f16b Binary files /dev/null and b/src/main/resources/Images/delete 2.png differ diff --git a/src/main/resources/Images/delete.png b/src/main/resources/Images/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..b23937817cfa4976c74f73288a6c34451934f16b Binary files /dev/null and b/src/main/resources/Images/delete.png differ diff --git a/src/main/resources/Images/edit 2.png b/src/main/resources/Images/edit 2.png new file mode 100644 index 0000000000000000000000000000000000000000..833b336008545736084b8b7178591740a5bd7ac7 Binary files /dev/null and b/src/main/resources/Images/edit 2.png differ diff --git a/src/main/resources/Images/edit.png b/src/main/resources/Images/edit.png new file mode 100644 index 0000000000000000000000000000000000000000..833b336008545736084b8b7178591740a5bd7ac7 Binary files /dev/null and b/src/main/resources/Images/edit.png differ diff --git a/src/main/resources/Images/pizzaslice.png b/src/main/resources/Images/pizzaslice.png index 6ab7c2818c2abe9a91e263d18c57b19ed7c66101..ad2aebbc8a93ef297a2a82229d385f655d9e88bc 100644 Binary files a/src/main/resources/Images/pizzaslice.png and b/src/main/resources/Images/pizzaslice.png differ diff --git a/src/main/resources/view/AddBudget.fxml b/src/main/resources/view/AddBudget.fxml new file mode 100644 index 0000000000000000000000000000000000000000..96e52a73c5c6b258612b7e8a231dd91f8eb5d5fb --- /dev/null +++ b/src/main/resources/view/AddBudget.fxml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.ComboBox?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.ColumnConstraints?> +<?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.RowConstraints?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Text?> + +<AnchorPane prefHeight="150.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.AddBudgetController"> + <children> + <GridPane prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" maxWidth="10.0" minWidth="0.0" prefWidth="0.0" /> + <ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="10.0" prefWidth="150.0" /> + <ColumnConstraints hgrow="SOMETIMES" maxWidth="180.0" minWidth="10.0" prefWidth="150.0" /> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + <ColumnConstraints hgrow="SOMETIMES" maxWidth="10.0" minWidth="10.0" prefWidth="0.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <VBox alignment="CENTER" GridPane.columnIndex="1" GridPane.valignment="CENTER"> + <children> + <Label text="Category/Title" /> + <ComboBox fx:id="categoryVariable" maxWidth="150.0" prefWidth="150.0" /> + </children> + </VBox> + <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="2"> + <children> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Amount" /> + <TextField fx:id="amountVariable" maxWidth="150.0" /> + </children> + </VBox> + <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="3"> + <children> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Description" /> + <TextField fx:id="descriptionVariable" /> + </children> + </VBox> + <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="15.0" GridPane.columnIndex="3" GridPane.rowIndex="1"> + <children> + <Button fx:id="cancelButton" mnemonicParsing="false" onAction="#closeButton" text="Cancel" /> + <Button fx:id="addButton" mnemonicParsing="false" onAction="#addBudget" text="Add New Budget" /> + </children> + </HBox> + </children> + </GridPane> + </children> +</AnchorPane> diff --git a/src/main/resources/view/AddExpense.fxml b/src/main/resources/view/AddExpense.fxml index 097992b0c7320fa41a777df6abb7036ab8274662..67cb0b9cd532b1ec998bcbec6a9ce26a79f60d13 100644 --- a/src/main/resources/view/AddExpense.fxml +++ b/src/main/resources/view/AddExpense.fxml @@ -3,55 +3,51 @@ <?import javafx.geometry.Insets?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.ComboBox?> +<?import javafx.scene.control.DialogPane?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.TextField?> <?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.RowConstraints?> -<GridPane hgap="10.0" vgap="10.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.SceneController"> - <columnConstraints> - <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> - <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> - <ColumnConstraints hgrow="SOMETIMES" maxWidth="95.0" minWidth="10.0" prefWidth="11.0" /> - <ColumnConstraints hgrow="SOMETIMES" maxWidth="189.0" minWidth="10.0" prefWidth="189.0" /> - </columnConstraints> - <rowConstraints> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> - </rowConstraints> - <padding> - <Insets bottom="10.0" left="10.0" top="20.0" /> - </padding> - <children> - <Label text="Date:" /> - <Label text="Amount:" GridPane.rowIndex="1" /> - <Label text="Description:" GridPane.rowIndex="2" /> - <Label text="Category" GridPane.rowIndex="3"> - <GridPane.margin> - <Insets /> - </GridPane.margin> - </Label> - <TextField promptText="Date" GridPane.columnIndex="1" GridPane.columnSpan="2" /> - <TextField promptText="Amount" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="1" /> - <TextField promptText="Description (optional)" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="2" /> - <ComboBox prefWidth="150.0" GridPane.columnIndex="1" GridPane.rowIndex="3"> - <GridPane.margin> - <Insets /> - </GridPane.margin> - </ComboBox> - <Button mnemonicParsing="false" onAction="#closeButton" text="Cancel" GridPane.columnIndex="3" GridPane.rowIndex="4"> - <GridPane.margin> - <Insets left="75.0" /> - </GridPane.margin> - </Button> - <Button mnemonicParsing="false" onAction="#closeButton" text="Button" GridPane.columnIndex="3" GridPane.rowIndex="4"> - <GridPane.margin> - <Insets left="130.0" /> - </GridPane.margin> - </Button> - </children> -</GridPane> +<DialogPane expanded="true" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.AddExpenseController"> + <content> + <GridPane> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <Label text="Date:" /> + <Label text="Amount:" GridPane.rowIndex="1" /> + <Label text="Description:" GridPane.rowIndex="2" /> + <Label text="Category" GridPane.rowIndex="3" /> + <Label text="Recurring" GridPane.rowIndex="4" /> + <TextField fx:id="dateField" promptText="1/1/23" GridPane.columnIndex="1" /> + <TextField fx:id="amountField" promptText="100" GridPane.columnIndex="1" GridPane.rowIndex="1" /> + <TextField fx:id="descriptionField" promptText="(optional)" GridPane.columnIndex="1" GridPane.rowIndex="2" /> + <ComboBox fx:id="categoryBox" prefWidth="150.0" promptText="Food" GridPane.columnIndex="1" GridPane.rowIndex="3" /> + <ComboBox fx:id="recurringBox" prefWidth="150.0" promptText="No" GridPane.columnIndex="1" GridPane.rowIndex="4" /> + <HBox alignment="BOTTOM_RIGHT" prefHeight="100.0" prefWidth="200.0" spacing="10.0" GridPane.columnIndex="1" GridPane.columnSpan="2" GridPane.rowIndex="5"> + <children> + <Button fx:id="cancelBtn" mnemonicParsing="false" onAction="#pressCancelBtn" prefHeight="25.0" prefWidth="60.0" text="Cancel" /> + <Button fx:id="okBtn" mnemonicParsing="false" onAction="#pressOkBtn" prefHeight="25.0" prefWidth="60.0" text="OK" /> + </children> + <GridPane.margin> + <Insets top="20.0" /> + </GridPane.margin> + </HBox> + </children> + </GridPane> + </content> +</DialogPane> diff --git a/src/main/resources/view/Budget.fxml b/src/main/resources/view/Budget.fxml new file mode 100644 index 0000000000000000000000000000000000000000..461014f8b2813ee9470742d01fcaef55932fa6b0 --- /dev/null +++ b/src/main/resources/view/Budget.fxml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.TableColumn?> +<?import javafx.scene.control.TableView?> +<?import javafx.scene.control.TextArea?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.ColumnConstraints?> +<?import javafx.scene.layout.FlowPane?> +<?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.RowConstraints?> +<?import javafx.scene.text.Font?> +<?import javafx.scene.text.Text?> + +<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.BudgetController"> + <children> + <ImageView fitHeight="468.0" fitWidth="600.0" pickOnBounds="true"> + <image> + <Image url="@../Images/backgroundMini.jpg" /> + </image> + </ImageView> + <GridPane prefHeight="468.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints maxHeight="397.0" minHeight="10.0" prefHeight="61.0" vgrow="SOMETIMES" /> + <RowConstraints maxHeight="397.0" minHeight="10.0" prefHeight="41.0" vgrow="SOMETIMES" /> + <RowConstraints maxHeight="397.0" minHeight="10.0" prefHeight="296.0" vgrow="SOMETIMES" /> + <RowConstraints maxHeight="152.0" minHeight="10.0" prefHeight="79.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <HBox alignment="TOP_CENTER" prefHeight="98.0" prefWidth="600.0" spacing="40.0" GridPane.rowIndex="3"> + <children> + <Button fx:id="addBudget" minHeight="60.0" minWidth="100.0" mnemonicParsing="false" onAction="#switchAddBudget" prefWidth="100.0" text="Add" /> + <Button fx:id="editBudget" minHeight="60.0" minWidth="100.0" mnemonicParsing="false" onAction="#switchAddBudget" prefWidth="100.0" text="Edit" /> + <Button fx:id="deleteBudget" minHeight="60.0" minWidth="100.0" mnemonicParsing="false" onAction="#deleteButton" prefWidth="100.0" text="Delete" /> + <Button minHeight="60.0" minWidth="100.0" mnemonicParsing="false" prefWidth="100.0" text="Save/Back" /> + </children> + </HBox> + <FlowPane alignment="CENTER" columnHalignment="CENTER" prefHeight="200.0" prefWidth="200.0" GridPane.halignment="CENTER" GridPane.rowIndex="2" GridPane.valignment="CENTER"> + <children> + <TableView fx:id="budgetTableView" prefHeight="260.0" prefWidth="540.0"> + <columns> + <TableColumn fx:id="categoryColumn" prefWidth="75.0" text="Category/Title" /> + <TableColumn fx:id="percentageColumn" prefWidth="75.0" text="Percentage" /> + <TableColumn fx:id="amountColumn" prefWidth="75.0" text="Amount" /> + <TableColumn fx:id="descriptionColumn" prefWidth="75.0" text="Description" /> + </columns> + <columnResizePolicy> + <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> + </columnResizePolicy> + </TableView> + </children> + </FlowPane> + <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0"> + <children> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Budget"> + <font> + <Font size="48.0" /> + </font> + </Text> + </children> + </HBox> + <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" GridPane.rowIndex="1"> + <children> + <TextArea fx:id="monthVariable" prefHeight="20.0" prefWidth="180.0" text="Month" /> + <TextArea fx:id="daysVariable" prefHeight="20.0" prefWidth="180.0" text="Days" /> + <TextArea fx:id="totalBudgetAmount" prefHeight="20.0" prefWidth="180.0" text="Amount" /> + </children> + </HBox> + </children> + </GridPane> + </children> +</AnchorPane> diff --git a/src/main/resources/view/Expenses.fxml b/src/main/resources/view/Expenses.fxml index 041a55504552a6d638ef7f7bc0d860e889029ec9..7985d6413c4f3ff58c6056a59b26752314f617be 100644 --- a/src/main/resources/view/Expenses.fxml +++ b/src/main/resources/view/Expenses.fxml @@ -19,7 +19,7 @@ <?import javafx.scene.text.Font?> <?import javafx.scene.text.Text?> -<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.SceneController"> +<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.ExpensesController"> <children> <ImageView fitHeight="400.0" fitWidth="600.0" pickOnBounds="true"> <image> @@ -29,7 +29,7 @@ <Cursor fx:constant="DEFAULT" /> </cursor> </ImageView> - <BorderPane prefHeight="400.0" prefWidth="593.0"> + <BorderPane prefHeight="400.0" prefWidth="600.0"> <top> <HBox BorderPane.alignment="CENTER"> <children> @@ -73,9 +73,30 @@ <children> <HBox alignment="BOTTOM_LEFT" prefWidth="410.0" spacing="5.0"> <children> - <Button fx:id="add" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#addExpense" text="Add" textAlignment="CENTER" /> - <Button fx:id="add1" alignment="TOP_CENTER" mnemonicParsing="false" text="Edit" textAlignment="CENTER" /> - <Button fx:id="add11" alignment="TOP_CENTER" mnemonicParsing="false" text="Delete" textAlignment="CENTER" /> + <Button fx:id="addBtn" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#handleAddButton" text="Add" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/add_image.png" /> + </image> + </ImageView> + </graphic></Button> + <Button fx:id="editBtn" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#handleEditButton" text="Edit" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/edit.png" /> + </image> + </ImageView> + </graphic></Button> + <Button fx:id="deleteBtn" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#handleDeleteBtn" text="Delete" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/delete.png" /> + </image> + </ImageView> + </graphic></Button> </children> <opaqueInsets> <Insets /> @@ -116,10 +137,11 @@ </HBox> <TableView fx:id="expenseTableView" prefHeight="260.0" prefWidth="485.0" GridPane.columnSpan="2" GridPane.rowIndex="1"> <columns> - <TableColumn fx:id="date" prefWidth="75.0" text="Date" /> - <TableColumn fx:id="amount" prefWidth="75.0" text="Amount" /> - <TableColumn fx:id="category" prefWidth="75.0" text="Category" /> - <TableColumn fx:id="description" prefWidth="75.0" text="Description" /> + <TableColumn fx:id="dateColumn" prefWidth="75.0" text="Date" /> + <TableColumn fx:id="amountColumn" prefWidth="75.0" text="Amount" /> + <TableColumn fx:id="categoryColumn" prefWidth="75.0" text="Category" /> + <TableColumn fx:id="descriptionColumn" prefWidth="75.0" text="Description" /> + <TableColumn fx:id="recurringColumn" prefWidth="75.0" text="Recurring" /> </columns> <columnResizePolicy> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> @@ -132,7 +154,7 @@ <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> </opaqueInsets> <left> - <Region prefHeight="357.0" prefWidth="25.0" BorderPane.alignment="CENTER" /> + <Region prefHeight="330.0" prefWidth="1.0" BorderPane.alignment="CENTER" /> </left> <right> <Region prefHeight="357.0" prefWidth="0.0" BorderPane.alignment="CENTER" /> diff --git a/src/main/resources/view/FirstMenu.fxml b/src/main/resources/view/FirstMenu.fxml index e8fe27a4d37df4c39247f7cf3741559d814495e8..94b6c19c15ed3da752c79b8ddb61f628b8edd7f5 100644 --- a/src/main/resources/view/FirstMenu.fxml +++ b/src/main/resources/view/FirstMenu.fxml @@ -26,7 +26,7 @@ <Font size="24.0" /> </font> </Button> - <Button layoutX="380.0" layoutY="212.0" mnemonicParsing="false" onAction="#underProgress" text="Old Budget"> + <Button layoutX="380.0" layoutY="212.0" mnemonicParsing="false" onAction="#switchMainMenu" text="Old Budget"> <font> <Font size="24.0" /> </font> diff --git a/src/main/resources/view/Income.fxml b/src/main/resources/view/Income.fxml index 4a4b9e7ba892ccfec2e1644f2ac01699bae7834d..090983dfc1b733b038c77c3a672954876a41a341 100644 --- a/src/main/resources/view/Income.fxml +++ b/src/main/resources/view/Income.fxml @@ -29,11 +29,11 @@ <Cursor fx:constant="DEFAULT" /> </cursor> </ImageView> - <BorderPane prefHeight="400.0" prefWidth="593.0"> + <BorderPane prefHeight="400.0" prefWidth="600.0"> <top> <HBox BorderPane.alignment="CENTER"> <children> - <Button cancelButton="true" mnemonicParsing="false" onAction="#switchStartMenu" text="Return "> + <Button mnemonicParsing="false" onAction="#switchStartMenu" text="Return "> <opaqueInsets> <Insets left="100.0" /> </opaqueInsets> @@ -42,7 +42,7 @@ </HBox.margin> </Button> <Region prefHeight="70.0" prefWidth="141.0" /> - <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Income" textAlignment="CENTER" translateX="30.0"> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Income" textAlignment="CENTER" wrappingWidth="174.6796875"> <HBox.margin> <Insets /> </HBox.margin> @@ -73,9 +73,33 @@ <children> <HBox alignment="BOTTOM_LEFT" prefWidth="410.0" spacing="5.0"> <children> - <Button fx:id="add" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#addIncome" text="Add" textAlignment="CENTER" /> - <Button fx:id="add1" alignment="TOP_CENTER" mnemonicParsing="false" text="Edit" textAlignment="CENTER" /> - <Button fx:id="add11" alignment="TOP_CENTER" mnemonicParsing="false" text="Delete" textAlignment="CENTER" /> + <Button fx:id="add" alignment="TOP_CENTER" mnemonicParsing="false" onAction="#addIncome" text="Add" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/add_image.png" /> + </image> + </ImageView> + </graphic> + </Button> + <Button alignment="TOP_CENTER" mnemonicParsing="false" text="Edit" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/edit.png" /> + </image> + </ImageView> + </graphic> + </Button> + <Button alignment="TOP_CENTER" mnemonicParsing="false" text="Delete" textAlignment="CENTER"> + <graphic> + <ImageView fitHeight="19.0" fitWidth="16.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../Images/delete.png" /> + </image> + </ImageView> + </graphic> + </Button> </children> <opaqueInsets> <Insets /> @@ -86,7 +110,7 @@ </HBox> <VBox alignment="BOTTOM_LEFT" prefHeight="200.0" prefWidth="100.0" spacing="5.0" GridPane.columnIndex="1"> <children> - <ComboBox fx:id="show" prefWidth="150.0" promptText="Show"> + <ComboBox fx:id="show" prefWidth="150.0" promptText="Show "> <opaqueInsets> <Insets /> </opaqueInsets> @@ -101,26 +125,29 @@ <Button mnemonicParsing="false" onAction="#switchOverview" text="Overview"> <HBox.margin> <Insets right="5.0" /> - </HBox.margin></Button> - <Button disable="true" mnemonicParsing="false" onAction="#switchIncome" text="Income" textFill="#4d1616" /> + </HBox.margin> + </Button> + <Button disable="true" mnemonicParsing="false" onAction="#switchIncome" text="Income" /> <Button mnemonicParsing="false" onAction="#switchExpenses" text="Expenses" /> <Button disable="true" mnemonicParsing="false" text="Savings" /> <Button mnemonicParsing="false" onAction="#switchExpenses" text="Next"> <HBox.margin> <Insets left="170.0" /> - </HBox.margin></Button> + </HBox.margin> + </Button> </children> <padding> <Insets top="10.0" /> </padding> </HBox> <TableView fx:id="expenseTableView" prefHeight="260.0" prefWidth="485.0" GridPane.columnSpan="2" GridPane.rowIndex="1"> - <columns> - <TableColumn fx:id="date" prefWidth="75.0" text="Date" /> - <TableColumn fx:id="amount" prefWidth="75.0" text="Amount" /> + <columns> + <TableColumn fx:id="date" prefWidth="75.0" text="Date" /> + <TableColumn fx:id="amount" prefWidth="75.0" text="Amount" /> <TableColumn fx:id="category" prefWidth="75.0" text="Category" /> <TableColumn fx:id="description" prefWidth="75.0" text="Description" /> - </columns> + <TableColumn fx:id="recurring" prefWidth="75.0" text="Recurring" /> + </columns> <columnResizePolicy> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> </columnResizePolicy> @@ -132,7 +159,7 @@ <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> </opaqueInsets> <left> - <Region prefHeight="357.0" prefWidth="25.0" BorderPane.alignment="CENTER" /> + <Region prefHeight="330.0" prefWidth="1.0" BorderPane.alignment="CENTER" /> </left> <right> <Region prefHeight="357.0" prefWidth="0.0" BorderPane.alignment="CENTER" /> diff --git a/src/main/resources/view/monthly_budget_overview.fxml b/src/main/resources/view/MainMenu 2.fxml similarity index 63% rename from src/main/resources/view/monthly_budget_overview.fxml rename to src/main/resources/view/MainMenu 2.fxml index 020e9f85a51411536cef53d3b4c99baad85d0551..109698ac7f27cdb85bb41ba23c4b5af84037a3f8 100644 --- a/src/main/resources/view/monthly_budget_overview.fxml +++ b/src/main/resources/view/MainMenu 2.fxml @@ -15,20 +15,24 @@ <?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.Region?> <?import javafx.scene.layout.RowConstraints?> +<?import javafx.scene.layout.StackPane?> +<?import javafx.scene.layout.VBox?> <?import javafx.scene.text.Font?> <?import javafx.scene.text.Text?> - -<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1"> +<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.MainMenuController"> <children> <ImageView fitHeight="400.0" fitWidth="600.0" pickOnBounds="true"> <cursor> <Cursor fx:constant="DEFAULT" /> </cursor> + <image> + <Image url="@../Images/backgroundMini.jpg" /> + </image> </ImageView> <BorderPane prefHeight="400.0" prefWidth="600.0" AnchorPane.topAnchor="0.0"> <center> - <GridPane gridLinesVisible="true" BorderPane.alignment="CENTER"> + <GridPane prefWidth="574.0" BorderPane.alignment="CENTER"> <columnConstraints> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> @@ -39,22 +43,37 @@ <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> </rowConstraints> <children> - <HBox prefHeight="68.0" prefWidth="574.0" GridPane.columnSpan="2"> + <VBox alignment="BOTTOM_RIGHT" GridPane.columnSpan="2"> <children> - <Region prefHeight="108.0" prefWidth="270.0" /> - <Label text="Label" /> - <Region prefHeight="108.0" prefWidth="100.0" /> - <DatePicker /> + <DatePicker fx:id="date" /> + <HBox alignment="BOTTOM_CENTER" prefHeight="28.0" prefWidth="574.0"> + <children> + <Label text="5000kr left" textAlignment="CENTER"> + <font> + <Font name="System Bold" size="12.0" /> + </font></Label> + </children> + </HBox> </children> - </HBox> - <AnchorPane GridPane.columnSpan="2" GridPane.rowIndex="1"> + </VBox> + <StackPane GridPane.columnSpan="2" GridPane.rowIndex="1"> <children> - <ProgressBar layoutX="9.0" layoutY="41.0" prefHeight="18.0" prefWidth="554.0" progress="0.37" /> + <ImageView fx:id="progressMarker" fitHeight="20.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true" rotate="-90.0" translateX="-150.0" translateY="25.0"> + <image> + <Image url="@../Images/arrow.png" /> + </image> + </ImageView> + <ProgressBar fx:id="progressbar" prefHeight="40.0" prefWidth="554.0" progress="0.72" translateY="-10.0" /> + <Label fx:id="today" text="Today" textAlignment="CENTER" translateX="-150.0" translateY="-2.0"> + <font> + <Font name="System Bold" size="12.0" /> + </font> + </Label> </children> - </AnchorPane> + </StackPane> <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="50.0" GridPane.columnSpan="2" GridPane.rowIndex="2"> <children> - <Button contentDisplay="TOP" mnemonicParsing="false" prefHeight="125.0" prefWidth="125.0" text="Food"> + <Button fx:id="foodButton" contentDisplay="TOP" mnemonicParsing="false" prefHeight="125.0" prefWidth="119.0" text="Food"> <graphic> <ImageView fitHeight="63.0" fitWidth="87.0" pickOnBounds="true"> <cursor> @@ -66,19 +85,19 @@ </ImageView> </graphic> </Button> - <Button contentDisplay="TOP" mnemonicParsing="false" prefHeight="125.0" prefWidth="125.0" text="Add expense"> + <Button fx:id="addExpenseButton" contentDisplay="TOP" mnemonicParsing="false" onAction="#switchExpenses" prefHeight="125.0" prefWidth="125.0" text="Add expense"> <graphic> <ImageView fitHeight="79.0" fitWidth="87.0" pickOnBounds="true"> <cursor> <Cursor fx:constant="DEFAULT" /> </cursor> <image> - <Image url="@../Images/add_expense.png" /> + <Image url="@../Images/add_image.png" /> </image> </ImageView> </graphic> </Button> - <Button contentDisplay="TOP" mnemonicParsing="false" prefHeight="125.0" prefWidth="125.0" text="Overview"> + <Button fx:id="overviewButton" contentDisplay="TOP" mnemonicParsing="false" onAction="#switchOverview" prefHeight="125.0" prefWidth="125.0" text="Overview"> <graphic> <ImageView fitHeight="63.0" fitWidth="87.0" pickOnBounds="true"> <cursor> @@ -91,12 +110,18 @@ </graphic> </Button> </children> + <opaqueInsets> + <Insets /> + </opaqueInsets> + <padding> + <Insets top="20.0" /> + </padding> </HBox> </children> </GridPane> </center> <bottom> - <Region prefHeight="8.0" prefWidth="600.0" BorderPane.alignment="CENTER" /> + <Region prefHeight="55.0" prefWidth="600.0" BorderPane.alignment="CENTER" /> </bottom> <left> <Region prefHeight="287.0" prefWidth="14.0" BorderPane.alignment="CENTER" /> @@ -105,9 +130,9 @@ <Region prefHeight="287.0" prefWidth="12.0" BorderPane.alignment="CENTER" /> </right> <top> - <HBox BorderPane.alignment="CENTER"> + <HBox prefHeight="51.0" prefWidth="600.0" BorderPane.alignment="CENTER"> <children> - <Button mnemonicParsing="false" onAction="#switchIncome" text="Return "> + <Button mnemonicParsing="false" text="Return "> <opaqueInsets> <Insets left="100.0" /> </opaqueInsets> diff --git a/src/main/resources/view/MainMenu.fxml b/src/main/resources/view/MainMenu.fxml new file mode 100644 index 0000000000000000000000000000000000000000..109698ac7f27cdb85bb41ba23c4b5af84037a3f8 --- /dev/null +++ b/src/main/resources/view/MainMenu.fxml @@ -0,0 +1,160 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.Cursor?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.DatePicker?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.ProgressBar?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.ColumnConstraints?> +<?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.Region?> +<?import javafx.scene.layout.RowConstraints?> +<?import javafx.scene.layout.StackPane?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Font?> +<?import javafx.scene.text.Text?> + +<AnchorPane xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="no.ntnu.idatt1002.demo.controller.MainMenuController"> + <children> + <ImageView fitHeight="400.0" fitWidth="600.0" pickOnBounds="true"> + <cursor> + <Cursor fx:constant="DEFAULT" /> + </cursor> + <image> + <Image url="@../Images/backgroundMini.jpg" /> + </image> + </ImageView> + <BorderPane prefHeight="400.0" prefWidth="600.0" AnchorPane.topAnchor="0.0"> + <center> + <GridPane prefWidth="574.0" BorderPane.alignment="CENTER"> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <VBox alignment="BOTTOM_RIGHT" GridPane.columnSpan="2"> + <children> + <DatePicker fx:id="date" /> + <HBox alignment="BOTTOM_CENTER" prefHeight="28.0" prefWidth="574.0"> + <children> + <Label text="5000kr left" textAlignment="CENTER"> + <font> + <Font name="System Bold" size="12.0" /> + </font></Label> + </children> + </HBox> + </children> + </VBox> + <StackPane GridPane.columnSpan="2" GridPane.rowIndex="1"> + <children> + <ImageView fx:id="progressMarker" fitHeight="20.0" fitWidth="25.0" pickOnBounds="true" preserveRatio="true" rotate="-90.0" translateX="-150.0" translateY="25.0"> + <image> + <Image url="@../Images/arrow.png" /> + </image> + </ImageView> + <ProgressBar fx:id="progressbar" prefHeight="40.0" prefWidth="554.0" progress="0.72" translateY="-10.0" /> + <Label fx:id="today" text="Today" textAlignment="CENTER" translateX="-150.0" translateY="-2.0"> + <font> + <Font name="System Bold" size="12.0" /> + </font> + </Label> + </children> + </StackPane> + <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="50.0" GridPane.columnSpan="2" GridPane.rowIndex="2"> + <children> + <Button fx:id="foodButton" contentDisplay="TOP" mnemonicParsing="false" prefHeight="125.0" prefWidth="119.0" text="Food"> + <graphic> + <ImageView fitHeight="63.0" fitWidth="87.0" pickOnBounds="true"> + <cursor> + <Cursor fx:constant="DEFAULT" /> + </cursor> + <image> + <Image url="@../Images/pizzaslice.png" /> + </image> + </ImageView> + </graphic> + </Button> + <Button fx:id="addExpenseButton" contentDisplay="TOP" mnemonicParsing="false" onAction="#switchExpenses" prefHeight="125.0" prefWidth="125.0" text="Add expense"> + <graphic> + <ImageView fitHeight="79.0" fitWidth="87.0" pickOnBounds="true"> + <cursor> + <Cursor fx:constant="DEFAULT" /> + </cursor> + <image> + <Image url="@../Images/add_image.png" /> + </image> + </ImageView> + </graphic> + </Button> + <Button fx:id="overviewButton" contentDisplay="TOP" mnemonicParsing="false" onAction="#switchOverview" prefHeight="125.0" prefWidth="125.0" text="Overview"> + <graphic> + <ImageView fitHeight="63.0" fitWidth="87.0" pickOnBounds="true"> + <cursor> + <Cursor fx:constant="DEFAULT" /> + </cursor> + <image> + <Image url="@../Images/overview_stonks.png" /> + </image> + </ImageView> + </graphic> + </Button> + </children> + <opaqueInsets> + <Insets /> + </opaqueInsets> + <padding> + <Insets top="20.0" /> + </padding> + </HBox> + </children> + </GridPane> + </center> + <bottom> + <Region prefHeight="55.0" prefWidth="600.0" BorderPane.alignment="CENTER" /> + </bottom> + <left> + <Region prefHeight="287.0" prefWidth="14.0" BorderPane.alignment="CENTER" /> + </left> + <right> + <Region prefHeight="287.0" prefWidth="12.0" BorderPane.alignment="CENTER" /> + </right> + <top> + <HBox prefHeight="51.0" prefWidth="600.0" BorderPane.alignment="CENTER"> + <children> + <Button mnemonicParsing="false" text="Return "> + <opaqueInsets> + <Insets left="100.0" /> + </opaqueInsets> + <HBox.margin> + <Insets left="10.0" top="10.0" /> + </HBox.margin> + </Button> + <Region prefHeight="70.0" prefWidth="103.0" /> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="BUDGET FEBRUARY" textAlignment="CENTER"> + <HBox.margin> + <Insets /> + </HBox.margin> + <font> + <Font size="30.0" /> + </font> + </Text> + </children> + <opaqueInsets> + <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> + </opaqueInsets> + </HBox> + </top> + </BorderPane> + </children> +</AnchorPane> diff --git a/src/main/resources/view/Overview.fxml b/src/main/resources/view/Overview.fxml index dc81039bbe9391dd63e3fc1afe7e469cb01cca37..4bc86e4cbfbe4e7c2322369bc1b7ad046db0f865 100644 --- a/src/main/resources/view/Overview.fxml +++ b/src/main/resources/view/Overview.fxml @@ -96,7 +96,7 @@ <Button mnemonicParsing="false" onAction="#switchIncome" text="Income" textFill="#4d1616" /> <Button mnemonicParsing="false" onAction="#switchExpenses" text="Expenses" /> <Button disable="true" mnemonicParsing="false" text="Savings" /> - <Button defaultButton="true" mnemonicParsing="false" onAction="#switchExpenses" text="Next"> + <Button defaultButton="true" mnemonicParsing="false" onAction="#switchMainMenu" text="Next"> <HBox.margin> <Insets left="170.0" /> </HBox.margin></Button> diff --git a/src/main/resources/view/deleteBudget.fxml b/src/main/resources/view/deleteBudget.fxml new file mode 100644 index 0000000000000000000000000000000000000000..21b63909cd168f35dd26b3803d214881afbb3c88 --- /dev/null +++ b/src/main/resources/view/deleteBudget.fxml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.ComboBox?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.ColumnConstraints?> +<?import javafx.scene.layout.GridPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.RowConstraints?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Text?> + +<AnchorPane prefHeight="150.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="view.DeleteBudget"> + <children> + <GridPane layoutX="23.0" layoutY="30.0" prefHeight="150.0" prefWidth="400.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> + <columnConstraints> + <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" /> + </columnConstraints> + <rowConstraints> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" /> + </rowConstraints> + <children> + <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0"> + <children> + <Text strokeType="OUTSIDE" strokeWidth="0.0" text="Delete Budget Item" /> + </children> + </VBox> + <HBox alignment="CENTER" GridPane.rowIndex="1"> + <children> + <ComboBox prefWidth="150.0" /> + </children> + </HBox> + <HBox alignment="CENTER" prefHeight="100.0" prefWidth="200.0" spacing="15.0" GridPane.rowIndex="2"> + <children> + <Button mnemonicParsing="false" text="Cancel" /> + <Button mnemonicParsing="false" text="Delete" /> + </children> + </HBox> + </children> + </GridPane> + </children> +</AnchorPane> diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudgetTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudgetTest.java new file mode 100644 index 0000000000000000000000000000000000000000..21e78490615680cfe43af5e716ca18acd6bdd1f9 --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/FileHandlingBudgetTest.java @@ -0,0 +1,77 @@ +package no.ntnu.idatt1002.demo.data.Budget; + +import no.ntnu.idatt1002.demo.data.Economics.ExpenseCategory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; + +import java.io.IOException; +import java.time.LocalDate; +import java.time.Month; + +import static org.junit.jupiter.api.Assertions.*; + + +import java.io.IOException; + +class FileHandlingBudgetTest { + BudgetItem foodItem; + BudgetItem bookItem; + BudgetItem clothesItem; + FileHandlingBudget fileHandlingBudget = new FileHandlingBudget(); + + + @Nested + @DisplayName("FileHandling budget with one BudgetItem does not throw exception") + class fileHandlingBudgetWithOneBudgetItemDoesNotThrowException{ + GeneralBudget generalBudget = new GeneralBudget(12, 1200); + String fileTitle = "oneBudgetItemTest"; + + @BeforeEach + void createGeneralBudget(){ + foodItem = new BudgetItem(500, "description", ExpenseCategory.FOOD); + generalBudget.addToBudgetBudgetItem(foodItem); + } + @Test + @DisplayName("Writing to file does not throw exception") + void writeGeneralBudgetToFileDoesNotThrowException() throws IOException { + assertDoesNotThrow(() -> fileHandlingBudget.writeGeneralBudgetToFile(fileTitle,generalBudget)); + } + + @Test + @DisplayName("Reading from file gives correct budget back") + void readingGeneralBudgetFromFileDoesNotThrowException()throws IOException{ + assertEquals(generalBudget,fileHandlingBudget.readGeneralBudgetFromFile(fileTitle)); + } + } + + @Nested + @DisplayName("FileHandling budget with multiple BudgetItems does not throw exception") + class FileHandlingBudgetWithMultipleBudgetItemsDoesNotThrowException{ + GeneralBudget generalBudget = new GeneralBudget(12, 1200); + String fileTitle = "multipleBudgetItem"; + @BeforeEach + void createGeneralBudget(){ + foodItem = new BudgetItem(500, "description", ExpenseCategory.FOOD); + bookItem = new BudgetItem(200, "anotherDescription", ExpenseCategory.BOOKS); + clothesItem = new BudgetItem(150, "anotheranotherdescription", ExpenseCategory.CLOTHES); + generalBudget.addToBudgetBudgetItem(foodItem); + generalBudget.addToBudgetBudgetItem(bookItem); + generalBudget.addToBudgetBudgetItem(clothesItem); + } + @Test + @DisplayName("Writing to file does not throw exception") + void writeGeneralBudgetToFileDoesNotThrowException() throws IOException { + assertDoesNotThrow(()->fileHandlingBudget.writeGeneralBudgetToFile(fileTitle,generalBudget)); + } + + @Test + @DisplayName("Reading from file gives correct budget back") + void readingGeneralBudgetFromFileDoesNotThrowException()throws IOException{ + assertEquals(generalBudget,fileHandlingBudget.readGeneralBudgetFromFile(fileTitle)); + } + } + +} diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java index 52b1a98e93749a625525ba06c4dccd68999109b3..d4ee06433f68d8e3b85eae037f72237ecb3c70b2 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Budget/GeneralBudgetTest.java @@ -30,8 +30,9 @@ class GeneralBudgetTest { void add_to_budget_throws_when_totalSum_is_over_maxAmount(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); + BudgetItem foodItem = new BudgetItem(1300, "Food", ExpenseCategory.FOOD); - assertThrows(IllegalArgumentException.class, () -> budget1.addToBudget(1300, "Food", ExpenseCategory.FOOD)); + assertThrows(IllegalArgumentException.class, () -> budget1.addToBudgetBudgetItem(foodItem)); } @Test @@ -39,9 +40,11 @@ class GeneralBudgetTest { void add_to_budget_throws_when_a_budget_with_same_category_already_exists(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - budget1.addToBudget(500, "Food", ExpenseCategory.FOOD); + BudgetItem foodItem = new BudgetItem(500, "Food", ExpenseCategory.FOOD); + budget1.addToBudgetBudgetItem(foodItem); + BudgetItem alsoFoodItem = new BudgetItem(200, "Food", ExpenseCategory.FOOD); - assertThrows(IllegalArgumentException.class, () -> budget1.addToBudget(200, "Food", ExpenseCategory.FOOD)); + assertThrows(IllegalArgumentException.class, () -> budget1.addToBudgetBudgetItem(alsoFoodItem)); } @Test @@ -49,8 +52,8 @@ class GeneralBudgetTest { void add_budget_to_generalBudget(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - BudgetItem item1 = new BudgetItem(500, "Food", ExpenseCategory.FOOD); - budget1.addToBudget(500, "Food", ExpenseCategory.FOOD); + BudgetItem foodItem = new BudgetItem(500, "Food", ExpenseCategory.FOOD); + budget1.addToBudgetBudgetItem(foodItem); assertEquals(1, list.size()); } @@ -60,9 +63,10 @@ class GeneralBudgetTest { void checks_if_the_list_contains_an_item_with_this_category_true(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - budget1.addToBudget(500, "Food", ExpenseCategory.FOOD); + BudgetItem foodItem = new BudgetItem(500, "Food", ExpenseCategory.FOOD); + budget1.addToBudgetBudgetItem(foodItem); - assertTrue(budget1.checksListOfItemsContainsBudgetItem(ExpenseCategory.FOOD)); + assertTrue(budget1.hasBudgetCategory(ExpenseCategory.FOOD)); } @Test @@ -70,9 +74,10 @@ class GeneralBudgetTest { void checks_if_the_list_contains_an_item_with_this_category_false(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - budget1.addToBudget(500, "Books", ExpenseCategory.BOOKS); + BudgetItem bookItem = new BudgetItem(500, "Books", ExpenseCategory.BOOKS); + budget1.addToBudgetBudgetItem(bookItem); - assertFalse(budget1.checksListOfItemsContainsBudgetItem(ExpenseCategory.FOOD)); + assertFalse(budget1.hasBudgetCategory(ExpenseCategory.FOOD)); } @Test @@ -80,8 +85,10 @@ class GeneralBudgetTest { void get_total_sum_of_all_budgetItems_in_the_budget(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - budget1.addToBudget(500, "Books", ExpenseCategory.BOOKS); - budget1.addToBudget(300, "Food", ExpenseCategory.FOOD); + BudgetItem bookItem = new BudgetItem(500, "Books", ExpenseCategory.BOOKS); + BudgetItem foodItem = new BudgetItem(300, "Food", ExpenseCategory.FOOD); + budget1.addToBudgetBudgetItem(bookItem); + budget1.addToBudgetBudgetItem(foodItem); assertEquals(800, budget1.totalSum()); } @@ -91,7 +98,8 @@ class GeneralBudgetTest { void delete_from_budget(){ List<BudgetItem> list = new ArrayList<>(); GeneralBudget budget1 = new GeneralBudget(12, list, 1200); - budget1.addToBudget(500, "Books", ExpenseCategory.BOOKS); + BudgetItem bookItem = new BudgetItem(500, "Books", ExpenseCategory.BOOKS); + budget1.addToBudgetBudgetItem(bookItem); budget1.deleteItemFromBudget(ExpenseCategory.BOOKS); assertTrue(list.isEmpty()); diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegisterTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegisterTest.java index 3f8c5564c7cf45960e2381aa2c909ab41272bd14..cdfd5f8c7af64cbbd9335c698f89c4320f1421ce 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegisterTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseRegisterTest.java @@ -5,6 +5,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import java.time.Month; +import java.time.YearMonth; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -18,7 +21,7 @@ class ExpenseRegisterTest { @Test @DisplayName("addItem method throws exception when it should") void addItemThrows() { - Expense expense = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); + Expense expense = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); expenseRegister.addItem(expense); assertThrows(IllegalArgumentException.class, () -> expenseRegister.addItem(expense)); } @@ -26,8 +29,8 @@ class ExpenseRegisterTest { @Test @DisplayName("addItem method does not throw exception when it should not") void addItemDoesNotThrow() { - Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); - Expense expense2 = new Expense("anotherDescription", 6.5f, true, ExpenseCategory.BOOKS, "02.03.23"); + Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); + Expense expense2 = new Expense("anotherDescription", 6.5f, true, ExpenseCategory.BOOKS, LocalDate.of(2023, Month.MARCH, 3)); assertDoesNotThrow(() -> expenseRegister.addItem(expense1)); assertDoesNotThrow(() -> expenseRegister.addItem(expense2)); } @@ -39,16 +42,16 @@ class ExpenseRegisterTest { @Test @DisplayName("removeItem does throw exception when it should") void removeItemDoesThrow(){ - Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); - Expense notExpense1 = new Expense("anotherDescription", 6.5f, true, ExpenseCategory.BOOKS, "02.03.23"); + Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); + Expense notExpense1 = new Expense("anotherDescription", 6.5f, true, ExpenseCategory.BOOKS, LocalDate.of(2023, Month.MARCH, 2)); expenseRegister.addItem(expense1); assertThrows(IllegalArgumentException.class, () -> expenseRegister.removeItem(notExpense1)); } @Test @DisplayName("removeItem method does not throw exception when it should not") void removeItemDoesNotThrow(){ - Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); - Expense expense1Copy = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); + Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); + Expense expense1Copy = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); expenseRegister.addItem(expense1); assertDoesNotThrow(() -> expenseRegister.removeItem(expense1Copy)); } @@ -61,30 +64,46 @@ class ExpenseRegisterTest { Expense expense1; Expense expense2; Expense expense3; + Expense expense4; @BeforeEach void addExpensesToRegister() { - expense1 = new Expense("description1", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); - expense2 = new Expense("description2", 62.4f, true, ExpenseCategory.FOOD, "01.02.21"); - expense3 = new Expense("description3", 9.81f, false, ExpenseCategory.CLOTHES, "05.07.23"); + expense1 = new Expense("description1", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); + expense2 = new Expense("description2", 62.4f, true, ExpenseCategory.FOOD, LocalDate.of(2021, Month.FEBRUARY, 1)); + expense3 = new Expense("description3", 9.81f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.JULY, 5)); + expense4 = new Expense("description3", 100.81f, false, ExpenseCategory.BOOKS, LocalDate.of(2023, Month.JULY, 12)); expenseRegister.addItem(expense1); expenseRegister.addItem(expense2); expenseRegister.addItem(expense3); + expenseRegister.addItem(expense4); } @Test @DisplayName("getTotalSum method gives correct amount") void getTotalSumCorrectAmount() { - double totalIncome = 59.9f + 62.4f + 9.81f; + double totalIncome = 59.9f + 62.4f + 9.81f + 100.81f; assertEquals(Math.round(expenseRegister.getTotalSum()), Math.round(totalIncome)); } @Test @DisplayName("getExpenseByCategory gives expected Expenses back") void getExpensesByCategoryGivesExpectedExpensesBack() { - List<Expense> expenseSalary = expenseRegister.getExpenseByCategory(ExpenseCategory.CLOTHES); - assertTrue(expenseSalary.contains(expense1) && expenseSalary.contains(expense3)); + ExpenseRegister expenseSalary = expenseRegister.getExpenseByCategory(ExpenseCategory.CLOTHES); + assertTrue(expenseSalary.getItems().contains(expense1)); + assertTrue(expenseSalary.getItems().contains(expense3)); + } + + @Test + @DisplayName("getExpenseByMonth gives expected Expenses back") + void getExpenseByMonthGivesCorrectExpenses() { + YearMonth yearMonth = YearMonth.of(2023, 7); + + ExpenseRegister expenseJuly = expenseRegister.getExpenseByMonth(yearMonth); + + assertTrue(expenseJuly.getItems().contains(expense4)); + assertTrue(expenseJuly.getItems().contains(expense3)); + assertFalse(expenseJuly.getItems().contains(expense2)); } } } diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseTest.java index 191c8513b06596eac7682e78dbb2ad21ee95f56c..60ea22080eb41a12791fbc0136c80a057d37fa64 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/ExpenseTest.java @@ -3,6 +3,9 @@ package no.ntnu.idatt1002.demo.data.Economics; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import java.time.Month; + import static org.junit.jupiter.api.Assertions.*; class ExpenseTest { @@ -10,14 +13,14 @@ class ExpenseTest { @Test @DisplayName("The Expense constructor throws exceptions when it should.") void constructorThrows(){ - assertThrows(IllegalArgumentException.class, () -> new Expense("description", 8.5f, false, null, "03.03.23")); - assertThrows(IllegalArgumentException.class, () -> new Expense("description", -10.0f, false, ExpenseCategory.BOOKS, "03.03.23")); + assertThrows(IllegalArgumentException.class, () -> new Expense("description", 8.5f, false, null, LocalDate.of(2023, Month.MARCH, 3))); + assertThrows(IllegalArgumentException.class, () -> new Expense("description", -10.0f, false, ExpenseCategory.BOOKS, LocalDate.of(2023, Month.MARCH, 3))); } @Test @DisplayName("The Expense constructor does not throw exceptions when it should not.") void constructorDoesThrow() { - assertDoesNotThrow(() -> new Expense("description", 59.9f, false, ExpenseCategory.BOOKS, "03.03.23")); + assertDoesNotThrow(() -> new Expense("description", 59.9f, false, ExpenseCategory.BOOKS, LocalDate.of(2023, Month.MARCH, 3))); } } \ No newline at end of file diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/FileHandlingTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/FileHandlingTest.java index 59ffe36701caa1eee0832678c4b41a3a16b43b8f..70dce32b8ffa47b20831c2108f00e576dc3035d2 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/FileHandlingTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/FileHandlingTest.java @@ -3,12 +3,35 @@ package no.ntnu.idatt1002.demo.data.Economics; import org.junit.jupiter.api.*; import java.io.IOException; +import java.time.LocalDate; +import java.time.Month; + import static org.junit.jupiter.api.Assertions.*; class FileHandlingTest { FileHandling fileHandling = new FileHandling(); ExpenseRegister expenseRegister = new ExpenseRegister(); IncomeRegister incomeRegister = new IncomeRegister(); + + @Nested + @DisplayName("Test isEmpty method") + class testIsEmpty{ + @Test + @DisplayName("isEmpty returns true if a file is empty") + void isEmptyReturnsTrueIfAFileIsEmpty() throws IOException { + fileHandling.writeItemRegisterToFile(incomeRegister, "incomeRegisterTest"); + assertTrue(fileHandling.isEmpty("incomeRegisterTest")); + } + + @Test + @DisplayName("isEmpty returns false if a file is not empty") + void isEmptyReturnsFalseIfFileIsNotEmpty() throws IOException { + Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); + incomeRegister.addItem(income1); + fileHandling.writeItemRegisterToFile(incomeRegister, "incomeRegisterTest"); + assertFalse(fileHandling.isEmpty("incomeRegisterTest")); + } + } @Nested @DisplayName("FileHandling IncomeRegister to file") class fileHandlingIncomeRegisterToFile{ @@ -18,7 +41,7 @@ class FileHandlingTest { class fileHandlingIncomeRegisterWithIncomeThatHasDescription{ @BeforeEach void addIncomeToIncomeRegister(){ - Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, "03.03.23"); + Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); incomeRegister.addItem(income1); } @Test @@ -38,7 +61,7 @@ class FileHandlingTest { class fileHandlingIncomeRegisterWithIncomeThatDoesNotHaveDescription{ @BeforeEach void addIncomeToIncomeRegister(){ - Income income1 = new Income(59.9f, false, IncomeCategory.GIFT, "03.03.23"); + Income income1 = new Income(59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); incomeRegister.addItem(income1); } @Test @@ -58,9 +81,9 @@ class FileHandlingTest { class fileHandlingIncomeRegisterWithMultipleIncome{ @BeforeEach void addIncomeToIncomeRegister(){ - Income income1 = new Income(59.9f, false, IncomeCategory.GIFT, "03.03.23"); - Income income2 = new Income("description2", 62.4f, true, IncomeCategory.GIFT, "01.02.21"); - Income income3 = new Income("description3", 9.81f, false, IncomeCategory.SALARY, "05.07.23"); + Income income1 = new Income(59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); + Income income2 = new Income("description2", 62.4f, true, IncomeCategory.GIFT, LocalDate.of(2021, Month.FEBRUARY, 1)); + Income income3 = new Income("description3", 9.81f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.JULY, 5)); incomeRegister.addItem(income1); incomeRegister.addItem(income2); incomeRegister.addItem(income3); @@ -87,7 +110,7 @@ class FileHandlingTest { class fileHandlingExpenseRegisterWithExpenseThatHasDescription{ @BeforeEach void addExpenseToExpenseRegister(){ - Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); + Expense expense1 = new Expense("description", 59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); expenseRegister.addItem(expense1); } @Test @@ -107,7 +130,7 @@ class FileHandlingTest { class fileHandlingExpenseRegisterWithExpenseThatDoesNotHaveDescription{ @BeforeEach void addExpenseToExpenseRegister(){ - Expense expense1 = new Expense(59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); + Expense expense1 = new Expense(59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); expenseRegister.addItem(expense1); } @Test @@ -127,9 +150,9 @@ class FileHandlingTest { class fileHandlingExpenseRegisterWithMultipleExpensen{ @BeforeEach void addExpenseToExpenseRegister(){ - Expense expense1 = new Expense(59.9f, false, ExpenseCategory.CLOTHES, "03.03.23"); - Expense expense2 = new Expense("description2", 62.4f, true, ExpenseCategory.FOOD, "01.02.21"); - Expense expense3 = new Expense("description3", 9.81f, false, ExpenseCategory.CLOTHES, "05.07.23"); + Expense expense1 = new Expense(59.9f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.MARCH, 3)); + Expense expense2 = new Expense("description2", 62.4f, true, ExpenseCategory.FOOD, LocalDate.of(2021, Month.FEBRUARY, 1)); + Expense expense3 = new Expense("description3", 9.81f, false, ExpenseCategory.CLOTHES, LocalDate.of(2023, Month.JULY, 5)); expenseRegister.addItem(expense1); expenseRegister.addItem(expense2); diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegisterTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegisterTest.java index 64d18f519505a3b7c6f4f99c9d7bca187088741b..83da1027f6fd4e0225673bc6df3cc25f392b838a 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegisterTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeRegisterTest.java @@ -5,6 +5,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import java.time.Month; +import java.time.YearMonth; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -18,7 +21,7 @@ public class IncomeRegisterTest { @Test @DisplayName("addItem method throws exception when it should") void addItemThrows() { - Income income = new Income("description", 59.9f, false, IncomeCategory.SALARY, "03.03.23"); + Income income = new Income("description", 59.9f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 3)); incomeRegister.addItem(income); assertThrows(IllegalArgumentException.class, () -> incomeRegister.addItem(income)); } @@ -26,8 +29,8 @@ public class IncomeRegisterTest { @Test @DisplayName("addItem method does not throw exception when it should not") void addItemDoesNotThrow() { - Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, "03.03.23"); - Income income2 = new Income("anotherDescription", 6.5f, true, IncomeCategory.SALARY, "02.03.23"); + Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); + Income income2 = new Income("anotherDescription", 6.5f, true, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 2)); assertDoesNotThrow(() -> incomeRegister.addItem(income1)); assertDoesNotThrow(() -> incomeRegister.addItem(income2)); } @@ -39,16 +42,16 @@ public class IncomeRegisterTest { @Test @DisplayName("removeItem does throw exception when it should") void removeItemDoesThrow(){ - Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, "03.03.23"); - Income notIncome1 = new Income("anotherDescription", 6.5f, true, IncomeCategory.SALARY, "02.03.23"); + Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 3)); + Income notIncome1 = new Income("anotherDescription", 6.5f, true, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 2)); incomeRegister.addItem(income1); assertThrows(IllegalArgumentException.class, () -> incomeRegister.removeItem(notIncome1)); } @Test @DisplayName("removeItem method does not throw exception when it should not") void removeItemDoesNotThrow(){ - Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, "03.03.23"); - Income income1Copy = new Income("description", 59.9f, false, IncomeCategory.GIFT, "03.03.23"); + Income income1 = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 2)); + Income income1Copy = new Income("description", 59.9f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.MARCH, 2)); incomeRegister.addItem(income1); assertDoesNotThrow(() -> incomeRegister.removeItem(income1Copy)); } @@ -60,29 +63,45 @@ public class IncomeRegisterTest { Income income1; Income income2; Income income3; + Income income4; @BeforeEach void addIncomeToRegister() { - income1 = new Income("description1", 59.9f, false, IncomeCategory.SALARY, "03.03.23"); - income2 = new Income("description2", 62.4f, true, IncomeCategory.GIFT, "01.02.21"); - income3 = new Income("description3", 9.81f, false, IncomeCategory.SALARY, "05.07.23"); + income1 = new Income("description1", 59.9f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 3)); + income2 = new Income("description2", 62.4f, true, IncomeCategory.GIFT,LocalDate.of(2021, Month.FEBRUARY, 1)); + income3 = new Income("description3", 9.81f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.JULY, 5)); + income4 = new Income("description3", 100.81f, false, IncomeCategory.GIFT, LocalDate.of(2023, Month.JULY, 12)); incomeRegister.addItem(income1); incomeRegister.addItem(income2); incomeRegister.addItem(income3); + incomeRegister.addItem(income4); } @Test @DisplayName("getTotalSum method gives correct amount") void getTotalSumCorrectAmount() { - double totalIncome = 59.9f + 62.4f + 9.81f; + double totalIncome = 59.9f + 62.4f + 9.81f + 100.81f; assertEquals(Math.round(incomeRegister.getTotalSum()), Math.round(totalIncome)); } @Test @DisplayName("getItemsByCategory gives expected Income back") void getIncomeByCategoryGivesCorrectIncome() { - List<Income> incomeSalary = incomeRegister.getIncomeByCategory(IncomeCategory.SALARY); - assertTrue(incomeSalary.contains(income1) && incomeSalary.contains(income3)); + IncomeRegister incomeSalary = incomeRegister.getIncomeByCategory(IncomeCategory.SALARY); + assertTrue(incomeSalary.getItems().contains(income1)); + assertTrue(incomeSalary.getItems().contains(income3)); + assertFalse(incomeSalary.getItems().contains(income4)); + } + + @Test + @DisplayName("getItemsByMonth gives expected Income back") + void getIncomeByMonthGivesCorrectIncomes() { + YearMonth yearMonth = YearMonth.of(2023, 7); + + IncomeRegister incomeJuly = incomeRegister.getIncomeByMonth(yearMonth); + assertTrue(incomeJuly.getItems().contains(income4)); + assertTrue(incomeJuly.getItems().contains(income3)); + assertFalse(incomeJuly.getItems().contains(income2)); } } } diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeTest.java index 69302606c5bebbf279efd8c395e1d4e887ec8fcd..17cf1fb98b50adfc6277d4fcfe4fb1b1074f8055 100644 --- a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeTest.java +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/IncomeTest.java @@ -1,10 +1,14 @@ package no.ntnu.idatt1002.demo.data.Economics; +import javafx.util.converter.LocalDateStringConverter; import no.ntnu.idatt1002.demo.data.Economics.Income; import no.ntnu.idatt1002.demo.data.Economics.IncomeCategory; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import java.time.LocalDate; +import java.time.Month; + import static org.junit.jupiter.api.Assertions.*; class IncomeTest { @@ -12,14 +16,14 @@ class IncomeTest { @Test @DisplayName("The Income constructor throws exceptions when it should.") void constructorThrows(){ - assertThrows(IllegalArgumentException.class, () -> new Income("description", 8.5f, false, null, "03.03.23")); - assertThrows(IllegalArgumentException.class, () -> new Income("description", -10.0f, false, IncomeCategory.SALARY, "03.03.23")); + assertThrows(IllegalArgumentException.class, () -> new Income("description", 8.5f, false, null, LocalDate.of(2023, Month.MARCH, 3))); + assertThrows(IllegalArgumentException.class, () -> new Income("description", -10.0f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 3))); }; @Test @DisplayName("The Income constructor does not throw exceptions when it should not.") void constructorDoesThrow() { - assertDoesNotThrow(() -> new Income("description", 59.9f, false, IncomeCategory.SALARY, "03.03.23")); + assertDoesNotThrow(() -> new Income("description", 59.9f, false, IncomeCategory.SALARY, LocalDate.of(2023, Month.MARCH, 3))); } } diff --git a/src/test/java/no/ntnu/idatt1002/demo/data/Economics/OverviewTest.java b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/OverviewTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9f7bb5711fc9487ac9b615c8a5667f08e50939ca --- /dev/null +++ b/src/test/java/no/ntnu/idatt1002/demo/data/Economics/OverviewTest.java @@ -0,0 +1,6 @@ +package no.ntnu.idatt1002.demo.data.Economics; + +public class OverviewTest { + + +}