package ch.zhaw.gartenverwaltung; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.plantList.PlantListModel; 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.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; import javafx.scene.layout.VBox; 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 { private static final Logger LOG = Logger.getLogger(PlantsController.class.getName()); private final PlantListModel plantListModel = new PlantListModel(); 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 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 * @param event event */ @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)); stage.initModality(Modality.APPLICATION_MODAL); stage.setResizable(false); stage.showAndWait(); } /** * 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} */ @Override public void initialize(URL url, ResourceBundle resourceBundle) { 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(); } }