From 15279838b751b9d5f90e5721addc310919a6143f Mon Sep 17 00:00:00 2001 From: David Guler Date: Mon, 14 Nov 2022 20:00:01 +0100 Subject: [PATCH 1/5] refactor: first attempt at dependency injection also some more renaming and improving date-picker dialog --- .../CropDetailController.java | 50 ++++-- .../gartenverwaltung/MainFXMLController.java | 112 +++++++++--- .../gartenverwaltung/MyGardenController.java | 140 +++++++++++++++ .../gartenverwaltung/MyPlantsController.java | 160 ------------------ .../MyScheduleController.java | 61 +++---- .../gartenverwaltung/PlantsController.java | 32 ++-- .../SelectSowDayController.java | 96 ++++------- .../zhaw/gartenverwaltung/models/Garden.java | 18 +- .../models/GardenSchedule.java | 9 +- .../models/PlantListModel.java | 8 +- src/main/java/module-info.java | 2 + .../ch/zhaw/gartenverwaltung/MainFXML.fxml | 4 +- .../{MyPlants.fxml => MyGarden.fxml} | 4 +- .../models/GardenPlanModelTest.java | 15 +- 14 files changed, 378 insertions(+), 333 deletions(-) create mode 100644 src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java delete mode 100644 src/main/java/ch/zhaw/gartenverwaltung/MyPlantsController.java rename src/main/resources/ch/zhaw/gartenverwaltung/{MyPlants.fxml => MyGarden.fxml} (93%) diff --git a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java index 622992c..1d887b5 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/CropDetailController.java @@ -1,9 +1,10 @@ package ch.zhaw.gartenverwaltung; +import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; -import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.GardenSchedule; +import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Pest; import ch.zhaw.gartenverwaltung.types.Plant; @@ -20,13 +21,23 @@ import javafx.stage.Stage; import java.io.IOException; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; public class CropDetailController { - private Crop crop = null; - private final PlantListModel plantListModel = new PlantListModel(); - private final GardenSchedule gardenSchedule = new GardenSchedule(); - private final Garden garden = new Garden(gardenSchedule); + private Crop crop; + private PlantList plantList; + private GardenSchedule gardenSchedule; + private Garden garden; + private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName()); + + @SuppressWarnings("unused") + public void injectDependencies(Garden garden, PlantList plantList, GardenSchedule gardenSchedule) { + this.garden = garden; + this.plantList = plantList; + this.gardenSchedule = gardenSchedule; + } @FXML private ImageView imageView; @@ -63,9 +74,6 @@ public class CropDetailController { @FXML private Label spacing_label; - public CropDetailController() throws IOException { - } - @FXML void editTaskList(ActionEvent event) { @@ -87,9 +95,11 @@ public class CropDetailController { } - public void setPlantFromCrop(Crop crop) throws HardinessZoneNotSetException, IOException { + public void setPlantFromCrop(Crop crop) throws HardinessZoneNotSetException, IOException, PlantNotFoundException { this.crop = crop; - Plant plant = plantListModel.getFilteredPlantListById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(0); + Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) + .orElseThrow(PlantNotFoundException::new); + cropName_label.setText(plant.name()); description_label.setText(plant.description()); light_label.setText(String.valueOf(plant.light())); @@ -104,12 +114,20 @@ public class CropDetailController { createPestList(plant); } - private void createTaskLists(Crop crop) throws IOException { - List taskList = gardenSchedule.getTaskListForCrop(crop.getCropId().get()); - for (Task task : taskList) { - Label label = new Label(task.getDescription()); - growthPhases_vbox.getChildren().add(label); - } + private void createTaskLists(Crop crop) { + crop.getCropId().ifPresent(id -> { + List taskList; + try { + taskList = gardenSchedule.getTaskListForCrop(id); + for (Task task : taskList) { + Label label = new Label(task.getDescription()); + growthPhases_vbox.getChildren().add(label); + } + } catch (IOException e) { + // TODO: Alert + LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause()); + } + }); } private void createPestList(Plant plant) { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java b/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java index 032bdb8..29eaa30 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MainFXMLController.java @@ -1,17 +1,35 @@ package ch.zhaw.gartenverwaltung; +import ch.zhaw.gartenverwaltung.io.CropList; +import ch.zhaw.gartenverwaltung.io.JsonCropList; +import ch.zhaw.gartenverwaltung.io.JsonPlantList; +import ch.zhaw.gartenverwaltung.io.JsonTaskList; +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.io.TaskList; +import ch.zhaw.gartenverwaltung.models.Garden; +import ch.zhaw.gartenverwaltung.models.GardenSchedule; +import ch.zhaw.gartenverwaltung.models.PlantListModel; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; @@ -20,9 +38,16 @@ public class MainFXMLController implements Initializable { /** * Caching the panes */ - private final Map panes = new HashMap<>(); + private final Map panes = new HashMap<>(); private static final Logger LOG = Logger.getLogger(MainFXMLController.class.getName()); + 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); + @FXML private Button home_button; @@ -30,7 +55,7 @@ public class MainFXMLController implements Initializable { private AnchorPane mainPane; @FXML - private Button myPlants_button; + private Button myGarden_button; @FXML private Button mySchedule_button; @@ -38,27 +63,30 @@ public class MainFXMLController implements Initializable { @FXML private Button plants_button; + public MainFXMLController() throws IOException { + } + @FXML void goToHome(ActionEvent event) throws IOException { - loadPane("Home.fxml"); + showPaneAsMainView("Home.fxml"); styleChangeButton(home_button); } @FXML void goToMyPlants(ActionEvent event) throws IOException { - loadPane("MyPlants.fxml"); - styleChangeButton(myPlants_button); + showPaneAsMainView("MyGarden.fxml"); + styleChangeButton(myGarden_button); } @FXML void goToMySchedule(ActionEvent event) throws IOException { - loadPane("MySchedule.fxml"); + showPaneAsMainView("MySchedule.fxml"); styleChangeButton(mySchedule_button); } @FXML void goToPlants(ActionEvent event) throws IOException { - loadPane("Plants.fxml"); + showPaneAsMainView("Plants.fxml"); styleChangeButton(plants_button); } @@ -69,23 +97,68 @@ public class MainFXMLController implements Initializable { * @param fxmlFile string of fxml file * @throws IOException exception when file does not exist */ - public void loadPane(String fxmlFile) throws IOException { - - AnchorPane anchorPane = panes.get(fxmlFile); + public void showPaneAsMainView(String fxmlFile) throws IOException { + Pane anchorPane = panes.get(fxmlFile); if (anchorPane == null) { - FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); - anchorPane = loader.load(); - panes.put(fxmlFile, anchorPane); - - if(fxmlFile.equals("MyPlants.fxml")) { - MyPlantsController myPlantsController = loader.getController(); - myPlantsController.getMainController(this); - } + loadAndCacheFxml(fxmlFile); + anchorPane = panes.get(fxmlFile); } mainPane.getChildren().setAll(anchorPane); anchorPane.prefWidthProperty().bind(mainPane.widthProperty()); anchorPane.prefHeightProperty().bind(mainPane.heightProperty()); + } + public Object loadSceneToStage(String fxmlFile, Stage appendee) throws IOException { + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + Pane root = loader.load(); + appendee.setScene(new Scene(root)); + Object controller = loader.getController(); + injectDependencies(controller); + return controller; + } + + public FXMLLoader loadAndCacheFxml(String fxmlFile) throws IOException { + FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); + AnchorPane anchorPane = loader.load(); + panes.put(fxmlFile, anchorPane); + injectDependencies(loader.getController()); + return loader; + } + + public void injectDependencies(Object controller) { + Optional injectMethod = Arrays.stream(controller.getClass().getMethods()) + .filter(method -> method.getName().equals("injectDependencies") ) + .findFirst(); + if (injectMethod.isPresent()) { + Method injectee = injectMethod.get(); + + List params = new ArrayList<>(); + for (Class parameterType : injectee.getParameterTypes()) { + Object toInject = switch (parameterType.getSimpleName()) { + case "Garden" -> garden; + case "PlantList" -> plantList; + case "PlantListModel" -> new PlantListModel(plantList); + case "GardenSchedule" -> gardenSchedule; + case "MainFXMLController" -> this; + default -> null; + }; + if (toInject != null) { + params.add(toInject); + } + } + try { + injectee.invoke(controller, params.toArray()); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + + private void preloadPanes() throws IOException { + loadAndCacheFxml("MyGarden.fxml"); + loadAndCacheFxml("MySchedule.fxml"); + loadAndCacheFxml("Plants.fxml").getController(); } private void styleChangeButton(Button button) { @@ -99,7 +172,8 @@ public class MainFXMLController implements Initializable { @Override public void initialize(URL url, ResourceBundle resourceBundle) { try { - loadPane("Home.fxml"); + preloadPanes(); + showPaneAsMainView("Home.fxml"); styleChangeButton(home_button); } catch (IOException e) { LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java new file mode 100644 index 0000000..afb94a3 --- /dev/null +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyGardenController.java @@ -0,0 +1,140 @@ +package ch.zhaw.gartenverwaltung; + +import ch.zhaw.gartenverwaltung.io.PlantList; +import ch.zhaw.gartenverwaltung.models.Garden; +import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; +import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; +import ch.zhaw.gartenverwaltung.types.Crop; +import ch.zhaw.gartenverwaltung.types.Plant; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.fxml.FXML; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.ButtonType; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; +import javafx.stage.Stage; + +import java.io.IOException; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MyGardenController { + private static final Logger LOG = Logger.getLogger(MyGardenController.class.getName()); + + MainFXMLController mainController; + private Garden garden; + private PlantList plantList; + + @FXML + private VBox myPlants_vbox; + + @SuppressWarnings("unused") + public void injectDependencies(Garden garden, PlantList plantList, MainFXMLController mainController) { + this.garden = garden; + this.plantList = plantList; + this.mainController = mainController; + + garden.getPlantedCrops().addListener((observable, oldValue, newValue) -> { + try { + createPlantView(newValue); + } catch (HardinessZoneNotSetException | IOException e) { + LOG.log(Level.SEVERE, "Could not update view of croplist!", e); + } + }); + try { + createPlantView(garden.getPlantedCrops()); + } catch (HardinessZoneNotSetException | IOException e) { + LOG.log(Level.SEVERE, "Could not update view of croplist!", e); + } + } + + @FXML + void addPlant(ActionEvent event) throws IOException { + mainController.showPaneAsMainView("Plants.fxml"); + } + + private void createPlantView(List crops) throws HardinessZoneNotSetException, IOException { + myPlants_vbox.getChildren().clear(); + for (Crop crop : crops) { + HBox hBox = createPlantView(crop); + myPlants_vbox.getChildren().add(hBox); + } + } + + private HBox createPlantView(Crop crop) throws HardinessZoneNotSetException, IOException { + //ToDo add better design + Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(); + HBox hBox = new HBox(10); + ImageView imageView = new ImageView(); + imageView.setPreserveRatio(false); + imageView.setFitHeight(100); + imageView.setFitWidth(100); + imageView.maxHeight(100); + if (plant.image() != null) { + imageView.setImage(plant.image()); + } + hBox.setMinHeight(100); + Label label = new Label(plant.name()); + label.setMaxWidth(2000); + HBox.setHgrow(label, Priority.ALWAYS); + Button details = new Button("Details"); + Button delete = new Button("delete"); + details.setOnAction(getGoToCropDetailEvent(crop)); + delete.setOnAction(getDeleteCropEvent(crop)); + hBox.getChildren().addAll(imageView, label, details, delete); + return hBox; + } + + private EventHandler getGoToCropDetailEvent(Crop crop) { + return (event) -> { + try { + Stage stage = new Stage(); + if (mainController.loadSceneToStage("CropDetail.fxml", stage) instanceof CropDetailController controller) { + controller.setPlantFromCrop(crop); + } + stage.initModality(Modality.APPLICATION_MODAL); + stage.setResizable(true); + stage.showAndWait(); + } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { + // TODO: show error alert + LOG.log(Level.SEVERE, "Could not load plant details.", e); + } + }; + } + + private EventHandler getDeleteCropEvent(Crop crop) { + return (event) -> { + try { + showConfirmation(crop); + } catch (IOException | HardinessZoneNotSetException e) { + e.printStackTrace(); + } + }; + } + + private void showConfirmation(Crop crop) throws IOException, HardinessZoneNotSetException { + Alert alert = new Alert(Alert.AlertType.CONFIRMATION); + alert.setTitle("Delete Crop"); + alert.setHeaderText("Are you sure want to delete this Crop?"); + alert.setContentText("placeholder"); + + alert.showAndWait() + .ifPresent(buttonType -> { + if (buttonType == ButtonType.OK) { + try { + garden.removeCrop(crop); + } catch (IOException e) { + // TODO: Show error alert + LOG.log(Level.SEVERE, "Could not remove crop.", e); + } + } + }); + } +} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyPlantsController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyPlantsController.java deleted file mode 100644 index 1639134..0000000 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyPlantsController.java +++ /dev/null @@ -1,160 +0,0 @@ -package ch.zhaw.gartenverwaltung; - -import ch.zhaw.gartenverwaltung.models.Garden; -import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; -import ch.zhaw.gartenverwaltung.models.PlantListModel; -import ch.zhaw.gartenverwaltung.models.GardenSchedule; -import ch.zhaw.gartenverwaltung.types.Crop; -import ch.zhaw.gartenverwaltung.types.Plant; -import javafx.event.ActionEvent; -import javafx.event.EventHandler; -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; -import javafx.scene.Parent; -import javafx.scene.Scene; -import javafx.scene.control.Alert; -import javafx.scene.control.Button; -import javafx.scene.control.ButtonType; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.VBox; -import javafx.stage.Modality; -import javafx.stage.Stage; - -import java.io.IOException; -import java.net.URL; -import java.util.*; - -public class MyPlantsController implements Initializable { - MainFXMLController mainController; - private final GardenSchedule gardenSchedule = new GardenSchedule(); - private final Garden garden = new Garden(gardenSchedule); - private final PlantListModel plantListModel = new PlantListModel(); - - @FXML - private VBox myPlants_vbox; - - public MyPlantsController() throws IOException { - } - - @FXML - void addPlant(ActionEvent event) throws IOException { - mainController.loadPane("Plants.fxml"); - } - - @Override - public void initialize(URL url, ResourceBundle resourceBundle) { - //ToDo update, when new crops are added - try { - loadCropList(); - } catch (HardinessZoneNotSetException | IOException e) { - e.printStackTrace(); - } - } - - private void loadCropList() throws HardinessZoneNotSetException, IOException { - List cropList = new LinkedList<>(); - try { - cropList = getCropList(); - } catch (IOException e) { - e.printStackTrace(); - } - createPlantView(cropList); - } - - private void createPlantView(List crops) throws HardinessZoneNotSetException, IOException { - myPlants_vbox.getChildren().clear(); - for(Crop crop : crops) { - HBox hBox = createPlantView(crop); - myPlants_vbox.getChildren().add(hBox); - } - } - - public void getMainController(MainFXMLController controller) { - mainController = controller; - } - - private List getCropList() throws IOException { - List cropList; - cropList = garden.getCrops(); - return cropList; - } - - private HBox createPlantView(Crop crop) throws HardinessZoneNotSetException, IOException { - //ToDo add better design - Plant plant = plantListModel.getFilteredPlantListById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(0); - HBox hBox = new HBox(10); - ImageView imageView = new ImageView(); - imageView.setPreserveRatio(false); - imageView.setFitHeight(100); - imageView.setFitWidth(100); - imageView.maxHeight(100); - if (plant.image() != null) { - imageView.setImage(plant.image()); - } - hBox.setMinHeight(100); - Label label = new Label(plant.name()); - label.setMaxWidth(2000); - HBox.setHgrow(label, Priority.ALWAYS); - Button details = new Button("Details"); - Button delete = new Button("delete"); - details.setOnAction(getGoToCropDetailEvent(crop)); - delete.setOnAction(getDeleteCropEvent(crop)); - hBox.getChildren().addAll(imageView, label, details, delete); - return hBox; - } - - private EventHandler getGoToCropDetailEvent(Crop crop) { - EventHandler event = new EventHandler() { - @Override - public void handle(ActionEvent event) { - Parent root; - FXMLLoader fxmlLoader = new FXMLLoader(Objects.requireNonNull(getClass().getResource("CropDetail.fxml"))); - try { - root = fxmlLoader.load(); - CropDetailController controller = fxmlLoader.getController(); - controller.setPlantFromCrop(crop); - Stage stage = new Stage(); - stage.setScene(new Scene(root)); - stage.initModality(Modality.APPLICATION_MODAL); - stage.setResizable(true); - stage.showAndWait(); - } catch (IOException | HardinessZoneNotSetException e) { - e.printStackTrace(); - } - } - }; - return event; - } - - private EventHandler getDeleteCropEvent(Crop crop) { - EventHandler event = new EventHandler() { - @Override - public void handle(ActionEvent event) { - try { - showConfirmation(crop); - } catch (IOException | HardinessZoneNotSetException e) { - e.printStackTrace(); - } - } - }; - return event; - } - - private void showConfirmation(Crop crop) throws IOException, HardinessZoneNotSetException { - Alert alert = new Alert(Alert.AlertType.CONFIRMATION); - alert.setTitle("Delete Crop"); - alert.setHeaderText("Are you sure want to delete this Crop?"); - alert.setContentText("placeholder"); - - Optional option = alert.showAndWait(); - - if (option.get() == ButtonType.OK) { - garden.removeCrop(crop); - loadCropList(); - } - } -} diff --git a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java index a763754..6585675 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/MyScheduleController.java @@ -1,18 +1,16 @@ package ch.zhaw.gartenverwaltung; +import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; -import ch.zhaw.gartenverwaltung.models.PlantListModel; 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.beans.value.ChangeListener; -import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.fxml.FXML; -import javafx.fxml.Initializable; import javafx.scene.control.Label; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; @@ -20,20 +18,29 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import java.io.IOException; -import java.net.URL; import java.time.LocalDate; -import java.util.LinkedList; import java.util.List; -import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MyScheduleController { + private static final Logger LOG = Logger.getLogger(MyScheduleController.class.getName()); -public class MyScheduleController implements Initializable { private Crop selectedCrop = null; - private final GardenSchedule gardenSchedule = new GardenSchedule(); - private final Garden garden = new Garden(gardenSchedule); - private final PlantListModel plantListModel = new PlantListModel(); + private GardenSchedule gardenSchedule; + private Garden garden; + private PlantList plantList; private final ListProperty cropListProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); + @SuppressWarnings("unused") + public void injectDependencies(Garden garden, GardenSchedule gardenSchedule, PlantList plantList) { + this.garden = garden; + this.gardenSchedule = gardenSchedule; + this.plantList = plantList; + + init(); + } @FXML private Label day1_label; @@ -82,11 +89,7 @@ public class MyScheduleController implements Initializable { @FXML private ListView scheduledPlants_listview; - public MyScheduleController() throws IOException { - } - - @Override - public void initialize(URL location, ResourceBundle resources) { + public void init() { List cropList; try { cropList = garden.getCrops(); @@ -107,15 +110,12 @@ public class MyScheduleController implements Initializable { } private void lookForSelectedListEntries() { - scheduledPlants_listview.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Crop oldValue, Crop newValue) { - selectedCrop = newValue; - try { - loadTaskList(); - } catch (IOException e) { - e.printStackTrace(); - } + scheduledPlants_listview.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + selectedCrop = newValue; + try { + loadTaskList(); + } catch (IOException e) { + e.printStackTrace(); } }); } @@ -132,7 +132,7 @@ public class MyScheduleController implements Initializable { } private void setCellFactoryListView() { - scheduledPlants_listview.setCellFactory(param -> new ListCell() { + scheduledPlants_listview.setCellFactory(param -> new ListCell<>() { @Override protected void updateItem(Crop crop, boolean empty) { super.updateItem(crop, empty); @@ -141,9 +141,12 @@ public class MyScheduleController implements Initializable { setText(null); } else { try { - setText(plantListModel.getFilteredPlantListById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(0).name()); + String text = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) + .map(Plant::name) + .orElse(""); + setText(text); } catch (HardinessZoneNotSetException | IOException e) { - e.printStackTrace(); + LOG.log(Level.WARNING, "Could not get plant for Cell", e); } } } @@ -151,7 +154,7 @@ public class MyScheduleController implements Initializable { } private void loadTaskList() throws IOException { - List> taskLists = new LinkedList<>(); + List> taskLists; if (selectedCrop != null) { taskLists = gardenSchedule.getTasksUpcomingWeekForCrop(selectedCrop.getCropId().get()); } else { diff --git a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java index 1d832ef..0004f30 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/PlantsController.java @@ -10,11 +10,7 @@ import javafx.beans.property.SimpleListProperty; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; import javafx.geometry.Insets; -import javafx.scene.Parent; -import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; @@ -23,22 +19,27 @@ import javafx.stage.Modality; import javafx.stage.Stage; import java.io.IOException; -import java.net.URL; import java.util.List; -import java.util.Objects; -import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; -public class PlantsController implements Initializable { +public class PlantsController { private static final Logger LOG = Logger.getLogger(PlantsController.class.getName()); - private final PlantListModel plantListModel = new PlantListModel(); + private PlantListModel plantListModel; + private MainFXMLController mainController; private Plant selectedPlant = null; private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A; // TODO: move to model private final ListProperty plantListProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); + @SuppressWarnings("unused") + public void injectDependencies(PlantListModel plantListModel, MainFXMLController mainController) { + this.plantListModel = plantListModel; + this.mainController = mainController; + init(); + } + @FXML private VBox seasons; @@ -66,13 +67,11 @@ public class PlantsController implements Initializable { */ @FXML void selectSowDate(ActionEvent event) throws IOException { - Parent root; - FXMLLoader fxmlLoader = new FXMLLoader(Objects.requireNonNull(getClass().getResource("SelectSowDay.fxml"))); - root = fxmlLoader.load(); - SelectSowDayController controller = fxmlLoader.getController(); - controller.getSelectedPlant(selectedPlant); Stage stage = new Stage(); - stage.setScene(new Scene(root)); + if (mainController.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) { + controller.setSelectedPlant(selectedPlant); + } + stage.initModality(Modality.APPLICATION_MODAL); stage.setResizable(false); stage.showAndWait(); @@ -85,8 +84,7 @@ public class PlantsController implements Initializable { * create event listener for selected list entry and search by query * {@inheritDoc} */ - @Override - public void initialize(URL url, ResourceBundle resourceBundle) { + public void init() { setListCellFactory(); fillPlantListWithHardinessZone(); list_plants.itemsProperty().bind(plantListProperty); diff --git a/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java b/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java index f00ba59..7dc9389 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/SelectSowDayController.java @@ -3,7 +3,6 @@ package ch.zhaw.gartenverwaltung; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; -import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.types.GrowthPhaseType; import ch.zhaw.gartenverwaltung.types.Plant; import javafx.event.ActionEvent; @@ -21,8 +20,12 @@ import java.util.ResourceBundle; public class SelectSowDayController implements Initializable { private Plant selectedPlant = null; - private final GardenSchedule gardenSchedule = new GardenSchedule(); - private final Garden garden = new Garden(gardenSchedule); + private Garden garden; + + @SuppressWarnings("unused") + public void injectDependencies(Garden garden) { + this.garden = garden; + } @FXML private DatePicker datepicker; @@ -34,9 +37,7 @@ public class SelectSowDayController implements Initializable { private Button save_button; @FXML - private RadioButton sow_radio; - - public SelectSowDayController() throws IOException {} + private RadioButton harvest_radio; /** * close the date selector window @@ -54,10 +55,8 @@ public class SelectSowDayController implements Initializable { */ @FXML void save(ActionEvent event) throws HardinessZoneNotSetException, IOException, PlantNotFoundException { - LocalDate sowDate; - if (sow_radio.isSelected()) { - sowDate = datepicker.getValue(); - } else { + LocalDate sowDate = datepicker.getValue(); + if (harvest_radio.isSelected()) { //ToDo method to get current lifecycle group in plant sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0); } @@ -69,9 +68,9 @@ public class SelectSowDayController implements Initializable { * save the plant which will be planted and update label * @param plant Plant */ - public void getSelectedPlant(Plant plant) { + public void setSelectedPlant(Plant plant) { selectedPlant = plant; - popup_label.setText("Select Harvest/Sow Date for" + selectedPlant.name()); + popup_label.setText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name())); } /** @@ -86,16 +85,16 @@ public class SelectSowDayController implements Initializable { Callback dayCellFactory= getDayCellFactory(); datepicker.setDayCellFactory(dayCellFactory); - datepicker.getEditor().setEditable(false); + datepicker.setEditable(false); - enableDisableSaveButton(); + save_button.disableProperty().bind(datepicker.valueProperty().isNull()); } /** * clear date picker editor when radio button is changed */ private void clearDatePickerEntries() { - sow_radio.selectedProperty().addListener((observable, oldValue, isNowSelected) -> datepicker.getEditor().clear()); + harvest_radio.selectedProperty().addListener((observable, oldValue, isNowSelected) -> datepicker.setValue(null)); } /** @@ -104,40 +103,33 @@ public class SelectSowDayController implements Initializable { */ private Callback getDayCellFactory() { - final Callback dayCellFactory = new Callback() { - + return (datePicker) -> new DateCell() { @Override - public DateCell call(final DatePicker datePicker) { - return new DateCell() { - @Override - public void updateItem(LocalDate item, boolean empty) { - super.updateItem(item, empty); - setDisable(true); - setStyle("-fx-background-color: #ffc0cb;"); - List dates; - LocalDate today = LocalDate.now(); - if (sow_radio.isSelected()) { - dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.SOW); - } else { - dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.HARVEST); - } - for (LocalDate date : dates) { - if (item.getMonth() == date.getMonth() - && item.getDayOfMonth() == date.getDayOfMonth() - && item.compareTo(today) > 0) { - setDisable(false); - setStyle("-fx-background-color: #32CD32;"); - } - } - if ((!sow_radio.isSelected() && selectedPlant.sowDateFromHarvestDate(item, 0).compareTo(today) < 0)) { - setDisable(true); - setStyle("-fx-background-color: #ffc0cb;"); - } + public void updateItem(LocalDate item, boolean empty) { + super.updateItem(item, empty); + setDisable(true); + setStyle("-fx-background-color: #ffc0cb;"); + List dates; + LocalDate today = LocalDate.now(); + if (harvest_radio.isSelected()) { + dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.HARVEST); + } else { + dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.SOW); + } + for (LocalDate date : dates) { + if (item.getMonth() == date.getMonth() + && item.getDayOfMonth() == date.getDayOfMonth() + && item.compareTo(today) > 0) { + setDisable(false); + setStyle("-fx-background-color: #32CD32;"); } - }; + } + if ((harvest_radio.isSelected() && selectedPlant.sowDateFromHarvestDate(item, 0).compareTo(today) < 0)) { + setDisable(true); + setStyle("-fx-background-color: #ffc0cb;"); + } } }; - return dayCellFactory; } /** @@ -147,18 +139,4 @@ public class SelectSowDayController implements Initializable { Stage stage = (Stage) save_button.getScene().getWindow(); stage.close(); } - - /** - * disable save button, when there is no date selected in date picker - */ - private void enableDisableSaveButton() { - save_button.setDisable(true); - datepicker.getEditor().textProperty().addListener((observable, oldValue, newValue) -> { - if (newValue == null || newValue.equals("")) { - save_button.setDisable(true); - } else { - save_button.setDisable(false); - } - }); - } } diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java b/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java index 3d6032a..fd25b2a 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/Garden.java @@ -2,12 +2,12 @@ package ch.zhaw.gartenverwaltung.models; import ch.zhaw.gartenverwaltung.io.CropList; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; -import ch.zhaw.gartenverwaltung.io.JsonCropList; 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.collections.ObservableList; import java.io.IOException; import java.time.LocalDate; @@ -19,21 +19,25 @@ import java.util.Optional; * The Gardenplan model manages the crops in the gardenplan. */ public class Garden { - private CropList cropList; - private final ObservableList plantedCrops = FXCollections.observableArrayList(); - private GardenSchedule gardenSchedule; + private final CropList cropList; + private final ListProperty plantedCrops = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final GardenSchedule gardenSchedule; /** * Constructor of Gardenplan model * * @param gardenSchedule holds a reference to the task list object. */ - public Garden(GardenSchedule gardenSchedule) throws IOException { + public Garden(GardenSchedule gardenSchedule, CropList cropList) throws IOException { this.gardenSchedule = gardenSchedule; - cropList = new JsonCropList(); + this.cropList = cropList; plantedCrops.addAll(cropList.getCrops()); } + public ListProperty getPlantedCrops() { + return plantedCrops; + } + /** * Creates a Crop with a {@link Plant} and the planting date of the plant. Then let the Tasklistmodel create the * gardening {@link Task} for the crop. Store the crop in the gardenplan file and the cache. diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java index 30a0a50..9195d51 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/GardenSchedule.java @@ -12,19 +12,14 @@ import java.util.List; import java.util.stream.Collectors; public class GardenSchedule { - private TaskList taskList; - private PlantList plantList; + private final TaskList taskList; + private final PlantList plantList; /** * Comparators to create sorted Task List */ static final Comparator sortByStartDate = Comparator.comparing(Task::getStartDate); - public GardenSchedule(){ - taskList = new JsonTaskList(); - plantList = new JsonPlantList(); - } - /** * Constructor to create Database Objects. */ diff --git a/src/main/java/ch/zhaw/gartenverwaltung/models/PlantListModel.java b/src/main/java/ch/zhaw/gartenverwaltung/models/PlantListModel.java index 6b96bee..19cce96 100644 --- a/src/main/java/ch/zhaw/gartenverwaltung/models/PlantListModel.java +++ b/src/main/java/ch/zhaw/gartenverwaltung/models/PlantListModel.java @@ -1,7 +1,6 @@ package ch.zhaw.gartenverwaltung.models; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; -import ch.zhaw.gartenverwaltung.io.JsonPlantList; import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.types.GrowthPhaseType; import ch.zhaw.gartenverwaltung.types.HardinessZone; @@ -16,7 +15,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; public class PlantListModel { - private PlantList plantList; + private final PlantList plantList; private HardinessZone currentZone; /** @@ -28,11 +27,6 @@ public class PlantListModel { /** * Constructor to create Database Object. */ - public PlantListModel() { - plantList = new JsonPlantList(); - setDefaultZone(); - } - public PlantListModel(PlantList plantList) { this.plantList = plantList; setDefaultZone(); diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 6900f7f..44103dd 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -9,6 +9,8 @@ module ch.zhaw.gartenverwaltung { opens ch.zhaw.gartenverwaltung to javafx.fxml; opens ch.zhaw.gartenverwaltung.types to com.fasterxml.jackson.databind; exports ch.zhaw.gartenverwaltung; + exports ch.zhaw.gartenverwaltung.io; exports ch.zhaw.gartenverwaltung.types; + exports ch.zhaw.gartenverwaltung.models; exports ch.zhaw.gartenverwaltung.json; } \ No newline at end of file diff --git a/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml b/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml index 569a89d..7fa27e1 100644 --- a/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml +++ b/src/main/resources/ch/zhaw/gartenverwaltung/MainFXML.fxml @@ -11,8 +11,8 @@