Compare commits

..

No commits in common. "05e7bcc2e83af1a1cc667fee09fcb80f1dd8970b" and "5ef3f6c587332a0b0d0f32d85f35946c3a02745c" have entirely different histories.

13 changed files with 131 additions and 184 deletions

View File

@ -1,7 +1,8 @@
package ch.zhaw.gartenverwaltung; package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
import javafx.application.Application; import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.io.IOException; import java.io.IOException;
@ -9,11 +10,10 @@ import java.io.IOException;
public class HelloApplication extends Application { public class HelloApplication extends Application {
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
AppLoader appLoader = new AppLoader(); FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("MainFXML.fxml"));
Scene scene = new Scene(fxmlLoader.load());
appLoader.loadSceneToStage("MainFXML.fxml", stage);
stage.setTitle("Gartenverwaltung"); stage.setTitle("Gartenverwaltung");
stage.setScene(scene);
stage.show(); stage.show();
} }

View File

@ -1,25 +1,21 @@
package ch.zhaw.gartenverwaltung; package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
import ch.zhaw.gartenverwaltung.bootstrap.ChangeViewEvent;
import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import java.io.IOException; import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
public class MainFXMLController { public class MainFXMLController implements Initializable {
private static final Logger LOG = Logger.getLogger(MainFXMLController.class.getName()); private static final Logger LOG = Logger.getLogger(MainFXMLController.class.getName());
private final AppLoader appLoader = new AppLoader(this);
@Inject
AppLoader appLoader;
@FXML @FXML
private Button home_button; private Button home_button;
@ -35,26 +31,29 @@ public class MainFXMLController {
@FXML @FXML
private Button plants_button; private Button plants_button;
public MainFXMLController() throws IOException {
}
@FXML @FXML
void goToHome() { void goToHome() throws IOException {
showPaneAsMainView("Home.fxml"); showPaneAsMainView("Home.fxml");
styleChangeButton(home_button); styleChangeButton(home_button);
} }
@FXML @FXML
void goToMyPlants() { void goToMyPlants() throws IOException {
showPaneAsMainView("MyGarden.fxml"); showPaneAsMainView("MyGarden.fxml");
styleChangeButton(myGarden_button); styleChangeButton(myGarden_button);
} }
@FXML @FXML
void goToMySchedule() { void goToMySchedule() throws IOException {
showPaneAsMainView("MySchedule.fxml"); showPaneAsMainView("MySchedule.fxml");
styleChangeButton(mySchedule_button); styleChangeButton(mySchedule_button);
} }
@FXML @FXML
void goToPlants() { void goToPlants() throws IOException {
showPaneAsMainView("Plants.fxml"); showPaneAsMainView("Plants.fxml");
styleChangeButton(plants_button); styleChangeButton(plants_button);
} }
@ -64,22 +63,15 @@ public class MainFXMLController {
* set HGrow and VGrow to parent AnchorPane. * set HGrow and VGrow to parent AnchorPane.
* Sends MainController to other Controllers. * Sends MainController to other Controllers.
* @param fxmlFile string of fxml file * @param fxmlFile string of fxml file
* @throws IOException exception when file does not exist
*/ */
public void showPaneAsMainView(String fxmlFile) { public void showPaneAsMainView(String fxmlFile) throws IOException {
try { Pane anchorPane = appLoader.loadPane(fxmlFile);
Pane anchorPane = appLoader.loadPane(fxmlFile); mainPane.getChildren().setAll(anchorPane);
mainPane.getChildren().setAll(anchorPane); anchorPane.prefWidthProperty().bind(mainPane.widthProperty());
anchorPane.prefWidthProperty().bind(mainPane.widthProperty()); anchorPane.prefHeightProperty().bind(mainPane.heightProperty());
anchorPane.prefHeightProperty().bind(mainPane.heightProperty());
anchorPane.removeEventHandler(ChangeViewEvent.CHANGE_MAIN_VIEW, changeMainViewHandler);
anchorPane.addEventHandler(ChangeViewEvent.CHANGE_MAIN_VIEW, changeMainViewHandler);
} catch (IOException e) {
LOG.log(Level.SEVERE, "Could not load pane.", e);
}
} }
private final EventHandler<ChangeViewEvent> changeMainViewHandler = (ChangeViewEvent event) -> showPaneAsMainView(event.view());
private void preloadPanes() throws IOException { private void preloadPanes() throws IOException {
appLoader.loadAndCacheFxml("MyGarden.fxml"); appLoader.loadAndCacheFxml("MyGarden.fxml");
@ -95,9 +87,8 @@ public class MainFXMLController {
* loads the default FXML File * loads the default FXML File
* {@inheritDoc} * {@inheritDoc}
*/ */
@AfterInject @Override
@SuppressWarnings("unused") public void initialize(URL url, ResourceBundle resourceBundle) {
public void init() {
try { try {
preloadPanes(); preloadPanes();
showPaneAsMainView("Home.fxml"); showPaneAsMainView("Home.fxml");

View File

@ -2,7 +2,6 @@ package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject; import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
import ch.zhaw.gartenverwaltung.bootstrap.ChangeViewEvent;
import ch.zhaw.gartenverwaltung.bootstrap.Inject; import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.io.PlantList;
import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.Garden;
@ -18,7 +17,6 @@ import javafx.scene.control.Button;
import javafx.scene.control.ButtonType; import javafx.scene.control.ButtonType;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@ -32,15 +30,16 @@ import java.util.logging.Logger;
public class MyGardenController { public class MyGardenController {
private static final Logger LOG = Logger.getLogger(MyGardenController.class.getName()); private static final Logger LOG = Logger.getLogger(MyGardenController.class.getName());
@Inject @Inject
AppLoader appLoader; AppLoader appLoader;
@Inject @Inject
MainFXMLController mainController;
@Inject
private Garden garden; private Garden garden;
@Inject @Inject
private PlantList plantList; private PlantList plantList;
@FXML
public AnchorPane myGardenRoot;
@FXML @FXML
private VBox myPlants_vbox; private VBox myPlants_vbox;
@ -62,8 +61,8 @@ public class MyGardenController {
} }
@FXML @FXML
void addPlant() { void addPlant(ActionEvent event) throws IOException {
myGardenRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "Plants.fxml")); mainController.showPaneAsMainView("Plants.fxml");
} }
private void createPlantView(List<Crop> crops) throws HardinessZoneNotSetException, IOException { private void createPlantView(List<Crop> crops) throws HardinessZoneNotSetException, IOException {
@ -129,7 +128,7 @@ public class MyGardenController {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION); Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Delete Crop"); alert.setTitle("Delete Crop");
alert.setHeaderText("Are you sure want to delete this Crop?"); alert.setHeaderText("Are you sure want to delete this Crop?");
alert.setContentText("Deleting this crop will remove all associated tasks from your schedule."); alert.setContentText("placeholder");
alert.showAndWait() alert.showAndWait()
.ifPresent(buttonType -> { .ifPresent(buttonType -> {

View File

@ -2,12 +2,9 @@ package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject; import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; import ch.zhaw.gartenverwaltung.bootstrap.AppLoader;
import ch.zhaw.gartenverwaltung.bootstrap.ChangeViewEvent;
import ch.zhaw.gartenverwaltung.bootstrap.Inject; import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.models.Garden;
import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantListModel;
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.types.HardinessZone; import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Seasons; import ch.zhaw.gartenverwaltung.types.Seasons;
@ -19,12 +16,11 @@ import javafx.geometry.Insets;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -36,8 +32,6 @@ public class PlantsController {
private PlantListModel plantListModel; private PlantListModel plantListModel;
@Inject @Inject
private AppLoader appLoader; private AppLoader appLoader;
@Inject
private Garden garden;
private Plant selectedPlant = null; private Plant selectedPlant = null;
private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A; private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A;
@ -45,9 +39,6 @@ public class PlantsController {
// TODO: move to model // TODO: move to model
private final ListProperty<Plant> plantListProperty = new SimpleListProperty<>(FXCollections.observableArrayList()); private final ListProperty<Plant> plantListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
@FXML
public AnchorPane plantsRoot;
@FXML @FXML
private VBox seasons; private VBox seasons;
@ -75,32 +66,13 @@ public class PlantsController {
@FXML @FXML
void selectSowDate() throws IOException { void selectSowDate() throws IOException {
Stage stage = new Stage(); Stage stage = new Stage();
Dialog<LocalDate> dateSelection = new Dialog<>();
dateSelection.setTitle("Select Date");
dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name()));
dateSelection.setResizable(false);
DialogPane dialogPane = dateSelection.getDialogPane();
ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL);
if (appLoader.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) { if (appLoader.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) {
controller.initSaveButton((Button) dialogPane.lookupButton(sowButton));
controller.setSelectedPlant(selectedPlant); controller.setSelectedPlant(selectedPlant);
dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null);
} }
dialogPane.setContent(stage.getScene().getRoot());
dateSelection.showAndWait() stage.initModality(Modality.APPLICATION_MODAL);
.ifPresent(date -> { stage.setResizable(false);
try { stage.showAndWait();
garden.plantAsCrop(selectedPlant, date);
} catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
LOG.log(Level.SEVERE, "Couldn't save Crop", e);
}
plantsRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "MyGarden.fxml"));
});
} }
/** /**
@ -134,7 +106,7 @@ public class PlantsController {
} }
/** /**
* set text of list view to plant name * set text of list view to plant name
*/ */
private void setListCellFactory() { private void setListCellFactory() {
list_plants.setCellFactory(param -> new ListCell<>() { list_plants.setCellFactory(param -> new ListCell<>() {
@ -154,10 +126,9 @@ public class PlantsController {
/** /**
* get plant list according to param season and hardiness zone * get plant list according to param season and hardiness zone
* fill list view with plant list * fill list view with plant list
*
* @param season enum of seasons * @param season enum of seasons
* @throws HardinessZoneNotSetException throws exception * @throws HardinessZoneNotSetException throws exception
* @throws IOException throws exception * @throws IOException throws exception
*/ */
private void viewFilteredListBySeason(Seasons season) throws HardinessZoneNotSetException, IOException { private void viewFilteredListBySeason(Seasons season) throws HardinessZoneNotSetException, IOException {
clearListView(); clearListView();
@ -167,9 +138,8 @@ public class PlantsController {
/** /**
* get plant list filtered by search plant entry and hardiness zone * get plant list filtered by search plant entry and hardiness zone
* fill list view with plant list * fill list view with plant list
*
* @throws HardinessZoneNotSetException throws exception when no hardiness zone is defined * @throws HardinessZoneNotSetException throws exception when no hardiness zone is defined
* @throws IOException throws exception * @throws IOException throws exception
*/ */
private void viewFilteredListBySearch() throws HardinessZoneNotSetException, IOException { private void viewFilteredListBySearch() throws HardinessZoneNotSetException, IOException {
search_plants.textProperty().addListener((observable, oldValue, newValue) -> { search_plants.textProperty().addListener((observable, oldValue, newValue) -> {
@ -214,7 +184,7 @@ public class PlantsController {
for (HardinessZone zone : HardinessZone.values()) { for (HardinessZone zone : HardinessZone.values()) {
RadioButton radioButton = new RadioButton(zone.name()); RadioButton radioButton = new RadioButton(zone.name());
radioButton.setToggleGroup(hardinessGroup); radioButton.setToggleGroup(hardinessGroup);
radioButton.setPadding(new Insets(0, 0, 10, 0)); radioButton.setPadding(new Insets(0,0,10,0));
if (zone.equals(DEFAULT_HARDINESS_ZONE)) { if (zone.equals(DEFAULT_HARDINESS_ZONE)) {
radioButton.setSelected(true); radioButton.setSelected(true);
} }
@ -236,7 +206,7 @@ public class PlantsController {
for (Seasons season : Seasons.values()) { for (Seasons season : Seasons.values()) {
RadioButton radioButton = new RadioButton(season.getName()); RadioButton radioButton = new RadioButton(season.getName());
radioButton.setToggleGroup(seasonGroup); radioButton.setToggleGroup(seasonGroup);
radioButton.setPadding(new Insets(0, 0, 10, 0)); radioButton.setPadding(new Insets(0,0,10,0));
if (season.equals(Seasons.AllSEASONS)) { if (season.equals(Seasons.AllSEASONS)) {
radioButton.setSelected(true); radioButton.setSelected(true);
} }
@ -270,12 +240,12 @@ public class PlantsController {
Image img = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); Image img = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
img_plant.setImage(img); img_plant.setImage(img);
list_plants.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { list_plants.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
if (newValue != null) { if(newValue != null) {
selectedPlant = newValue; selectedPlant = newValue;
description_plant.setText(selectedPlant.description()); description_plant.setText(selectedPlant.description());
selectSowDay_button.setDisable(false); selectSowDay_button.setDisable(false);
Image img1; Image img1;
if (selectedPlant.image() != null) { if(selectedPlant.image() != null) {
img1 = selectedPlant.image(); img1 = selectedPlant.image();
} else { } else {
img1 = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); img1 = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));

View File

@ -1,55 +1,88 @@
package ch.zhaw.gartenverwaltung; package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import ch.zhaw.gartenverwaltung.models.Garden;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType; import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.stage.Stage;
import javafx.util.Callback; import javafx.util.Callback;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.ResourceBundle;
public class SelectSowDayController { public class SelectSowDayController implements Initializable {
private Plant selectedPlant; private Plant selectedPlant = null;
@Inject
private Garden garden;
@FXML @FXML
private DatePicker datepicker; private DatePicker datepicker;
@FXML
private Label popup_label;
@FXML
private Button save_button;
@FXML @FXML
private RadioButton harvest_radio; private RadioButton harvest_radio;
public LocalDate retrieveResult() { /**
* close the date selector window
*/
@FXML
void cancel() {
closeWindow();
}
/**
* get sow date from datePicker or calculate sow date from harvest date
* save selected plant and sow date
*/
@FXML
void save() throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
LocalDate sowDate = datepicker.getValue(); LocalDate sowDate = datepicker.getValue();
if (harvest_radio.isSelected()) { if (harvest_radio.isSelected()) {
//ToDo method to get current lifecycle group in plant //ToDo method to get current lifecycle group in plant
sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0); sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0);
} }
return sowDate; garden.plantAsCrop(selectedPlant, sowDate);
closeWindow();
} }
/** /**
* Set the {@link Plant} for which a date should be selected. * save the plant which will be planted and update label
*
* @param plant Plant * @param plant Plant
*/ */
public void setSelectedPlant(Plant plant) { public void setSelectedPlant(Plant plant) {
selectedPlant = plant; selectedPlant = plant;
popup_label.setText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name()));
} }
/** /**
* add listener and set default values * add listener and set default values
* {@inheritDoc}
* @param location location
* @param resources resources
*/ */
@FXML @Override
public void initialize() { public void initialize(URL location, ResourceBundle resources) {
clearDatePickerEntries(); clearDatePickerEntries();
Callback<DatePicker, DateCell> dayCellFactory = getDayCellFactory(); Callback<DatePicker, DateCell> dayCellFactory= getDayCellFactory();
datepicker.setDayCellFactory(dayCellFactory); datepicker.setDayCellFactory(dayCellFactory);
datepicker.setEditable(false); datepicker.setEditable(false);
}
public void initSaveButton(Button saveButton) { save_button.disableProperty().bind(datepicker.valueProperty().isNull());
saveButton.disableProperty().bind(datepicker.valueProperty().isNull());
} }
/** /**
@ -93,4 +126,12 @@ public class SelectSowDayController {
} }
}; };
} }
/**
* close date picker window
*/
private void closeWindow() {
Stage stage = (Stage) save_button.getScene().getWindow();
stage.close();
}
} }

View File

@ -5,10 +5,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/**
* Annotates a method to be executed after all dependencies annotates with {@link Inject}
* have been injected.
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD) @Target(ElementType.METHOD)
public @interface AfterInject { } public @interface AfterInject { }

View File

@ -1,6 +1,7 @@
package ch.zhaw.gartenverwaltung.bootstrap; package ch.zhaw.gartenverwaltung.bootstrap;
import ch.zhaw.gartenverwaltung.HelloApplication; import ch.zhaw.gartenverwaltung.HelloApplication;
import ch.zhaw.gartenverwaltung.MainFXMLController;
import ch.zhaw.gartenverwaltung.io.CropList; import ch.zhaw.gartenverwaltung.io.CropList;
import ch.zhaw.gartenverwaltung.io.JsonCropList; import ch.zhaw.gartenverwaltung.io.JsonCropList;
import ch.zhaw.gartenverwaltung.io.JsonPlantList; import ch.zhaw.gartenverwaltung.io.JsonPlantList;
@ -12,6 +13,7 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantListModel;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -37,19 +39,14 @@ public class AppLoader {
private final GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList); private final GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList);
private final Garden garden = new Garden(gardenSchedule, cropList); private final Garden garden = new Garden(gardenSchedule, cropList);
private final MainFXMLController mainController;
public AppLoader() throws IOException { public AppLoader(MainFXMLController mainController) throws IOException {
this.mainController = mainController;
} }
/**
* Loads and returns a {@link Pane} (cached).
*
* @param fxmlFile The file name to be loaded
* @return The loaded Pane
* @throws IOException if the file could not be loaded
*/
public Pane loadPane(String fxmlFile) throws IOException { public Pane loadPane(String fxmlFile) throws IOException {
Pane pane = panes.get(fxmlFile); Pane pane = panes.get(fxmlFile);
if (pane == null) { if (pane == null) {
@ -59,16 +56,6 @@ public class AppLoader {
return pane; return pane;
} }
/**
* Loads the given fxml-file from resources (no caching) and creates a new {@link Scene},
* which is then appended to the given {@link Stage}.
* Performs dependency-injection.
*
* @param fxmlFile The file name to be loaded
* @param appendee The {@link Stage} to which the new {@link Scene} is appended.
* @return The controller of the loaded scene.
* @throws IOException if the file could not be loaded
*/
public Object loadSceneToStage(String fxmlFile, Stage appendee) throws IOException { public Object loadSceneToStage(String fxmlFile, Stage appendee) throws IOException {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
Pane root = loader.load(); Pane root = loader.load();
@ -78,27 +65,13 @@ public class AppLoader {
return controller; return controller;
} }
/**
* Loads the given fxml-file from resources and caches the pane.
* Performs dependency-injection.
*
* @param fxmlFile The file name to be loaded
* @throws IOException if the file could not be loaded
*/
public void loadAndCacheFxml(String fxmlFile) throws IOException { public void loadAndCacheFxml(String fxmlFile) throws IOException {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
Pane pane = loader.load(); AnchorPane anchorPane = loader.load();
panes.put(fxmlFile, pane); panes.put(fxmlFile, anchorPane);
annotationInject(loader.getController()); annotationInject(loader.getController());
} }
/**
* Injects the applications dependencies into the given object's fields annotated with {@link Inject}.
* Afterwards, all methods on the objects annotated with {@link AfterInject} are executed.
* (Success of the injections is not guaranteed!)
*
* @param controller The class containing the injectable fields
*/
public void annotationInject(Object controller) { public void annotationInject(Object controller) {
Arrays.stream(controller.getClass().getDeclaredFields()) Arrays.stream(controller.getClass().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(Inject.class)) .filter(field -> field.isAnnotationPresent(Inject.class))
@ -131,6 +104,7 @@ public class AppLoader {
case "PlantList" -> plantList; case "PlantList" -> plantList;
case "PlantListModel" -> new PlantListModel(plantList); case "PlantListModel" -> new PlantListModel(plantList);
case "GardenSchedule" -> gardenSchedule; case "GardenSchedule" -> gardenSchedule;
case "MainFXMLController" -> mainController;
case "AppLoader" -> this; case "AppLoader" -> this;
default -> null; default -> null;
}; };

View File

@ -1,19 +0,0 @@
package ch.zhaw.gartenverwaltung.bootstrap;
import javafx.event.Event;
import javafx.event.EventType;
public class ChangeViewEvent extends Event {
private final String view;
public static final EventType<ChangeViewEvent> CHANGE_MAIN_VIEW = new EventType<>("CHANGE_MAIN_VIEW");
public ChangeViewEvent(EventType<? extends Event> eventType, String view) {
super(eventType);
this.view = view;
}
public String view() {
return view;
}
}

View File

@ -5,9 +5,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/**
* Annotates a Field to be injected from the application-dependencies
*/
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface Inject { } public @interface Inject { }

View File

@ -7,7 +7,7 @@
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="655.0" prefWidth="1175.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.MyGardenController" fx:id="myGardenRoot"> <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="655.0" prefWidth="1175.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.MyGardenController">
<children> <children>
<VBox layoutY="49.0" prefHeight="655.0" prefWidth="1175.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <VBox layoutY="49.0" prefHeight="655.0" prefWidth="1175.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children> <children>

View File

@ -15,8 +15,7 @@
<AnchorPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="1000.0" prefHeight="853.0" <AnchorPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="1000.0" prefHeight="853.0"
prefWidth="1219.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" prefWidth="1219.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.zhaw.gartenverwaltung.PlantsController" fx:controller="ch.zhaw.gartenverwaltung.PlantsController">
fx:id="plantsRoot">
<children> <children>
<SplitPane dividerPositions="0.7377363661277062" layoutX="539.0" layoutY="266.0" prefHeight="853.0" prefWidth="1219.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <SplitPane dividerPositions="0.7377363661277062" layoutX="539.0" layoutY="266.0" prefHeight="853.0" prefWidth="1219.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items> <items>

View File

@ -1,7 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DatePicker?> <?import javafx.scene.control.DatePicker?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.RadioButton?> <?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.ToggleGroup?> <?import javafx.scene.control.ToggleGroup?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
@ -14,11 +16,12 @@
<children> <children>
<VBox maxWidth="1.7976931348623157E308" prefHeight="408.0" prefWidth="640.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <VBox maxWidth="1.7976931348623157E308" prefHeight="408.0" prefWidth="640.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children> <children>
<Label fx:id="popup_label" text="Label" />
<HBox alignment="CENTER" prefHeight="293.0" prefWidth="631.0"> <HBox alignment="CENTER" prefHeight="293.0" prefWidth="631.0">
<children> <children>
<VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0"> <VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0">
<children> <children>
<RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow" toggleGroup="$group"> <RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow">
<VBox.margin> <VBox.margin>
<Insets bottom="10.0" /> <Insets bottom="10.0" />
</VBox.margin> </VBox.margin>
@ -35,6 +38,16 @@
<DatePicker fx:id="datepicker" /> <DatePicker fx:id="datepicker" />
</children> </children>
</HBox> </HBox>
<HBox fillHeight="false" prefHeight="54.0" prefWidth="631.0" VBox.vgrow="NEVER">
<children>
<Button fx:id="save_button" mnemonicParsing="false" onAction="#save" prefHeight="25.0" prefWidth="53.0" text="Save">
<HBox.margin>
<Insets right="10.0" />
</HBox.margin>
</Button>
<Button fx:id="cancel_button" mnemonicParsing="false" onAction="#cancel" text="Cancel" />
</children>
</HBox>
</children> </children>
<padding> <padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />

View File

@ -6,25 +6,17 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.IOException; import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.MonthDay; import java.time.MonthDay;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
public class GardenPlanModelTest { public class GardenPlanModelTest {
private final URL dbDataSource = JsonCropList.class.getResource("user-crops.json");
private final URL testFile = JsonCropList.class.getResource("test-user-crops.json");
CropList cropList; CropList cropList;
List<Crop> exampleCrops; List<Crop> exampleCrops;
Crop exampleCropOnion; Crop exampleCropOnion;
@ -37,7 +29,7 @@ public class GardenPlanModelTest {
Garden model; Garden model;
@BeforeEach @BeforeEach
void setUp() throws IOException, URISyntaxException { void setUp() throws IOException {
examplePlantOnion = new Plant( examplePlantOnion = new Plant(
@ -84,24 +76,18 @@ public class GardenPlanModelTest {
exampleCrops.add(exampleCrop1); exampleCrops.add(exampleCrop1);
exampleCrops.add(exampleCrop2); exampleCrops.add(exampleCrop2);
exampleCrops.add(exampleCrop3); exampleCrops.add(exampleCrop3);
cropList = mockCropList(exampleCrops); cropList = mockGardenPlan(exampleCrops);
// Reset Crop "database" before test GardenSchedule gardenSchedule = new GardenSchedule(new JsonTaskList(), new JsonPlantList());
assertNotNull(testFile); model = new Garden(gardenSchedule, cropList);
assertNotNull(dbDataSource);
Files.copy(Path.of(testFile.toURI()), Path.of(dbDataSource.toURI()), StandardCopyOption.REPLACE_EXISTING);
CropList testDatabase = new JsonCropList(dbDataSource);
GardenSchedule gardenSchedule = mock(GardenSchedule.class);
model = new Garden(gardenSchedule, testDatabase);
} }
CropList mockCropList(List<Crop> cropList) throws IOException { CropList mockGardenPlan(List<Crop> cropList) throws IOException {
CropList croplist = mock(CropList.class); CropList gardenPlan = mock(CropList.class);
when(croplist.getCrops()).thenReturn(cropList); when(gardenPlan.getCrops()).thenReturn(cropList);
when(croplist.getCropById(5)).thenReturn(java.util.Optional.ofNullable(exampleCropCarrot)); when(gardenPlan.getCropById(5)).thenReturn(java.util.Optional.ofNullable(exampleCropCarrot));
when(croplist.getCropById(3)).thenReturn(java.util.Optional.ofNullable(exampleCropOnion)); when(gardenPlan.getCropById(3)).thenReturn(java.util.Optional.ofNullable(exampleCropOnion));
return croplist; return gardenPlan;
} }
@Test @Test