diff --git a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java index bbe7cea..c644865 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java @@ -22,6 +22,7 @@ import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; import javafx.stage.Stage; @@ -87,7 +88,7 @@ public class CropDetailController { private ListView pests_listView; @FXML - void addTask() throws IOException { + void addTask() throws IOException, HardinessZoneNotSetException { createTaskDialog(true, null); } @@ -136,7 +137,7 @@ public class CropDetailController { if (plant.image() != null) { imageView.setImage(plant.image()); } - area_label.setText(""); + area_label.setText(String.valueOf(crop.getArea())); location_label.setText(""); setTaskListProperty(crop); @@ -205,22 +206,28 @@ public class CropDetailController { } private HBox createTaskHBox(Task task) { - HBox hBox = new HBox(); + HBox hBox = new HBox(10); Label taskName = new Label(task.getName()+": "); + taskName.setMinWidth(100); + taskName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); taskName.setStyle("-fx-font-weight: bold"); Label taskDescription = new Label(task.getDescription()); taskDescription.setWrapText(true); - taskDescription.setMaxWidth(2000); - HBox.setHgrow(taskDescription, Priority.ALWAYS); + taskDescription.setMaxSize(600, Double.MAX_VALUE); + Pane puffer = new Pane(); + HBox.setHgrow(puffer, Priority.ALWAYS); + Button edit = new Button(); Button delete = new Button(); + HBox.setHgrow(edit, Priority.NEVER); + HBox.setHgrow(delete, Priority.NEVER); setIconToButton(edit, "editIcon.png"); setIconToButton(delete, "deleteIcon.png"); edit.setOnAction(getEditTaskEvent(task)); delete.setOnAction(deleteTask(task)); - hBox.getChildren().addAll(taskName, taskDescription, edit, delete); + hBox.getChildren().addAll(taskName, taskDescription, puffer, edit, delete); return hBox; } @@ -229,12 +236,15 @@ public class CropDetailController { label.setStyle("-fx-font-weight: bold"); HBox hBox = new HBox(); hBox.fillHeightProperty(); - Label label1 = new Label(pest.description()); - label1.setAlignment(Pos.TOP_LEFT); - label1.setWrapText(true); - label1.setMaxWidth(600); + Label description = new Label(pest.description()); + description.setAlignment(Pos.TOP_LEFT); + description.setWrapText(true); + description.setMaxWidth(600); + Pane puffer = new Pane(); + HBox.setHgrow(puffer, Priority.ALWAYS); Button button = new Button("Get Counter Measures"); - hBox.getChildren().addAll(label, label1, button); + HBox.setHgrow(button, Priority.NEVER); + hBox.getChildren().addAll(label, description, puffer, button); return hBox; } @@ -255,7 +265,7 @@ public class CropDetailController { return (event) -> { try { createTaskDialog(false, task); - } catch (IOException e) { + } catch (IOException | HardinessZoneNotSetException e) { e.printStackTrace(); } }; @@ -267,7 +277,7 @@ public class CropDetailController { }; } - private void createTaskDialog(boolean newTask, Task givenTask) throws IOException { + private void createTaskDialog(boolean newTask, Task givenTask) throws IOException, HardinessZoneNotSetException { Dialog dialog = new Dialog<>(); dialog.setTitle("Set Task"); dialog.setHeaderText("Add/Edit Task:"); @@ -289,7 +299,7 @@ public class CropDetailController { if (!newTask) { controller.setTaskValue(givenTask); } - dialog.setResultConverter(button -> button.equals(saveTask) ? controller.returnResult() : null); + dialog.setResultConverter(button -> button.equals(saveTask) ? controller.returnResult(this.crop) : null); dialog.showAndWait() .ifPresent(task -> { @@ -334,8 +344,11 @@ public class CropDetailController { //ToDo method to set location location_label.setText(string); } else { - System.out.println(string); - //ToDo method to set area of crop in garden + try { + garden.updateCrop(this.crop.withArea(Double.parseDouble(string))); + } catch (IOException e) { + e.printStackTrace(); + } area_label.setText(string); } }); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/HelloController.java b/src/main/java/ch/zhaw/gartenverwaltung/HelloController.java deleted file mode 100644 index 7e952ac..0000000 --- a/src/main/java/ch/zhaw/gartenverwaltung/HelloController.java +++ /dev/null @@ -1,14 +0,0 @@ -package ch.zhaw.gartenverwaltung; - -import javafx.fxml.FXML; -import javafx.scene.control.Label; - -public class HelloController { - @FXML - private Label welcomeText; - - @FXML - protected void onHelloButtonClick() { - welcomeText.setText("Welcome to JavaFX Application!"); - } -} \ No newline at end of file diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java index b6270ca..34cf1a7 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java @@ -51,7 +51,6 @@ public class MyGardenController { @AfterInject @SuppressWarnings("unused") public void init() { - System.out.println("once"); setIconToButton(addPlant_button, "addIcon.png"); myGarden_listView.itemsProperty().bind(garden.getPlantedCrops()); setCellFactory(); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java index e895480..f73feb2 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java @@ -9,11 +9,14 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Task; +import javafx.beans.property.ListProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.collections.FXCollections; import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.control.ListCell; -import javafx.scene.control.ListView; +import javafx.scene.control.*; +import javafx.scene.layout.HBox; import javafx.scene.layout.Pane; +import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import java.io.IOException; @@ -24,6 +27,7 @@ import java.util.logging.Logger; public class MyScheduleController { private static final Logger LOG = Logger.getLogger(MyScheduleController.class.getName()); + private final ListProperty> taskListProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); private Crop selectedCrop = null; @@ -35,46 +39,7 @@ public class MyScheduleController { private PlantList plantList; @FXML - private Label day1_label; - - @FXML - private Pane day1_pane; - - @FXML - private Label day2_label; - - @FXML - private Pane day2_pane; - - @FXML - private Label day3_label; - - @FXML - private Pane day3_pane; - - @FXML - private Label day4_label; - - @FXML - private Pane day4_pane; - - @FXML - private Label day5_label; - - @FXML - private Pane day5_pane; - - @FXML - private Label day6_label; - - @FXML - private Pane day6_pane; - - @FXML - private Label day7_label; - - @FXML - private Pane day7_pane; + private ListView> week_listView; @FXML private Label information_label; @@ -85,10 +50,11 @@ public class MyScheduleController { @AfterInject @SuppressWarnings("unused") public void init() { - setCellFactoryListView(); + setCellFactoryCropListView(); + setCellFactoryTaskListView(); scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops()); + week_listView.itemsProperty().bind(taskListProperty); lookForSelectedListEntries(); - setDayLabels(); information_label.setText(""); try { loadTaskList(); @@ -108,18 +74,7 @@ public class MyScheduleController { }); } - private void setDayLabels() { - LocalDate today = LocalDate.now(); - day1_label.setText(today.getDayOfWeek().toString()); - day2_label.setText(today.plusDays(1).getDayOfWeek().toString()); - day3_label.setText(today.plusDays(2).getDayOfWeek().toString()); - day4_label.setText(today.plusDays(3).getDayOfWeek().toString()); - day5_label.setText(today.plusDays(4).getDayOfWeek().toString()); - day6_label.setText(today.plusDays(5).getDayOfWeek().toString()); - day7_label.setText(today.plusDays(6).getDayOfWeek().toString()); - } - - private void setCellFactoryListView() { + private void setCellFactoryCropListView() { scheduledPlants_listview.setCellFactory(param -> new ListCell<>() { @Override protected void updateItem(Crop crop, boolean empty) { @@ -141,6 +96,23 @@ public class MyScheduleController { }); } + private void setCellFactoryTaskListView() { + week_listView.setCellFactory(param -> new ListCell<>() { + @Override + protected void updateItem(List taskList, boolean empty) { + super.updateItem(taskList, empty); + + if (empty || taskList == null) { + setGraphic(null); + setText(null); + } else { + setText(""); + setGraphic(weekTaskVBox(taskList, this.getIndex())); + } + } + }); + } + private void loadTaskList() throws IOException { List> taskLists; if (selectedCrop != null) { @@ -148,25 +120,66 @@ public class MyScheduleController { } else { taskLists = gardenSchedule.getTasksUpcomingWeek(); } - if (!taskLists.isEmpty()) { - viewTaskListOfDay(day1_pane, taskLists.get(0)); - viewTaskListOfDay(day2_pane, taskLists.get(1)); - viewTaskListOfDay(day3_pane, taskLists.get(2)); - viewTaskListOfDay(day4_pane, taskLists.get(3)); - viewTaskListOfDay(day5_pane, taskLists.get(4)); - viewTaskListOfDay(day6_pane, taskLists.get(5)); - viewTaskListOfDay(day7_pane, taskLists.get(6)); - } + taskListProperty.clear(); + taskListProperty.addAll(taskLists); } - private void viewTaskListOfDay(Pane pane, List tasks) { - //ToDo update pane with task list - VBox vBox = new VBox(); + private VBox weekTaskVBox(List tasks, int dayIndex) { + VBox vBox = new VBox(10); + LocalDate today = LocalDate.now(); + Label weekDay = new Label(today.plusDays(dayIndex).getDayOfWeek().toString()); + weekDay.setStyle("-fx-font-weight: bold; -fx-underline: true"); + vBox.getChildren().add(weekDay); for (Task task : tasks) { - Label label = new Label(task.getDescription()); - vBox.getChildren().add(label); + HBox hBox = new HBox(10); + Label taskName = new Label(task.getName() + ":"); + taskName.setStyle("-fx-font-weight: bold"); + taskName.setMinWidth(100); + taskName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); + hBox.getChildren().addAll(taskName); + + HBox hBoxDescription = new HBox(); + Label taskDescription = new Label(task.getDescription()); + taskDescription.setWrapText(true); + taskDescription.setMaxSize(600, Double.MAX_VALUE); + Pane puffer = new Pane(); + HBox.setHgrow(puffer, Priority.ALWAYS); + CheckBox checkBox = new CheckBox("Task completed?"); + checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> { + if (newValue) { + showConfirmation(task, checkBox); + } + }); + HBox.setHgrow(checkBox, Priority.NEVER); + hBoxDescription.getChildren().addAll(taskDescription, puffer, checkBox); + vBox.getChildren().addAll(hBox, hBoxDescription); } - pane.getChildren().add(vBox); + return vBox; + } + + /** + * Alert to confirm that task has been completed. + * @param task {@link Task} which is selected + */ + private void showConfirmation(Task task, CheckBox checkBox) { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("Task Completed?"); + alert.setHeaderText("Are you sure you have completed this task?"); + alert.setContentText("Confirming that you have completed the task will remove it from the schedule."); + + alert.showAndWait() + .ifPresent(buttonType -> { + if (buttonType == ButtonType.OK) { + task.done(); + try { + loadTaskList(); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + checkBox.setSelected(false); + } + }); } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java index 5961c5f..2acee0d 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java @@ -233,11 +233,11 @@ public class PlantsController { RadioButton radioButton = new RadioButton(season.getName()); radioButton.setToggleGroup(seasonGroup); radioButton.setPadding(new Insets(0, 0, 10, 0)); - if (season.equals(Seasons.AllSEASONS)) { + if (season.equals(Seasons.ALLSEASONS)) { radioButton.setSelected(true); } radioButton.selectedProperty().addListener((observable, oldValue, newValue) -> { - if (season.equals(Seasons.AllSEASONS)) { + if (season.equals(Seasons.ALLSEASONS)) { fillPlantListWithHardinessZone(); } else { try { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/TaskFormularController.java b/src/main/java/ch/zhaw/gartenverwaltung/TaskFormularController.java index 936bf09..b4bb93b 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/TaskFormularController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/TaskFormularController.java @@ -1,23 +1,35 @@ package ch.zhaw.gartenverwaltung; +import ch.zhaw.gartenverwaltung.bootstrap.AfterInject; +import ch.zhaw.gartenverwaltung.bootstrap.Inject; +import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.models.Garden; +import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.types.Crop; +import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Task; -import javafx.beans.binding.Binding; -import javafx.beans.binding.Bindings; -import javafx.beans.binding.BooleanBinding; -import javafx.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.*; import javafx.util.Callback; +import java.io.IOException; import java.net.URL; import java.time.LocalDate; import java.util.ResourceBundle; public class TaskFormularController implements Initializable { private Crop crop; + private Plant plant; + private Task task = null; + + @Inject + private GardenSchedule gardenSchedule; + @Inject + private Garden garden; + @Inject + private PlantList plantList; @FXML private TextArea description_area; @@ -34,19 +46,28 @@ public class TaskFormularController implements Initializable { @FXML private TextField taskName_field; + @AfterInject + @SuppressWarnings("unused") - public Task returnResult() { + public Task returnResult(Crop crop) { + int interval = 0; + if (!(interval_field.getText().isEmpty() || interval_field.getText().equals(""))) { + interval = Integer.parseInt(interval_field.getText()); + } Task task = new Task(taskName_field.getText(), description_area.getText(), start_datePicker.getValue(), end_datePicker.getValue(), - Integer.parseInt(interval_field.getText()), crop.getCropId().get()); + interval, crop.getCropId().get()); + if (this.task != null) return this.task.updateTask(task); return task; } - public void setCorp(Crop crop) { + public void setCorp(Crop crop) throws HardinessZoneNotSetException, IOException { this.crop = crop; + this.plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(); } public void setTaskValue(Task task) { + this.task = task; taskName_field.setText(task.getName()); description_area.setText(task.getDescription()); start_datePicker.setValue(task.getStartDate()); @@ -69,7 +90,7 @@ public class TaskFormularController implements Initializable { setDisable(true); setStyle("-fx-background-color: #ffc0cb;"); - if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0) { + if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0 && item.compareTo(crop.getStartDate().plusDays(plant.timeToHarvest(0))) < 0) { setDisable(false); setStyle("-fx-background-color: #32CD32;"); } @@ -93,7 +114,7 @@ public class TaskFormularController implements Initializable { setDisable(true); setStyle("-fx-background-color: #ffc0cb;"); - if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0) { + if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0 && item.compareTo(crop.getStartDate().plusDays(plant.timeToHarvest(0))) < 0) { setDisable(false); setStyle("-fx-background-color: #32CD32;"); } @@ -114,12 +135,8 @@ public class TaskFormularController implements Initializable { }); button.disableProperty().bind(start_datePicker.valueProperty().isNull() - .or(end_datePicker.valueProperty().isNull()) .or(taskName_field.textProperty().isEmpty()) - .or(description_area.textProperty().isEmpty()) - .or(interval_field.textProperty().isEmpty())); - - + .or(description_area.textProperty().isEmpty())); } @Override diff --git a/src/main/java/ch/zhaw/gartenverwaltung/TextFieldFormularController.java b/src/main/java/ch/zhaw/gartenverwaltung/TextFieldFormularController.java index a53c240..97742d9 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/TextFieldFormularController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/TextFieldFormularController.java @@ -27,6 +27,15 @@ public class TextFieldFormularController { } public void initSaveButton(Button button) { + text_area.textProperty().addListener((observable, oldValue, newValue) -> { + if (newValue.matches("\\d*\\.?\\d*")) { + text_area.setText(newValue); + } else { + text_area.setText(oldValue); + } + }); + button.disableProperty().bind(text_area.textProperty().isEmpty()); } + } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AfterInject.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AfterInject.java index 72a88fd..23772bd 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AfterInject.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AfterInject.java @@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotates a method to be executed after all dependencies annotates with {@link Inject} + * Annotates a method to be executed after all dependencies annotated with {@link Inject} * have been injected. */ @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java index 44cea0d..f461714 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/AppLoader.java @@ -18,6 +18,10 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; +/** + * Class responsible for bootstrapping the application wide dependencies + * and injecting them into JavaFX Controllers. + */ public class AppLoader { /** * Caching the panes @@ -27,17 +31,24 @@ public class AppLoader { /** * Application-wide dependencies */ - private final PlantList plantList = new JsonPlantList(); - private final CropList cropList = new JsonCropList(); - private final TaskList taskList = new JsonTaskList(); - - private final GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList); - private final Garden garden = new Garden(gardenSchedule, cropList); - + private final Map dependencies = new HashMap<>(); public AppLoader() throws IOException { - } + PlantList plantList = new JsonPlantList(); + CropList cropList = new JsonCropList(); + TaskList taskList = new JsonTaskList(); + GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList); + dependencies.put(PlantList.class.getSimpleName(), plantList); + dependencies.put(CropList.class.getSimpleName(), cropList); + dependencies.put(TaskList.class.getSimpleName(), taskList); + + dependencies.put(PlantListModel.class.getSimpleName(), new PlantListModel(plantList)); + + dependencies.put(GardenSchedule.class.getSimpleName(), gardenSchedule); + dependencies.put(Garden.class.getSimpleName(), new Garden(gardenSchedule, cropList)); + dependencies.put(AppLoader.class.getSimpleName(), this); + } /** * Loads and returns a {@link Pane} (cached). @@ -130,26 +141,18 @@ public class AppLoader { }); Arrays.stream(controller.getClass().getMethods()) - .filter(method -> method.isAnnotationPresent(AfterInject.class)) + .filter(method -> method.isAnnotationPresent(AfterInject.class) && method.getParameterCount() == 0) .forEach(afterInjectMethod -> { - if (afterInjectMethod.getParameterCount() == 0) { - try { - afterInjectMethod.invoke(controller); - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } + try { + afterInjectMethod.invoke(controller); + } catch (IllegalAccessException | InvocationTargetException e) { + // TODO: Log + e.printStackTrace(); } }); } private Object getAppDependency(Class type) { - return switch (type.getSimpleName()) { - case "Garden" -> garden; - case "PlantList" -> plantList; - case "PlantListModel" -> new PlantListModel(plantList); - case "GardenSchedule" -> gardenSchedule; - case "AppLoader" -> this; - default -> null; - }; + return dependencies.get(type.getSimpleName()); } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/ChangeViewEvent.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/ChangeViewEvent.java index 4388ebe..f8242d3 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/ChangeViewEvent.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/ChangeViewEvent.java @@ -3,11 +3,20 @@ package ch.zhaw.gartenverwaltung.bootstrap; import javafx.event.Event; import javafx.event.EventType; +/** + * Represents an event that should lead to a view being changed. + */ public class ChangeViewEvent extends Event { private final String view; public static final EventType CHANGE_MAIN_VIEW = new EventType<>("CHANGE_MAIN_VIEW"); + /** + * Creates an Event that should lead to the main view being changed. + * + * @param eventType The {@link EventType} specifying which view should be changed. + * @param view The filename of the View to be changed to + */ public ChangeViewEvent(EventType eventType, String view) { super(eventType); this.view = view; diff --git a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/Inject.java b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/Inject.java index 02409d5..803844f 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/Inject.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/bootstrap/Inject.java @@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotates a Field to be injected from the application-dependencies + * Annotates a Field to be injected from the application-dependencies. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/CropList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/CropList.java index 7b9fd47..0805c99 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/CropList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/CropList.java @@ -6,6 +6,10 @@ import java.io.IOException; import java.util.List; import java.util.Optional; +/** + * Represents a List of {@link Crop}s. + * The interface specifies the operations to add/update and remove entries. + */ public interface CropList { /** * Yields a list of all {@link Crop}s in the database. diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/IdProvider.java b/src/main/java/ch/zhaw/gartenverwaltung/io/IdProvider.java index 5842f0d..49fd868 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/IdProvider.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/IdProvider.java @@ -1,10 +1,18 @@ package ch.zhaw.gartenverwaltung.io; +/** + * Provides an sequential ID starting from the given initial Value. + */ public class IdProvider { private long currentId; public IdProvider(long initialValue) { currentId = initialValue; } + + /** + * Yields the next ID in the sequence. + * @return The next ID + */ public long incrementAndGet() { return ++currentId; } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonCropList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonCropList.java index c7fd0ea..aa30391 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonCropList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonCropList.java @@ -19,6 +19,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; +/** + * Implements the {@link CropList} interface for reading and writing {@link Crop} objects + * from and to a local JSON file. + * The reads are cached to minimize file-io operations. + */ public class JsonCropList implements CropList { private final URL dataSource; @@ -40,7 +45,7 @@ public class JsonCropList implements CropList { } /** - * Default constructor + * Default constructor. Uses a file from the app resources. */ public JsonCropList() { this.dataSource = getClass().getResource("user-crops.json"); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantList.java index 7b76f70..ec46d67 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonPlantList.java @@ -20,8 +20,8 @@ import java.util.Map; import java.util.Optional; /** - * Implements the {@link PlantList} interface for loading {@link Plant} objects - * from a JSON file. + * Implements the {@link PlantList} interface for reading {@link Plant} objects + * from a local JSON file. * The reads are cached to minimize file-io operations. */ public class JsonPlantList implements PlantList { @@ -44,9 +44,17 @@ public class JsonPlantList implements PlantList { imageModule.addDeserializer(Image.class, new PlantImageDeserializer()); } + /** + * Default constructor. Uses a file from the app resources. + */ public JsonPlantList() { this.dataSource = getClass().getResource("plantdb.json"); } + + /** + * Constructor to use a specified {@link URL} as a {@link #dataSource} + * @param dataSource A {@link URL} to the file to be used as a data source + */ public JsonPlantList(URL dataSource) { this.dataSource = dataSource; } @@ -67,7 +75,7 @@ public class JsonPlantList implements PlantList { } /** - * @see PlantList#getPlantById(long) + * @see PlantList#getPlantById(HardinessZone, long) */ @Override public Optional getPlantById(HardinessZone zone, long id) throws HardinessZoneNotSetException, IOException { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonTaskList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonTaskList.java index 7f6d36b..5b1cb96 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/JsonTaskList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/JsonTaskList.java @@ -20,8 +20,8 @@ import java.util.List; import java.util.Map; /** - * Implements the {@link TaskList} interface for loading and writing {@link Task} objects - * from and to a JSON file. + * Implements the {@link TaskList} interface for reading and writing {@link Task} objects + * from and to a local JSON file. * The reads are cached to minimize file-io operations. */ public class JsonTaskList implements TaskList { @@ -45,9 +45,17 @@ public class JsonTaskList implements TaskList { timeModule.addSerializer(LocalDate.class, dateSerializer); } + /** + * Default constructor. Uses a file from the app resources. + */ public JsonTaskList() { this.dataSource = getClass().getResource("taskdb.json"); } + + /** + * Constructor to use a specified {@link URL} as a {@link #dataSource} + * @param dataSource A {@link URL} to the file to be used as a data source + */ public JsonTaskList(URL dataSource) { this.dataSource = dataSource; } @@ -88,7 +96,8 @@ public class JsonTaskList implements TaskList { if(taskMap.isEmpty()) { loadTaskListFromFile(); } - taskMap.values().removeIf(task -> task.getCropId() == cropId); + taskMap.entrySet().removeIf(entry -> entry.getValue().getCropId() == cropId); + writeTaskListToFile(); notifySubscribers(); } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/PlantList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/PlantList.java index 8650429..f5c4dc9 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/PlantList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/PlantList.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.Optional; /** - * A database of {@link Plant}s. + * A List of {@link Plant}s. * The interface specifies the minimal required operations. */ public interface PlantList { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/io/TaskList.java b/src/main/java/ch/zhaw/gartenverwaltung/io/TaskList.java index 95f5b07..60e745c 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/io/TaskList.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/io/TaskList.java @@ -7,8 +7,8 @@ import java.time.LocalDate; import java.util.List; /** - * A database of {@link Task}s. - * The interface specifies the minimal required operations. + * Represents a List of {@link Task}s. + * The interface specifies the operations to add/update and remove entries. */ public interface TaskList { /** diff --git a/src/main/java/ch/zhaw/gartenverwaltung/json/GrowthPhaseTypeDeserializer.java b/src/main/java/ch/zhaw/gartenverwaltung/json/GrowthPhaseTypeDeserializer.java index 35956a1..9da78da 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/json/GrowthPhaseTypeDeserializer.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/json/GrowthPhaseTypeDeserializer.java @@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; +/** + * Used by the Jackson Library to deserialize a String to a {@link GrowthPhaseType} + */ public class GrowthPhaseTypeDeserializer extends StdDeserializer { public GrowthPhaseTypeDeserializer(Class vc) { super(vc); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/json/HardinessZoneDeserializer.java b/src/main/java/ch/zhaw/gartenverwaltung/json/HardinessZoneDeserializer.java index 2a8ec1b..8170436 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/json/HardinessZoneDeserializer.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/json/HardinessZoneDeserializer.java @@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; +/** + * Used by the Jackson Library to deserialize a String to a {@link HardinessZone} + */ public class HardinessZoneDeserializer extends StdDeserializer { public HardinessZoneDeserializer(Class vc) { super(vc); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java b/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java index d40b882..29e055a 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/json/PlantImageDeserializer.java @@ -13,6 +13,9 @@ import java.io.InputStream; import java.net.URISyntaxException; import java.net.URL; +/** + * Used by the Jackson Library to deserialize a String to a {@link Image} + */ public class PlantImageDeserializer extends JsonDeserializer { @Override diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java b/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java index fd25b2a..617f03c 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java @@ -70,6 +70,19 @@ public class Garden { plantedCrops.clear(); plantedCrops.addAll(cropList.getCrops()); } + + /** + * Updates the {@link Crop} from the file and the cache + * + * @param crop The crop which is being updated + * @throws IOException If the database cannot be accessed + */ + public void updateCrop(Crop crop) throws IOException { + cropList.saveCrop(crop); + plantedCrops.clear(); + plantedCrops.addAll(cropList.getCrops()); + } + /** * Returns a list of {@link Crop}s which are currently in the gardenplan. * diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java index babcc01..96eae4f 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java @@ -150,13 +150,18 @@ public class GardenSchedule { dayTaskList.add(new ArrayList<>()); final int finalI = i; weekTasks.forEach(task -> { - LocalDate checkDate = task.getNextExecution(); - do { - if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) { - dayTaskList.get(finalI).add(task); - } - checkDate = checkDate.plusDays(task.getInterval().orElse(0)); - } while (task.getInterval().isPresent() && checkDate.isBefore(LocalDate.now().plusDays(listLength))); + if (task.getNextExecution() == null) { + task.isDone(); + } else { + LocalDate checkDate = task.getNextExecution(); + + do { + if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) { + dayTaskList.get(finalI).add(task); + } + checkDate = checkDate.plusDays(task.getInterval().orElse(0)); + } while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength))); + } }); } return dayTaskList; @@ -191,6 +196,6 @@ public class GardenSchedule { * @return a sorted coppy of the given Tasklist */ private List getSortedTaskList(List taskList, Comparator comparator) { - return taskList.stream().sorted(comparator).collect(Collectors.toList()); + return taskList.stream().filter(task -> task.getNextExecution() != null).sorted(comparator).collect(Collectors.toList()); } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java index 4cf269f..d602f51 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Plant.java @@ -67,16 +67,16 @@ public record Plant( public int timeToHarvest(int group) { List activeLifecycle = lifecycleForGroup(group); GrowthPhase sow = activeLifecycle.stream() - .filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.SOW)) + .filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.SOW)) .findFirst() .orElseThrow(); GrowthPhase harvest = activeLifecycle.stream() - .filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.HARVEST)) + .filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.HARVEST)) .findFirst() .orElseThrow(); int currentYear = LocalDate.now().getYear(); - return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear)); + return (int) DAYS.between(sow.startDate().atYear(currentYear),harvest.startDate().atYear(currentYear)); } public int lifecycleGroupFromHarvestDate(LocalDate harvestDate) { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Seasons.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Seasons.java index 2a2d2d0..fd2601c 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Seasons.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Seasons.java @@ -3,7 +3,7 @@ package ch.zhaw.gartenverwaltung.types; import java.time.MonthDay; public enum Seasons { - AllSEASONS("--01-01", "--12-31", "All Seasons"), + ALLSEASONS("--01-01", "--12-31", "All Seasons"), SPRING("--03-01", "--05-30", "Spring"), SUMMER("--06-01", "--08-30", "Summer"), AUTUMN("--09-01", "--11-30", "Autumn"), diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java b/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java index c7d506a..f85e5b1 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/Task.java @@ -10,14 +10,15 @@ import java.util.Optional; */ public class Task { private Long id; - private final String name; - private final String description; - private final LocalDate startDate; + private String name; + private String description; + private LocalDate startDate; private Integer interval; private LocalDate endDate; private LocalDate nextExecution; private LocalDate nextNotification; private long cropId; + private boolean done; /** * default constructor @@ -78,7 +79,7 @@ public class Task { } public void done(){ - if(interval != null && !nextExecution.plusDays(interval).isAfter(endDate)){ + if(interval != null && interval != 0 && !nextExecution.plusDays(interval).isAfter(endDate)){ nextExecution = nextExecution.plusDays(interval); } else { nextExecution = null; @@ -112,4 +113,14 @@ public class Task { public Optional getEndDate() { return Optional.ofNullable(endDate); } + + public Task updateTask(Task task) { + this.name = task.getName(); + this.description = task.getDescription(); + this.startDate = task.getStartDate(); + this.endDate = task.getEndDate().orElse(null); + this.interval = task.getInterval().orElse(0); + this.cropId = task.getCropId(); + return this; + } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/types/TaskTemplate.java b/src/main/java/ch/zhaw/gartenverwaltung/types/TaskTemplate.java index b2cb06f..39e349f 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/types/TaskTemplate.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/types/TaskTemplate.java @@ -42,7 +42,7 @@ public class TaskTemplate { } public Task generateTask(LocalDate realStartDate, long cropId) { - LocalDate endDate = relativeEndDate != null ? realStartDate.plusDays(relativeEndDate) : null; + LocalDate endDate = relativeEndDate != null ? realStartDate.plusDays(relativeEndDate) : realStartDate; if (interval == null) { this.interval = 0; diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/CropDetail.fxml b/src/main/resources/ch/zhaw/gartenverwaltung/CropDetail.fxml index c0f0a7c..1ee27fb 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/CropDetail.fxml +++ b/src/main/resources/ch/zhaw/gartenverwaltung/CropDetail.fxml @@ -107,7 +107,7 @@ -