package ch.zhaw.gartenverwaltung; import ch.zhaw.gartenverwaltung.bootstrap.AfterInject; import ch.zhaw.gartenverwaltung.bootstrap.AppLoader; import ch.zhaw.gartenverwaltung.bootstrap.ChangeViewEvent; import ch.zhaw.gartenverwaltung.bootstrap.Inject; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantNotFoundException; import ch.zhaw.gartenverwaltung.types.HardinessZone; import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Seasons; import javafx.beans.property.ListProperty; import javafx.beans.property.SimpleListProperty; import javafx.collections.FXCollections; import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.VBox; import java.io.IOException; import java.time.LocalDate; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; public class PlantsController { private static final Logger LOG = Logger.getLogger(PlantsController.class.getName()); @Inject private PlantListModel plantListModel; @Inject private AppLoader appLoader; @Inject private Garden garden; 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()); @FXML public AnchorPane plantsRoot; @FXML private VBox seasons; @FXML private VBox climate_zones; @FXML private Label description_plant; @FXML private ImageView img_plant; @FXML private ListView list_plants; @FXML private Button selectSowDay_button; @FXML private TextField search_plants; /** * open new window to select sow or harvest day to save the crop */ @FXML void selectSowDate() throws IOException { Dialog 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.loadPaneToDialog("SelectSowDay.fxml", dialogPane) instanceof SelectSowDayController controller) { controller.initSaveButton((Button) dialogPane.lookupButton(sowButton)); controller.setSelectedPlant(selectedPlant); dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null); dateSelection.showAndWait() .ifPresent(date -> { try { 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")); }); } } /** * fill list view with current hardiness zone * set default values * create filter of season and hardiness zone * create event listener for selected list entry and search by query * {@inheritDoc} */ @AfterInject @SuppressWarnings("unused") public void init() { setListCellFactory(); fillPlantListWithHardinessZone(); list_plants.itemsProperty().bind(plantListProperty); description_plant.setText(""); selectSowDay_button.setDisable(true); createFilterSeasons(); createFilterHardinessZone(); lookForSelectedListEntry(); try { viewFilteredListBySearch(); } catch (HardinessZoneNotSetException e) { LOG.log(Level.WARNING, "Hardiness Zone not set!"); } catch (IOException e) { LOG.log(Level.WARNING, "Could not retrieve data!", e); } } /** * set text of list view to plant name */ private void setListCellFactory() { list_plants.setCellFactory(param -> new ListCell<>() { @Override protected void updateItem(Plant plant, boolean empty) { super.updateItem(plant, empty); if (empty || plant == null || plant.name() == null) { setText(null); } else { setText(plant.name()); } } }); } /** * get plant list according to param season and hardiness zone * fill list view with plant list * * @param season enum of seasons * @throws HardinessZoneNotSetException throws exception * @throws IOException throws exception */ private void viewFilteredListBySeason(Seasons season) throws HardinessZoneNotSetException, IOException { clearListView(); plantListProperty.addAll(plantListModel.getFilteredPlantListBySaisonWithoutGrowthPhase(plantListModel.getCurrentZone(), season.getStartDate(), season.getEndDate())); } /** * get plant list filtered by search plant entry and hardiness zone * fill list view with plant list * * @throws HardinessZoneNotSetException throws exception when no hardiness zone is defined * @throws IOException throws exception */ private void viewFilteredListBySearch() throws HardinessZoneNotSetException, IOException { search_plants.textProperty().addListener((observable, oldValue, newValue) -> { if (newValue.isEmpty()) { fillPlantListWithHardinessZone(); } else { try { List filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, newValue); clearListView(); plantListProperty.addAll(filteredPlants); } catch (HardinessZoneNotSetException e) { LOG.log(Level.WARNING, "Hardiness Zone not set!"); } catch (IOException e) { LOG.log(Level.WARNING, "Could not retrieve data!", e); } } }); } /** * get plant list of current hardiness zone * fill list view with plant list */ private void fillPlantListWithHardinessZone() { try { clearListView(); plantListProperty.addAll(plantListModel.getPlantList(plantListModel.getCurrentZone())); } catch (HardinessZoneNotSetException e) { LOG.log(Level.WARNING, "Hardiness Zone not set!"); } catch (IOException e) { LOG.log(Level.WARNING, "Could not retrieve data!", e); } } /** * creates radio buttons for the hardiness zones defined in enum HardinessZone * defines default value as selected * when selected filter viewList according to hardiness zone */ private void createFilterHardinessZone() { ToggleGroup hardinessGroup = new ToggleGroup(); for (HardinessZone zone : HardinessZone.values()) { RadioButton radioButton = new RadioButton(zone.name()); radioButton.setToggleGroup(hardinessGroup); radioButton.setPadding(new Insets(0, 0, 10, 0)); if (zone.equals(DEFAULT_HARDINESS_ZONE)) { radioButton.setSelected(true); } radioButton.selectedProperty().addListener((observable, oldValue, newValue) -> { plantListModel.setCurrentZone(zone); fillPlantListWithHardinessZone(); }); climate_zones.getChildren().add(radioButton); } } /** * creates radio buttons for the seasons defined in enum Seasons * defines default value as selected * when selected filter viewList according to seasons */ private void createFilterSeasons() { ToggleGroup seasonGroup = new ToggleGroup(); for (Seasons season : Seasons.values()) { RadioButton radioButton = new RadioButton(season.getName()); radioButton.setToggleGroup(seasonGroup); radioButton.setPadding(new Insets(0, 0, 10, 0)); if (season.equals(Seasons.AllSEASONS)) { radioButton.setSelected(true); } radioButton.selectedProperty().addListener((observable, oldValue, newValue) -> { if (season.equals(Seasons.AllSEASONS)) { fillPlantListWithHardinessZone(); } else { try { viewFilteredListBySeason(season); } catch (HardinessZoneNotSetException e) { LOG.log(Level.WARNING, "Hardiness Zone not set!"); } catch (IOException e) { LOG.log(Level.WARNING, "Could not retrieve data!", e); } } }); seasons.getChildren().add(radioButton); } } /** * observes changes in the selectedProperty of ListView and updates: * the description label * image of the plant */ private void lookForSelectedListEntry() { selectedPlant = null; description_plant.setText(""); selectSowDay_button.setDisable(true); Image img = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); img_plant.setImage(img); list_plants.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { if (newValue != null) { selectedPlant = newValue; description_plant.setText(selectedPlant.description()); selectSowDay_button.setDisable(false); Image img1; if (selectedPlant.image() != null) { img1 = selectedPlant.image(); } else { img1 = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); } img_plant.setImage(img1); } else { selectedPlant = null; description_plant.setText(""); selectSowDay_button.setDisable(true); Image img1 = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png"))); img_plant.setImage(img1); } }); } /** * clears the ListView of entries */ private void clearListView() { plantListProperty.clear(); } }