Merge branch 'feature_json-task-db_M2' into feature_gardenplan-model_M2

# Conflicts:
#	src/main/java/ch/zhaw/gartenverwaltung/gardenplan/Gardenplanmodel.java
#	src/main/java/ch/zhaw/gartenverwaltung/io/JsonTaskDatabase.java
This commit is contained in:
Gian-Andrea Hutter 2022-10-31 13:23:02 +01:00
commit bc3ba43b7e
31 changed files with 1126 additions and 87 deletions

View File

@ -27,3 +27,6 @@ These branches are for bugfixes.
These branches are for javadoc and project documentation (such as the readme, class diagrams etc.).
## User Manual
- Search Plant List: if first Char is '#': only exact match in ID.

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -0,0 +1,7 @@
<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLPackage</id><coordinates><x>390</x><y>60</y><w>340</w><h>100</h></coordinates><panel_attributes>UI</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>180</y><w>460</w><h>120</h></coordinates><panel_attributes>Domain</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>330</y><w>460</w><h>120</h></coordinates><panel_attributes>Technical Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>90</y><w>100</w><h>60</h></coordinates><panel_attributes>Views (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>IO</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Jackson</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Types</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Models</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>90</y><w>110</w><h>60</h></coordinates><panel_attributes>Controllers (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Logging</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>JavaFX</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>220</y><w>110</w><h>60</h></coordinates><panel_attributes>Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>370</y><w>110</w><h>60</h></coordinates><panel_attributes>HTTP/API</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>150</y><w>90</w><h>70</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>70;10;10;50</additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>290</y><w>110</w><h>80</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>90;10;10;60</additional_attributes></element><element><id>Relation</id><coordinates><x>340</x><y>120</y><w>350</w><h>400</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>60;10;10;10;10;380;330;380;330;310</additional_attributes></element><element><id>Relation</id><coordinates><x>770</x><y>270</y><w>30</w><h>120</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>Relation</id><coordinates><x>360</x><y>250</y><w>60</w><h>180</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>40;10;10;10;10;160;40;160</additional_attributes></element><element><id>Relation</id><coordinates><x>610</x><y>120</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>10;10;50;10;50;100</additional_attributes></element></diagram>

View File

@ -10,9 +10,9 @@ import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
stage.setTitle("Hello!");
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("MainFXML.fxml"));
Scene scene = new Scene(fxmlLoader.load());
stage.setTitle("Gartenverwaltung");
stage.setScene(scene);
stage.show();
}

View File

@ -0,0 +1,5 @@
package ch.zhaw.gartenverwaltung;
public class HomeController
{
}

View File

@ -0,0 +1,105 @@
package ch.zhaw.gartenverwaltung;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.ResourceBundle;
public class MainFXMLController implements Initializable {
/**
* Caching the panes
*/
private final Map<String, Node> panes = new HashMap<>();
@FXML
private Button home_button;
@FXML
private AnchorPane mainPane;
@FXML
private Button myPlants_button;
@FXML
private Button mySchedule_button;
@FXML
private Button plants_button;
@FXML
void goToHome(ActionEvent event) throws IOException {
loadPane("Home.fxml");
styleChangeButton(home_button);
}
@FXML
void goToMyPlants(ActionEvent event) throws IOException {
loadPane("MyPlants.fxml");
styleChangeButton(myPlants_button);
}
@FXML
void goToMySchedule(ActionEvent event) throws IOException {
loadPane("MySchedule.fxml");
styleChangeButton(mySchedule_button);
}
@FXML
void goToPlants(ActionEvent event) throws IOException {
loadPane("Plants.fxml");
styleChangeButton(plants_button);
}
/**
* Updates the mainPane with the selected fxml file.
* set HGrow and VGrow to parent AnchorPane.
* Sends MainController to other Controllers.
* @param fxmlFile string of fxml file
* @throws IOException exception when file does not exist
*/
public void loadPane(String fxmlFile) throws IOException {
//ToDo HGrow and VGrow of new node
Node node = panes.get(fxmlFile);
System.out.println(node);
if (node == null) {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
node = loader.load();
panes.put(fxmlFile, node);
if(fxmlFile.equals("MyPlants.fxml")) {
MyPlantsController myPlantsController = loader.getController();
myPlantsController.getMainController(this);
}
}
mainPane.getChildren().setAll(node);
}
private void styleChangeButton(Button button) {
//ToDo changeStyle of the menu buttons
}
/**
* loads the default FXML File
* {@inheritDoc}
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
try {
loadPane("Home.fxml");
styleChangeButton(home_button);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,58 @@
package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.types.Plant;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
public class MyPlantsController implements Initializable {
MainFXMLController mainController;
@FXML
private Button addPlant_button;
@FXML
private VBox myPlants_vbox;
@FXML
void addPlant(ActionEvent event) throws IOException {
mainController.loadPane("Plants.fxml");
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
//ToDo
List<Plant> myPlants = getMyPlants();
createPlantView(myPlants);
}
private void createPlantView(List<Plant> myPlants) {
//ToDo
for(Plant plant : myPlants) {
createPlantView();
}
}
public void getMainController(MainFXMLController controller) {
mainController = controller;
}
private List<Plant> getMyPlants() {
//ToDo method to get myPlantList(scheduled)
//Method to call all Plants saved
List<Plant> myPlantList = new LinkedList<>();
return myPlantList;
}
private void createPlantView() {
//ToDo FXML Panel with Plant data
}
}

View File

@ -0,0 +1,124 @@
package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.types.Plant;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.Pane;
import java.net.URL;
import java.time.LocalDate;
import java.util.LinkedList;
import java.util.List;
import java.util.ResourceBundle;
public class MyScheduleController implements Initializable {
private Plant selectedPlant = null;
@FXML
private Label day1_label;
@FXML
private Pane day1_pane;
@FXML
private Label day2_label;
@FXML
private Pane day2_pane;
@FXML
private Label day3_label;
@FXML
private Pane day3_pane;
@FXML
private Label day4_label;
@FXML
private Pane day4_pane;
@FXML
private Label day5_label;
@FXML
private Pane day5_pane;
@FXML
private Label day6_label;
@FXML
private Pane day6_pane;
@FXML
private Label day7_label;
@FXML
private Pane day7_pane;
@FXML
private Label information_label;
@FXML
private ListView<Plant> scheduledPlants_listview;
@Override
public void initialize(URL location, ResourceBundle resources) {
List<Plant> plantList = new LinkedList<>();
fillListViewMyPlantsInSchedule(plantList);
getSelectedPlantTask();
setDayLabels();
information_label.setText("");
}
private void getSelectedPlantTask() {
scheduledPlants_listview.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Plant>() {
@Override
public void changed(ObservableValue<? extends Plant> observable, Plant oldValue, Plant newValue) {
if(newValue != null) {
selectedPlant = newValue;
//ToDo update day<x>_panel with task for the day
} else {
selectedPlant = null;
//ToDo update day<x>_panel with task for the day (all plants)
}
}
});
}
private void setDayLabels() {
LocalDate today = LocalDate.now();
day1_label.setText(today.getDayOfWeek().toString());
day2_label.setText(today.plusDays(1).getDayOfWeek().toString());
day3_label.setText(today.plusDays(2).getDayOfWeek().toString());
day4_label.setText(today.plusDays(3).getDayOfWeek().toString());
day5_label.setText(today.plusDays(4).getDayOfWeek().toString());
day6_label.setText(today.plusDays(5).getDayOfWeek().toString());
day7_label.setText(today.plusDays(6).getDayOfWeek().toString());
}
private void fillListViewMyPlantsInSchedule(List<Plant> list) {
for (Plant plant : list) {
scheduledPlants_listview.getItems().add(plant);
}
scheduledPlants_listview.setCellFactory(param -> new ListCell<Plant>() {
@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());
}
}
});
}
}

View File

@ -0,0 +1,215 @@
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 javafx.application.Platform;
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.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Bounds;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.ResourceBundle;
public class PlantsController implements Initializable {
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<Plant> plantListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
@FXML
private CheckBox autum_filter;
@FXML
private VBox climate_zones;
@FXML
private Label description_plant;
@FXML
private ImageView img_plant;
@FXML
private ListView<Plant> list_plants;
@FXML
private Button saveToMyPlant_button;
@FXML
private TextField search_plants;
@FXML
private CheckBox sommer_filter;
@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
void saveToMyPlant(ActionEvent event) {
//ToDo model save selectedPlant to mySelectedPlant(IO)
}
@FXML
void searchForPlant(KeyEvent event) {
viewFilteredListBySearch(search_plants.getText());
}
/**
* {@inheritDoc}
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
setListCellFactory();
try {
plantListProperty.addAll(plantListModel.getPlantList(DEFAULT_HARDINESS_ZONE));
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
list_plants.itemsProperty().bind(plantListProperty);
list_plants.getSelectionModel().selectedItemProperty()
.addListener((observable, oldPlant, newPlant) -> {
if (newPlant != null) {
img_plant.setImage(newPlant.image());
}
});
description_plant.setText("");
saveToMyPlant_button.setDisable(true);
createFilterHardinessZone();
lookForSelectedListEntry();
}
private void centerImage() {
//img_plant.setX(0.3);
//img_plant.setX(-100);
}
private void setListCellFactory() {
list_plants.setCellFactory(param -> new ListCell<Plant>() {
@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());
}
}
});
}
/**
* update the ListView according to the plant list provided
* Entry in ListView is plant name
* @param list plantList which fill the ListView
*/
private void fillListViewWithData(List<Plant> list) {
clearListView();
for (Plant plant : list) {
list_plants.getItems().add(plant);
}
}
private void viewFilteredListByFilters() {
boolean springValue = spring_filter.isSelected();
boolean sommerValue = sommer_filter.isSelected();
boolean autumValue = autum_filter.isSelected();
boolean winterValue = winter_filter.isSelected();
//ToDo getFilteredPlantList with (plantListModel.getFilteredPlantList(DEFAULT_HARDINESS_ZONE, <predicate>))
//List<Plant> plantList = new LinkedList<>();
//fillListViewWithData(plantList);
}
private void viewFilteredListBySearch(String query) {
//ToDo getFilteredPlantList with (plantListModel.getFilteredPlantList(DEFAULT_HARDINESS_ZONE, <predicate>))
try {
List<Plant> filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, query);
clearListView();
plantListProperty.addAll(filteredPlants);
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
}
private void createFilterHardinessZone() {
//ToDo create radioList of hardinessZone in VBox climate_zones
}
/**
* observes changes in the selectedProperty of ListView and updates the description label
*/
private void lookForSelectedListEntry() {
list_plants.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Plant>() {
@Override
public void changed(ObservableValue<? extends Plant> observable, Plant oldValue, Plant newValue) {
//ToDo
if(newValue != null) {
selectedPlant = newValue;
description_plant.setText(selectedPlant.description());
saveToMyPlant_button.setDisable(false);
//update img plant
} else {
selectedPlant = null;
description_plant.setText("");
saveToMyPlant_button.setDisable(true);
//update img when null placeholder PNG
}
}
});
}
/**
* clears the ListView of entries
*/
private void clearListView() {
plantListProperty.clear();
}
}

View File

@ -1,10 +1,13 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.json.PlantImageDeserializer;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.MonthDayDeserializer;
import javafx.scene.image.Image;
import java.io.IOException;
import java.net.URL;
@ -31,10 +34,14 @@ public class JsonPlantDatabase implements PlantDatabase {
* Creating constant objects required to deserialize the {@link MonthDay} classes
*/
private final static JavaTimeModule timeModule = new JavaTimeModule();
private final static SimpleModule imageModule = new SimpleModule();
static {
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("MM-dd");
MonthDayDeserializer dateDeserializer = new MonthDayDeserializer(dateFormat);
timeModule.addDeserializer(MonthDay.class, dateDeserializer);
imageModule.addDeserializer(Image.class, new PlantImageDeserializer());
}
/**
@ -75,8 +82,9 @@ public class JsonPlantDatabase implements PlantDatabase {
}
if (dataSource != null) {
currentZone = zone;
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(timeModule);
ObjectMapper mapper = new ObjectMapper()
.registerModule(timeModule)
.registerModule(imageModule);
List<Plant> result;
result = mapper.readerForListOf(Plant.class).readValue(dataSource);

View File

@ -9,6 +9,7 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@ -25,6 +26,7 @@ import java.util.Map;
public class JsonTaskDatabase implements TaskDatabase{
IdProvider idProvider;
private final URL dataSource = getClass().getResource("taskdb.json");
private final static String INVALID_DATASOURCE_MSG = "Invalid datasource specified!";
private Map<Long, Task> taskMap = Collections.emptyMap();
@ -35,9 +37,10 @@ public class JsonTaskDatabase implements TaskDatabase{
static {
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDateDeserializer dateDeserializer = new LocalDateDeserializer(dateFormat);
//TODO Serializer
LocalDateSerializer dateSerializer = new LocalDateSerializer(dateFormat);
timeModule.addDeserializer(LocalDate.class, dateDeserializer);
timeModule.addSerializer(LocalDate.class, dateSerializer);
}
/**
@ -98,12 +101,16 @@ public class JsonTaskDatabase implements TaskDatabase{
* @throws IOException If the database cannot be accessed
*/
private void writeTaskListToFile() throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(timeModule)
.registerModule(new Jdk8Module());
if(dataSource != null) {
mapper.writeValue(new File(dataSource.getFile()), taskMap);
try {
new ObjectMapper()
.registerModule(timeModule)
.registerModule(new Jdk8Module())
.writeValue(new File(dataSource.toURI()), taskMap.values());
} catch (URISyntaxException e) {
throw new IOException(INVALID_DATASOURCE_MSG, e);
}
}
}
@ -115,7 +122,8 @@ public class JsonTaskDatabase implements TaskDatabase{
private void loadTaskListFromFile() throws IOException {
if (dataSource != null) {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(timeModule);
mapper.registerModule(timeModule)
.registerModule(new Jdk8Module());
List<Task> result;
result = mapper.readerForListOf(Task.class).readValue(dataSource);

View File

@ -17,11 +17,12 @@ public class GrowthPhaseTypeDeserializer extends StdDeserializer<GrowthPhaseType
@Override
public GrowthPhaseType deserialize(JsonParser parser, DeserializationContext context) throws IOException {
GrowthPhaseType result = null;
String token = parser.getText();
try {
result = GrowthPhaseType.valueOf(parser.getText().toUpperCase());
result = GrowthPhaseType.valueOf(token.toUpperCase());
} catch (IllegalArgumentException e) {
// TODO: Log
System.err.println("bad growth phase type");
System.err.printf("Bad growth phase type \"%s\"\n", token);
}
return result;
}

View File

@ -18,11 +18,12 @@ public class HardinessZoneDeserializer extends StdDeserializer<HardinessZone> {
@Override
public HardinessZone deserialize(JsonParser parser, DeserializationContext context) throws IOException {
HardinessZone result = null;
String token = parser.getText();
try {
result = HardinessZone.valueOf(parser.getText().toUpperCase());
result = HardinessZone.valueOf(token.toUpperCase());
} catch (IllegalArgumentException e) {
// TODO: Log
System.err.println("bad growth phase type");
System.err.printf("Unknown Hardiness Zone \"%s\"\n", token);
}
return result;
}

View File

@ -0,0 +1,33 @@
package ch.zhaw.gartenverwaltung.json;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import javafx.scene.image.Image;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
public class PlantImageDeserializer extends JsonDeserializer<Image> {
@Override
public Image deserialize(JsonParser parser, DeserializationContext context) throws IOException {
Image result = null;
URL imageUrl = PlantDatabase.class.getResource(String.format("images/%s", parser.getText()));
if (imageUrl != null) {
try (InputStream is = new FileInputStream(new File(imageUrl.toURI()))) {
result = new Image(is);
} catch (IllegalArgumentException | URISyntaxException e) {
// TODO: Log
e.printStackTrace();
System.err.printf("Cannot find Image \"%s\"\n", imageUrl.getFile());
}
}
return result;
}
}

View File

@ -3,14 +3,17 @@ package ch.zhaw.gartenverwaltung.plantList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonPlantDatabase;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import java.io.IOException;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class PlantListModel {
private PlantDatabase plantDatabase;
@ -19,8 +22,8 @@ public class PlantListModel {
/**
* Comparators to create sorted Plant List
*/
static final Comparator<Plant> sortByName = (Plant o1, Plant o2) -> o1.name().compareTo(o2.name());
static final Comparator<Plant> SortById = (Plant o1, Plant o2) -> Long.compare(o1.id(), o2.id());
static final Comparator<Plant> sortByName = Comparator.comparing(Plant::name);
static final Comparator<Plant> SortById = Comparator.comparingLong(Plant::id);
/**
* Constructor to create Database Object.
@ -30,12 +33,12 @@ public class PlantListModel {
setDefaultZone();
}
public PlantListModel(PlantDatabase plantDatabase){
public PlantListModel(PlantDatabase plantDatabase) {
this.plantDatabase = plantDatabase;
setDefaultZone();
}
private void setDefaultZone(){
private void setDefaultZone() {
currentZone = HardinessZone.ZONE_8A; // TODO: get Default Zone from Config
}
@ -49,6 +52,7 @@ public class PlantListModel {
/**
* Method to get actual Plant List in alphabetic Order
*
* @return actual Plant List in alphabetic Order
*/
public List<Plant> getPlantList(HardinessZone zone) throws HardinessZoneNotSetException, IOException {
@ -59,36 +63,39 @@ public class PlantListModel {
/**
* Method to get the actual Plant list in custom Order
* @param zone selected hardiness zone
*
* @param zone selected hardiness zone
* @param comparator comparator to sort the list
* @return sorted list with plants in the given hardiness zone
* @throws IOException If the database cannot be accessed
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getSortedPlantList(HardinessZone zone, Comparator<Plant> comparator) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
return plantDatabase.getPlantList(zone).stream().sorted(comparator).toList();
return plantDatabase.getPlantList(zone).stream().sorted(comparator).collect(Collectors.toList());
}
/**
* Method to get Filtered plant list
*
* @param predicate predicate to filter the list
* @param zone selected hardiness zone
* @param zone selected hardiness zone
* @return filterd list with plants in the hardinness zone
* @throws IOException If the database cannot be accessed
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getFilteredPlantList(HardinessZone zone, Predicate<Plant> predicate) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
return getPlantList(zone).stream().filter(predicate).toList();
return getPlantList(zone).stream().filter(predicate).collect(Collectors.toList());
}
/**
* Method to get Filtered plant list by id by exact match
*
* @param zone selected hardiness zone
* @param id id of plant
* @param id id of plant
* @return if id doesn't exist: empty List, else list with 1 plant entry.
* @throws IOException If the database cannot be accessed
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getFilteredPlantListById(HardinessZone zone, Long id) throws HardinessZoneNotSetException, IOException {
@ -97,4 +104,67 @@ public class PlantListModel {
plantDatabase.getPlantById(zone, id).ifPresent(plantList::add);
return plantList;
}
/**
* @param zone selected hardiness zone
* @param searchString the string to search plant List, set '#' as first char the search by id.
* @return List of plants found in Plant List which contain the search String in the name or description
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
* @throws IOException If the database cannot be accessed
*/
public List<Plant> getFilteredPlantListByString(HardinessZone zone, String searchString) throws HardinessZoneNotSetException, IOException {
if (searchString.length() == 0) {
return getPlantList(zone);
} else if (searchString.charAt(0) == '#') {
try {
return getFilteredPlantListById(zone, Long.parseLong(searchString.substring(1)));
} catch (NumberFormatException e) {
return new ArrayList<>();
}
} else {
String caseInsensitiveSearchString = searchString.toLowerCase();
return getFilteredPlantList(zone, plant ->
plant.name().toLowerCase().contains(caseInsensitiveSearchString) ||
plant.description().toLowerCase().contains(caseInsensitiveSearchString)
);
}
}
/**
* @param type GrowPhaseType to filter
* @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
*/
private List<Plant> getFilteredPlantListBySaison(GrowthPhaseType type, 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) && growthPhase.type() == type));
}
/**
* @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> getFilteredPlantListByPlantingSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantListBySaison(GrowthPhaseType.PLANT, 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> getFilteredPlantListByHarvestSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantListBySaison(GrowthPhaseType.HARVEST, zone, from, to);
}
}

View File

@ -1,7 +1,10 @@
package ch.zhaw.gartenverwaltung.types;
import javafx.scene.image.Image;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
import static java.time.temporal.ChronoUnit.DAYS;
@ -9,6 +12,7 @@ public record Plant(
long id,
String name,
String description,
Image image,
String spacing,
int light,
String soil,
@ -22,7 +26,7 @@ public record Plant(
public List<GrowthPhase> lifecycleForGroup(int group) {
return lifecycle.stream()
.filter(growthPhase -> growthPhase.group() != group)
.toList();
.collect(Collectors.toList());
}
public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) {

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="729.0" prefWidth="1060.0"
xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.HomeController">
<children>
<VBox layoutX="75.0" layoutY="73.0" prefHeight="729.0" prefWidth="1060.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label text="Gartenverwaltung">
<font>
<Font size="34.0" />
</font>
</Label>
<Label prefHeight="106.0" prefWidth="1040.0" text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." wrapText="true" />
<Label text="Tutorial">
<font>
<Font name="System Bold" size="18.0" />
</font>
</Label>
<Pane prefHeight="200.0" prefWidth="200.0">
<children>
<VBox prefHeight="200.0" prefWidth="1040.0">
<children>
<Label text="Task 1" wrapText="true" />
<Label text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." wrapText="true" />
</children>
</VBox>
</children>
</Pane>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
</children>
</AnchorPane>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="938.0" prefWidth="1110.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.MainFXMLController">
<children>
<HBox maxWidth="35.0" minHeight="35.0" prefHeight="38.0" prefWidth="1110.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button fx:id="home_button" mnemonicParsing="false" onAction="#goToHome" prefHeight="38.0" prefWidth="121.0" text="Home" HBox.hgrow="NEVER" />
<Button fx:id="plants_button" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#goToPlants" prefHeight="38.0" prefWidth="121.0" text="Plants" />
<Button fx:id="myPlants_button" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#goToMyPlants" prefHeight="38.0" prefWidth="121.0" text="MyPlants" />
<Button fx:id="mySchedule_button" layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#goToMySchedule" prefHeight="38.0" prefWidth="121.0" text="MySchedule" />
<Pane maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" />
</children>
</HBox>
<AnchorPane fx:id="mainPane" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="35.0" />
</children>
</AnchorPane>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<?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.MyPlantsController">
<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">
<children>
<Label text="MyPlants">
<font>
<Font name="System Bold" size="28.0" />
</font>
<VBox.margin>
<Insets bottom="10.0" />
</VBox.margin>
</Label>
<VBox fx:id="myPlants_vbox" prefHeight="200.0" prefWidth="100.0" VBox.vgrow="ALWAYS" />
<Button fx:id="addPlant_button" mnemonicParsing="false" onAction="#addPlant" prefHeight="45.0" prefWidth="155.0" text="Add new Plant">
<VBox.margin>
<Insets top="10.0" />
</VBox.margin>
</Button>
</children>
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
</padding>
</VBox>
</children>
</AnchorPane>

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="572.0" prefWidth="867.0"
xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.MyScheduleController">
<children>
<Label layoutX="14.0" layoutY="14.0" text="MySchedule">
<font>
<Font size="24.0" />
</font>
</Label>
<HBox layoutY="31.0" prefHeight="541.0" prefWidth="867.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="50.0">
<children>
<ListView fx:id="scheduledPlants_listview" maxWidth="1.7976931348623157E308" prefHeight="522.0" prefWidth="365.0" HBox.hgrow="NEVER" />
<VBox maxWidth="1.7976931348623157E308" prefHeight="537.0" prefWidth="650.0" HBox.hgrow="ALWAYS">
<children>
<GridPane alignment="CENTER_LEFT" gridLinesVisible="true" maxWidth="1.7976931348623157E308" prefHeight="403.0" prefWidth="575.0" VBox.vgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints fillWidth="false" hgrow="NEVER" maxWidth="278.0" minWidth="100.0" prefWidth="173.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="10.0" prefWidth="402.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Label fx:id="day1_label" alignment="CENTER" prefHeight="32.0" prefWidth="173.0" text="Label" />
<Label fx:id="day2_label" alignment="CENTER" prefHeight="29.0" prefWidth="173.0" text="Label" GridPane.rowIndex="1" />
<Label fx:id="day3_label" alignment="CENTER" prefHeight="32.0" prefWidth="172.0" text="Label" GridPane.rowIndex="2" />
<Label fx:id="day4_label" alignment="CENTER" prefHeight="35.0" prefWidth="173.0" text="Label" GridPane.rowIndex="3" />
<Label fx:id="day5_label" alignment="CENTER" prefHeight="31.0" prefWidth="173.0" text="Label" GridPane.rowIndex="4" />
<Label fx:id="day6_label" alignment="CENTER" prefHeight="31.0" prefWidth="173.0" text="Label" GridPane.rowIndex="5" />
<Label fx:id="day7_label" alignment="CENTER" prefHeight="35.0" prefWidth="173.0" text="Label" GridPane.rowIndex="6" />
<Pane fx:id="day1_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" />
<Pane fx:id="day2_pane" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Pane fx:id="day3_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Pane fx:id="day4_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Pane fx:id="day5_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Pane fx:id="day6_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="5" />
<Pane fx:id="day7_pane" prefHeight="200.0" prefWidth="200.0" GridPane.columnIndex="1" GridPane.rowIndex="6" />
</children>
</GridPane>
<Pane prefHeight="119.0" prefWidth="575.0" VBox.vgrow="NEVER">
<children>
<Label alignment="TOP_LEFT" layoutX="14.0" layoutY="14.0" prefHeight="17.0" prefWidth="550.0" text="Importants Information:" wrapText="true">
<font>
<Font name="System Bold" size="12.0" />
</font>
</Label>
<Label fx:id="information_label" alignment="TOP_LEFT" layoutX="14.0" layoutY="31.0" maxWidth="1.7976931348623157E308" prefHeight="82.0" prefWidth="550.0" text="Label" wrapText="true" />
</children>
</Pane>
</children>
</VBox>
</children>
</HBox>
</children>
</AnchorPane>

View File

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.geometry.Rectangle2D?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<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" fx:controller="ch.zhaw.gartenverwaltung.PlantsController">
<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">
<items>
<AnchorPane maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<children>
<VBox maxWidth="1.7976931348623157E308" prefHeight="850.6666666666666" prefWidth="894.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label prefHeight="45.0" prefWidth="903.0" text="Plants">
<font>
<Font name="System Bold" size="30.0" />
</font>
</Label>
<TextField fx:id="search_plants" onKeyTyped="#searchForPlant" promptText="Search for Plant Name" />
<HBox alignment="CENTER_LEFT" prefHeight="480.0" prefWidth="881.0" VBox.vgrow="ALWAYS">
<children>
<ListView fx:id="list_plants" maxWidth="1.7976931348623157E308" prefHeight="497.0" prefWidth="580.0" HBox.hgrow="ALWAYS" />
<ImageView fx:id="img_plant" fitHeight="322.0" fitWidth="861.0" pickOnBounds="true" preserveRatio="true" HBox.hgrow="NEVER">
<viewport>
<Rectangle2D height="300.0" width="300.0" />
</viewport>
<image>
<Image url="@placeholder.png" />
</image>
</ImageView>
</children>
</HBox>
<Label prefHeight="33.0" prefWidth="919.0" text="Plant Information:">
<font>
<Font name="System Bold" size="12.0" />
</font>
<padding>
<Insets top="15.0" />
</padding>
</Label>
<Label fx:id="description_plant" alignment="TOP_LEFT" maxWidth="1.7976931348623157E308" prefHeight="194.0" prefWidth="893.0" text="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." textAlignment="JUSTIFY" wrapText="true">
<padding>
<Insets bottom="10.0" top="10.0" />
</padding>
</Label>
<Button fx:id="saveToMyPlant_button" alignment="CENTER" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#saveToMyPlant" prefHeight="38.0" prefWidth="917.0" text="Save to MyPlants" />
</children>
</VBox>
</children>
</AnchorPane>
<AnchorPane maxWidth="300.0" minHeight="0.0" minWidth="300.0" prefHeight="160.0" prefWidth="100.0">
<children>
<VBox layoutX="38.0" layoutY="100.0" prefHeight="850.6666666666666" prefWidth="316.6666666666667" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Label text="Filter">
<font>
<Font name="System Bold" size="17.0" />
</font>
</Label>
<TitledPane animated="false" text="Saison">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<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">
<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>
</AnchorPane>
</content>
</TitledPane>
<TitledPane animated="false" text="Climate Zones">
<content>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
<children>
<VBox fx:id="climate_zones" layoutX="36.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>
</AnchorPane>
</content>
</TitledPane>
</children>
</VBox>
</children>
</AnchorPane>
</items>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</SplitPane>
</children>
</AnchorPane>

View File

@ -0,0 +1,5 @@
Potato, Onion
Photos by Lars Blankers: https://unsplash.com/@lmablankers?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText
Carrot
Photo by Maja Vujic: https://unsplash.com/@majavujic87?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -6,6 +6,7 @@
"light": 6,
"spacing": "35",
"soil": "sandy",
"image": "potato.jpg",
"pests": [
{
"name": "Rot",
@ -86,6 +87,7 @@
"id": 1,
"name": "Early Carrot",
"description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
"image": "carrot.jpg",
"lifecycle": [
{
"startDate": "02-20",
@ -167,6 +169,7 @@
"id": 2,
"name": "Summertime Onion",
"description": "Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
"image": "onion.jpg",
"lifecycle": [
{
"startDate": "03-15",

View File

@ -1,50 +1,50 @@
[
{
"id" : 1,
"name" : "sow plant",
"description": "Plant the seeds, crops in de bed.",
"startDate" : "2022-05-01",
"endDate" : "2022-05-01",
"interval" : 0
"id": 1,
"name": "sow plant",
"description": "Plant the seeds, crops in de bed.",
"startDate": "2022-05-01",
"endDate": "2022-05-01",
"interval": 0
},
{
"id" : 2,
"name" : "water plant",
"id": 2,
"name": "water plant",
"description": "water the plant, so that the soil is wet around the plant.",
"startDate" : "2022-05-01",
"endDate" : "2022-09-01",
"interval" : 2
"startDate": "2022-05-01",
"endDate": "2022-09-01",
"interval": 2
},
{
"id" : 3,
"name" : "fertilize plant",
"id": 3,
"name": "fertilize plant",
"description": "The fertilizer has to be mixed with water. Then fertilize the plants soil with the mixture",
"startDate" : "2022-06-01",
"endDate" : "2022-08-01",
"interval" : 28
"startDate": "2022-06-01",
"endDate": "2022-08-01",
"interval": 28
},
{
"id" : 4,
"name" : "covering plant",
"id": 4,
"name": "covering plant",
"description": "Take a big enough coverage for the plants. Cover the whole plant with a bit space between the plant and the coverage",
"startDate" : "2022-07-01",
"endDate" : "2022-07-01",
"interval" : 0
"startDate": "2022-07-01",
"endDate": "2022-07-01",
"interval": 0
},
{
"id" : 5,
"name" : "look after plant",
"id": 5,
"name": "look after plant",
"description": "Look for pest or illness at the leaves of the plant. Check the soil around the plant, if the roots are enough covered with soil",
"startDate" : "2022-05-01",
"endDate" : "2022-09-01",
"interval" : 5
"startDate": "2022-05-01",
"endDate": "2022-09-01",
"interval": 5
},
{
"id" : 6,
"name" : "harvest plant",
"id": 6,
"name": "harvest plant",
"description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ",
"startDate" : "2022-09-01",
"endDate" : "2022-09-01",
"interval" : 0
"startDate": "2022-09-01",
"endDate": "2022-09-01",
"interval": 0
}
]
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -30,9 +30,7 @@ public class JsonPlantDatabaseTest {
List<Plant> testList;
try {
testList = testDatabase.getPlantList(HardinessZone.ZONE_8A);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (HardinessZoneNotSetException e) {
} catch (IOException | HardinessZoneNotSetException e) {
throw new RuntimeException(e);
}
Assertions.assertEquals(3, testList.size());
@ -47,11 +45,8 @@ public class JsonPlantDatabaseTest {
void getPlantById() {
Optional<Plant> testPlant;
try {
testDatabase.getPlantList(HardinessZone.ZONE_8A);
testPlant = testDatabase.getPlantById(1);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (HardinessZoneNotSetException e) {
testPlant = testDatabase.getPlantById(HardinessZone.ZONE_8A,1);
} catch (IOException | HardinessZoneNotSetException e) {
throw new RuntimeException(e);
}
Assertions.assertTrue(testPlant.isPresent());
@ -63,11 +58,8 @@ public class JsonPlantDatabaseTest {
void getPlantByIdMustFail() {
Optional<Plant> testPlant;
try {
testDatabase.getPlantList(HardinessZone.ZONE_8A);
testPlant = testDatabase.getPlantById(99);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (HardinessZoneNotSetException e) {
testPlant = testDatabase.getPlantById(HardinessZone.ZONE_8A,99);
} catch (IOException | HardinessZoneNotSetException e) {
throw new RuntimeException(e);
}
Assertions.assertFalse(testPlant.isPresent());

View File

@ -6,32 +6,80 @@ import org.junit.jupiter.api.*;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Optional;
public class JsonTaskDatabaseTest {
TaskDatabase testDatabase;
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
@BeforeEach
void connectToDb() {
// testDatabase = new JsonTaskDatabase();
testDatabase = new JsonTaskDatabase();
}
@Test
@DisplayName("Check if results are retrieved completely")
void getTasks(){
/*
List<Task> taskList=null;
try {
taskList = testDatabase.getTaskList(formatter.parse("01.05.2022"), formatter.parse("01.08.2022"));
taskList = testDatabase.getTaskList(LocalDate.parse("30.04.2022",formatter),
LocalDate.parse("31.05.2022",formatter));
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ParseException e) {
throw new RuntimeException(e);
}
Assertions.assertTrue(taskList.size()>0);
*/
Assertions.assertEquals(3,taskList.size());
}
//@Disabled("disabled until idProvider works")
@Test
@DisplayName("Add task.")
void addTask(){
Task task = new Task("Testtask","This is a test Task.",LocalDate.parse("01.05.2022",formatter));
try {
testDatabase.saveTask(task);
List<Task> taskList=null;
try {
taskList = testDatabase.getTaskList(LocalDate.parse("30.04.2022",formatter),
LocalDate.parse("31.05.2022",formatter));
} catch (IOException e) {
throw new RuntimeException(e);
}
Assertions.assertEquals(4,taskList.size());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Test
@DisplayName("Remove task.")
void removeTask(){
Task task = new Task("Dummy","Dummy",LocalDate.parse("31.05.2022",formatter)).withId(2);
try {
testDatabase.removeTask(task);
List<Task> taskList=null;
try {
taskList = testDatabase.getTaskList(LocalDate.parse("30.04.2022",formatter),
LocalDate.parse("31.05.2022",formatter));
} catch (IOException e) {
throw new RuntimeException(e);
}
Assertions.assertEquals(2,taskList.size());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -3,14 +3,14 @@ package ch.zhaw.gartenverwaltung.plantList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonPlantDatabase;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@ -43,31 +43,39 @@ class PlantListModelTest {
20,
"summertime onion",
"Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
null,
"15,30,2",
0,
"sandy to loamy, loose soil, free of stones",
new ArrayList<>(),
new ArrayList<>())
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
examplePlantList.add(new Plant(
0,
"Potato",
"The potato is a tuber, round or oval, with small white roots called 'eyes', that are growth buds. The size varies depending on the variety; the colour of the skin can be white, yellow or even purple.",
null,
"35",
6,
"sandy",
new ArrayList<>(),
new ArrayList<>())
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
examplePlantList.add(new Plant(
1,
"Early Carrot",
"Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
null,
"5,35,2.5",
0,
"sandy to loamy, loose soil, free of stones",
new ArrayList<>(),
new ArrayList<>())
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
}
@ -146,4 +154,46 @@ class PlantListModelTest {
assertEquals(1, plantListResult.size());
assertEquals(examplePlantList.get(0), plantListResult.get(0));
}
@Test
void getFilteredPlantListByString() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "#2");
assertEquals(0, plantListResult.size());
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "#20");
assertEquals(1, plantListResult.size());
assertEquals(examplePlantList.get(0), plantListResult.get(0));
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "#a2");
assertEquals(0, plantListResult.size());
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "onion");
assertEquals(1, plantListResult.size());
assertEquals(examplePlantList.get(0), plantListResult.get(0));
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "white roots");
assertEquals(1, plantListResult.size());
assertEquals(examplePlantList.get(1), plantListResult.get(0));
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "apple");
assertEquals(0, plantListResult.size());
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "");
assertEquals(3, plantListResult.size());
}
@Test
void getFilteredPlantListByPlantingSaison() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListByPlantingSaison(HardinessZone.ZONE_8A, MonthDay.of(4, 4), MonthDay.of(8, 4));
assertEquals(2, plantListResult.size());
assertEquals(examplePlantList.get(2), plantListResult.get(0));
assertEquals(examplePlantList.get(1), plantListResult.get(1));
}
@Test
void getFilteredPlantListByHarvestSaison() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListByHarvestSaison(HardinessZone.ZONE_8A, MonthDay.of(4, 4), MonthDay.of(8, 4));
assertEquals(2, plantListResult.size());
assertEquals(examplePlantList.get(1), plantListResult.get(0));
assertEquals(examplePlantList.get(0), plantListResult.get(1));
}
}