Merge pull request #45 from schrom01/feature_controllerPlantList_M2

Plant Controller Filter to hardiness zone and season
This commit is contained in:
giavaphi 2022-10-31 13:07:49 +01:00 committed by GitHub Enterprise
commit 7a6a0eb66f
5 changed files with 179 additions and 118 deletions

View File

@ -19,7 +19,7 @@ public class MainFXMLController implements Initializable {
/** /**
* Caching the panes * Caching the panes
*/ */
private final Map<String, Node> panes = new HashMap<>(); private final Map<String, AnchorPane> panes = new HashMap<>();
@FXML @FXML
private Button home_button; private Button home_button;
@ -68,20 +68,22 @@ public class MainFXMLController implements Initializable {
* @throws IOException exception when file does not exist * @throws IOException exception when file does not exist
*/ */
public void loadPane(String fxmlFile) throws IOException { public void loadPane(String fxmlFile) throws IOException {
//ToDo HGrow and VGrow of new node
Node node = panes.get(fxmlFile); AnchorPane anchorPane = panes.get(fxmlFile);
System.out.println(node); if (anchorPane == null) {
if (node == null) {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile))); FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
node = loader.load(); anchorPane = loader.load();
panes.put(fxmlFile, node); panes.put(fxmlFile, anchorPane);
if(fxmlFile.equals("MyPlants.fxml")) { if(fxmlFile.equals("MyPlants.fxml")) {
MyPlantsController myPlantsController = loader.getController(); MyPlantsController myPlantsController = loader.getController();
myPlantsController.getMainController(this); myPlantsController.getMainController(this);
} }
} }
mainPane.getChildren().setAll(node); mainPane.getChildren().setAll(anchorPane);
anchorPane.prefWidthProperty().bind(mainPane.widthProperty());
anchorPane.prefHeightProperty().bind(mainPane.heightProperty());
} }
private void styleChangeButton(Button button) { private void styleChangeButton(Button button) {

View File

@ -4,6 +4,7 @@ import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.plantList.PlantListModel; import ch.zhaw.gartenverwaltung.plantList.PlantListModel;
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 javafx.application.Platform; import javafx.application.Platform;
import javafx.beans.property.ListProperty; import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleListProperty;
@ -13,8 +14,10 @@ import javafx.collections.FXCollections;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Bounds; import javafx.geometry.Bounds;
import javafx.scene.control.*; import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
@ -30,10 +33,11 @@ public class PlantsController implements Initializable {
private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A; private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A;
// 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 @FXML
private CheckBox autum_filter; private VBox seasons;
@FXML @FXML
private VBox climate_zones; private VBox climate_zones;
@ -53,81 +57,44 @@ public class PlantsController implements Initializable {
@FXML @FXML
private TextField search_plants; private TextField search_plants;
@FXML /**
private CheckBox sommer_filter; * saves the current selected plant in new JSON database
* @param event event
@FXML */
private CheckBox spring_filter;
@FXML
private CheckBox winter_filter;
@FXML
void filterAutum(ActionEvent event) {
//ToDo
}
@FXML
void filterSommer(ActionEvent event) {
//ToDo
}
@FXML
void filterSpring(ActionEvent event) {
//ToDo
}
@FXML
void filterWinter(ActionEvent event) {
//ToDo
}
@FXML @FXML
void saveToMyPlant(ActionEvent event) { void saveToMyPlant(ActionEvent event) {
//ToDo model save selectedPlant to mySelectedPlant(IO) //ToDo model save selectedPlant to mySelectedPlant(IO)
} }
@FXML
void searchForPlant(KeyEvent event) {
viewFilteredListBySearch(search_plants.getText());
}
/** /**
* 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} * {@inheritDoc}
*/ */
@Override @Override
public void initialize(URL url, ResourceBundle resourceBundle) { public void initialize(URL url, ResourceBundle resourceBundle) {
setListCellFactory(); setListCellFactory();
try { fillPlantListWithHardinessZone();
plantListProperty.addAll(plantListModel.getPlantList(DEFAULT_HARDINESS_ZONE));
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
list_plants.itemsProperty().bind(plantListProperty); list_plants.itemsProperty().bind(plantListProperty);
list_plants.getSelectionModel().selectedItemProperty()
.addListener((observable, oldPlant, newPlant) -> {
if (newPlant != null) {
img_plant.setImage(newPlant.image());
}
});
description_plant.setText(""); description_plant.setText("");
saveToMyPlant_button.setDisable(true); saveToMyPlant_button.setDisable(true);
createFilterSeasons();
createFilterHardinessZone(); createFilterHardinessZone();
lookForSelectedListEntry(); lookForSelectedListEntry();
try {
viewFilteredListBySearch();
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
} }
private void centerImage() { /**
* set text of list view to plant name
//img_plant.setX(0.3); */
//img_plant.setX(-100);
}
private void setListCellFactory() { private void setListCellFactory() {
list_plants.setCellFactory(param -> new ListCell<Plant>() { list_plants.setCellFactory(param -> new ListCell<Plant>() {
@Override @Override
@ -144,62 +111,138 @@ public class PlantsController implements Initializable {
} }
/** /**
* update the ListView according to the plant list provided * get plant list according to param season and hardiness zone
* Entry in ListView is plant name * fill list view with plant list
* @param list plantList which fill the ListView * @param season enum of seasons
* @throws HardinessZoneNotSetException throws exception
* @throws IOException throws exception
*/ */
private void fillListViewWithData(List<Plant> list) { private void viewFilteredListBySeason(Seasons season) throws HardinessZoneNotSetException, IOException {
clearListView(); clearListView();
for (Plant plant : list) { plantListProperty.addAll(plantListModel.getFilteredPlantListBySaisonWithoutGrowthPhase(plantListModel.getCurrentZone(), season.getStartDate(), season.getEndDate()));
list_plants.getItems().add(plant);
} }
} /**
* get plant list filtered by search plant entry and hardiness zone
private void viewFilteredListByFilters() { * fill list view with plant list
boolean springValue = spring_filter.isSelected(); * @throws HardinessZoneNotSetException throws exception when no hardiness zone is defined
boolean sommerValue = sommer_filter.isSelected(); * @throws IOException throws exception
boolean autumValue = autum_filter.isSelected(); */
boolean winterValue = winter_filter.isSelected(); private void viewFilteredListBySearch() throws HardinessZoneNotSetException, IOException {
//ToDo getFilteredPlantList with (plantListModel.getFilteredPlantList(DEFAULT_HARDINESS_ZONE, <predicate>)) search_plants.textProperty().addListener((observable, oldValue, newValue) -> {
//List<Plant> plantList = new LinkedList<>(); if (newValue.isEmpty()) {
//fillListViewWithData(plantList); fillPlantListWithHardinessZone();
} }else {
private void viewFilteredListBySearch(String query) {
//ToDo getFilteredPlantList with (plantListModel.getFilteredPlantList(DEFAULT_HARDINESS_ZONE, <predicate>))
try { try {
List<Plant> filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, query); List<Plant> filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, newValue);
clearListView(); clearListView();
plantListProperty.addAll(filteredPlants); plantListProperty.addAll(filteredPlants);
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
}
});
}
/**
* 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 | IOException e) { } catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/**
* 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() { private void createFilterHardinessZone() {
//ToDo create radioList of hardinessZone in VBox climate_zones 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(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
plantListModel.setCurrentZone(zone);
fillPlantListWithHardinessZone();
}
});
climate_zones.getChildren().add(radioButton);
}
} }
/** /**
* observes changes in the selectedProperty of ListView and updates the description label * 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.name());
radioButton.setToggleGroup(seasonGroup);
radioButton.setPadding(new Insets(0,0,10,0));
if (season.equals(Seasons.AllSEASONS)) {
radioButton.setSelected(true);
}
radioButton.selectedProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
if (season.equals(Seasons.AllSEASONS)) {
fillPlantListWithHardinessZone();
} else {
try {
viewFilteredListBySeason(season);
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
}
}
});
seasons.getChildren().add(radioButton);
}
}
/**
* observes changes in the selectedProperty of ListView and updates:
* the description label
* image of the plant
*/ */
private void lookForSelectedListEntry() { private void lookForSelectedListEntry() {
list_plants.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Plant>() { list_plants.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Plant>() {
@Override @Override
public void changed(ObservableValue<? extends Plant> observable, Plant oldValue, Plant newValue) { public void changed(ObservableValue<? extends Plant> observable, Plant oldValue, Plant newValue) {
//ToDo
if(newValue != null) { if(newValue != null) {
selectedPlant = newValue; selectedPlant = newValue;
description_plant.setText(selectedPlant.description()); description_plant.setText(selectedPlant.description());
saveToMyPlant_button.setDisable(false); saveToMyPlant_button.setDisable(false);
//update img plant Image img;
if(selectedPlant.image() != null) {
img = selectedPlant.image();
} else {
img = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
}
img_plant.setImage(img);
} else { } else {
selectedPlant = null; selectedPlant = null;
description_plant.setText(""); description_plant.setText("");
saveToMyPlant_button.setDisable(true); saveToMyPlant_button.setDisable(true);
//update img when null placeholder PNG Image img = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
img_plant.setImage(img);
} }
} }
}); });

View File

@ -167,4 +167,17 @@ public class PlantListModel {
public List<Plant> getFilteredPlantListByHarvestSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException { public List<Plant> getFilteredPlantListByHarvestSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantListBySaison(GrowthPhaseType.HARVEST, zone, from, to); return getFilteredPlantListBySaison(GrowthPhaseType.HARVEST, zone, from, to);
} }
/**
*
* @param zone selected hardiness zone
* @param from the earliest date to for the filter
* @param to the lastest date for the filter
* @return List of Plants with selected saison
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
* @throws IOException If the database cannot be accessed
*/
public List<Plant> getFilteredPlantListBySaisonWithoutGrowthPhase(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantList(zone, plant -> plant.lifecycle().stream().anyMatch(growthPhase -> growthPhase.startDate().compareTo(from) >= 0 && (growthPhase.startDate().compareTo(to) <= 0)));
}
} }

View File

@ -0,0 +1,26 @@
package ch.zhaw.gartenverwaltung.types;
import java.time.MonthDay;
public enum Seasons {
AllSEASONS("--01-01", "--12-31"),
SPRING("--03-01", "--05-30"),
SOMMER("--06-01", "--08-30"),
AUTUM("--09-01", "--11-30"),
WINTER("--12-01", "--02-28");
public final String startDate;
public final String endDate;
Seasons(String startDate, String endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
public MonthDay getStartDate() {
return MonthDay.parse(this.startDate);
}
public MonthDay getEndDate() {
return MonthDay.parse(this.endDate);
}
}

View File

@ -3,7 +3,6 @@
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?> <?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?> <?import javafx.scene.control.ListView?>
<?import javafx.scene.control.SplitPane?> <?import javafx.scene.control.SplitPane?>
@ -16,8 +15,9 @@
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?> <?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="1000.0" prefHeight="853.0" prefWidth="1219.0" <AnchorPane maxHeight="-Infinity" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="1000.0" prefHeight="853.0"
xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.PlantsController"> prefWidth="1219.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ch.zhaw.gartenverwaltung.PlantsController">
<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>
@ -30,7 +30,7 @@
<Font name="System Bold" size="30.0" /> <Font name="System Bold" size="30.0" />
</font> </font>
</Label> </Label>
<TextField fx:id="search_plants" onKeyTyped="#searchForPlant" promptText="Search for Plant Name" /> <TextField fx:id="search_plants" promptText="Search for Plant Name" />
<HBox alignment="CENTER_LEFT" prefHeight="480.0" prefWidth="881.0" VBox.vgrow="ALWAYS"> <HBox alignment="CENTER_LEFT" prefHeight="480.0" prefWidth="881.0" VBox.vgrow="ALWAYS">
<children> <children>
<ListView fx:id="list_plants" maxWidth="1.7976931348623157E308" prefHeight="497.0" prefWidth="580.0" HBox.hgrow="ALWAYS" /> <ListView fx:id="list_plants" maxWidth="1.7976931348623157E308" prefHeight="497.0" prefWidth="580.0" HBox.hgrow="ALWAYS" />
@ -75,30 +75,7 @@
<content> <content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0"> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children> <children>
<VBox layoutX="37.0" layoutY="-19.0" prefHeight="180.66666666666666" prefWidth="310.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> <VBox fx:id="seasons" layoutX="37.0" layoutY="-19.0" prefHeight="180.66666666666666" prefWidth="310.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
<children>
<CheckBox fx:id="spring_filter" mnemonicParsing="false" onAction="#filterSpring" text="Spring">
<padding>
<Insets top="10.0" />
</padding>
</CheckBox>
<CheckBox fx:id="sommer_filter" mnemonicParsing="false" onAction="#filterSommer" text="Sommer">
<padding>
<Insets top="10.0" />
</padding>
</CheckBox>
<CheckBox fx:id="autum_filter" mnemonicParsing="false" onAction="#filterAutum" text="Autum">
<padding>
<Insets top="10.0" />
</padding>
</CheckBox>
<CheckBox fx:id="winter_filter" mnemonicParsing="false" onAction="#filterWinter" text="Winter">
<padding>
<Insets top="10.0" />
</padding>
</CheckBox>
</children>
</VBox>
</children> </children>
</AnchorPane> </AnchorPane>
</content> </content>