Compare commits

..
Author SHA1 Message Date
Gian-Andrea Hutter 2cb64f3dee Merge branch 'dev' into feature_gardenplan-model_M2 2022-11-02 13:10:06 +01:00
Gian-Andrea Hutter b1e4e51d68 #27 gardenplanmodelTest first version implemented 2022-11-02 13:08:23 +01:00
Gian-Andrea Hutter 9e14920fbb #27 gardenplanmodel fully implemented 2022-11-01 10:33:07 +01:00
Gian-Andrea Hutter 0987b42086 Merge remote-tracking branch 'origin/feature_taskList_m2' into feature_gardenplan-model_M2
# Conflicts:
#	src/main/resources/ch/zhaw/gartenverwaltung/io/taskdb.json
2022-10-31 14:32:33 +01:00
schrom01 d1d9d11b66 added Methods in TaskListModel
added Field Crop ID in Task
added method removeTasksforCrop
2022-10-31 14:30:42 +01:00
Gian-Andrea Hutter 521f3ae025 Merge remote-tracking branch 'origin/feature_taskList_m2' into feature_gardenplan-model_M2 2022-10-31 14:28:06 +01:00
Gian-Andrea Hutter 52b4b1c01d Merge remote-tracking branch 'origin/feature_taskList_m2' into feature_gardenplan-model_M2 2022-10-31 13:47:38 +01:00
schrom01 007fc81b22 added Method planTasksForCrop 2022-10-31 13:47:17 +01:00
Gian-Andrea Hutter bc3ba43b7e 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
2022-10-31 13:23:02 +01:00
Gian-Andrea Hutter 2e12c3f868 Merge remote-tracking branch 'origin/feature_json-task-db_M2' into feature_json-task-db_M2 2022-10-31 13:19:31 +01:00
Gian-Andrea Hutter 29ad2fdae2 #17 Bug Mismatchexception fixed 2022-10-31 13:19:14 +01:00
giavaphiandGitHub Enterprise 7a6a0eb66f Merge pull request #45 from schrom01/feature_controllerPlantList_M2
Plant Controller Filter to hardiness zone and season
2022-10-31 13:07:49 +01:00
gulerdavandGitHub Enterprise 3afeb8a22d Merge branch 'dev' into feature_controllerPlantList_M2 2022-10-31 13:05:49 +01:00
gulerdavandGitHub Enterprise 88f9bf7990 Merge pull request #44 from schrom01/feature_plantlist-gui_M2
Display images in gui and fix image deserialise with spaces
2022-10-31 12:59:06 +01:00
Elias Csomor 5c6528a038 Update JsonTaskDatabaseTest.java 2022-10-31 12:54:52 +01:00
giavaphi 5f35d99839 fixed merge conflict PlantsController 2022-10-31 12:52:27 +01:00
Gian-Andrea Hutter afac3ba855 #17 Serialization implemented 2022-10-31 12:45:24 +01:00
Gian-Andrea Hutter a87f3da9d2 Merge branch 'feature_plantlist-gui_M2' into feature_json-task-db_M2 2022-10-31 12:43:43 +01:00
Gian-Andrea Hutter 6273b0e59a #27 implementation of task template with task generation 2022-10-31 12:24:54 +01:00
Elias Csomor 2510608117 Extended taskDb tests 2022-10-31 11:55:20 +01:00
giavaphi 5b039eb762 #12 small changes and java doc 2022-10-31 09:23:44 +01:00
Gian-Andrea Hutter b79387abc2 Merge branch 'dev' into feature_json-task-db_M2 2022-10-31 08:40:52 +01:00
schrom01 25057d34f0 created Class TaskListModel 2022-10-31 08:06:35 +01:00
Gian-Andrea Hutter 63d7eddff4 #27 first implemention of the Gardenplanmodel 2022-10-30 23:34:42 +01:00
giavaphi c83b8695ab #12 PlantsController filter list view 2022-10-30 23:23:19 +01:00
giavaphi f22ef61d3c #42 bug resize window fix 2022-10-30 18:06:18 +01:00
15 changed files with 569 additions and 144 deletions
@@ -19,7 +19,7 @@ public class MainFXMLController implements Initializable {
/**
* Caching the panes
*/
private final Map<String, Node> panes = new HashMap<>();
private final Map<String, AnchorPane> panes = new HashMap<>();
@FXML
private Button home_button;
@@ -68,20 +68,22 @@ public class MainFXMLController implements Initializable {
* @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) {
AnchorPane anchorPane = panes.get(fxmlFile);
if (anchorPane == null) {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
node = loader.load();
panes.put(fxmlFile, node);
anchorPane = loader.load();
panes.put(fxmlFile, anchorPane);
if(fxmlFile.equals("MyPlants.fxml")) {
MyPlantsController myPlantsController = loader.getController();
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) {
@@ -4,6 +4,7 @@ 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.application.Platform;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
@@ -13,8 +14,10 @@ import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Bounds;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
@@ -30,10 +33,11 @@ public class PlantsController implements Initializable {
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;
private VBox seasons;
@FXML
private VBox climate_zones;
@@ -53,81 +57,44 @@ public class PlantsController implements Initializable {
@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
}
/**
* saves the current selected plant in new JSON database
* @param event event
*/
@FXML
void saveToMyPlant(ActionEvent event) {
//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}
*/
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
setListCellFactory();
try {
plantListProperty.addAll(plantListModel.getPlantList(DEFAULT_HARDINESS_ZONE));
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
fillPlantListWithHardinessZone();
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);
createFilterSeasons();
createFilterHardinessZone();
lookForSelectedListEntry();
try {
viewFilteredListBySearch();
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
}
private void centerImage() {
//img_plant.setX(0.3);
//img_plant.setX(-100);
}
/**
* set text of list view to plant name
*/
private void setListCellFactory() {
list_plants.setCellFactory(param -> new ListCell<Plant>() {
@Override
@@ -144,62 +111,138 @@ public class PlantsController implements Initializable {
}
/**
* update the ListView according to the plant list provided
* Entry in ListView is plant name
* @param list plantList which fill the ListView
* 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 fillListViewWithData(List<Plant> list) {
private void viewFilteredListBySeason(Seasons season) throws HardinessZoneNotSetException, IOException {
clearListView();
for (Plant plant : list) {
list_plants.getItems().add(plant);
}
plantListProperty.addAll(plantListModel.getFilteredPlantListBySaisonWithoutGrowthPhase(plantListModel.getCurrentZone(), season.getStartDate(), season.getEndDate()));
}
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);
/**
* 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<Plant> filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, newValue);
clearListView();
plantListProperty.addAll(filteredPlants);
} catch (HardinessZoneNotSetException | IOException e) {
e.printStackTrace();
}
}
});
}
private void viewFilteredListBySearch(String query) {
//ToDo getFilteredPlantList with (plantListModel.getFilteredPlantList(DEFAULT_HARDINESS_ZONE, <predicate>))
/**
* get plant list of current hardiness zone
* fill list view with plant list
*/
private void fillPlantListWithHardinessZone() {
try {
List<Plant> filteredPlants = plantListModel.getFilteredPlantListByString(DEFAULT_HARDINESS_ZONE, query);
clearListView();
plantListProperty.addAll(filteredPlants);
plantListProperty.addAll(plantListModel.getPlantList(plantListModel.getCurrentZone()));
} catch (HardinessZoneNotSetException | IOException e) {
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() {
//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() {
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
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 {
selectedPlant = null;
description_plant.setText("");
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);
}
}
});
@@ -1,8 +1,92 @@
package ch.zhaw.gartenverwaltung.gardenplan;
import ch.zhaw.gartenverwaltung.io.GardenPlan;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonGardenPlan;
import ch.zhaw.gartenverwaltung.taskList.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.taskList.TaskListModel;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* The Gardenplan model manages the crops in the gardenplan.
*/
public class Gardenplanmodel {
// private JasonGardenplan gardenplan;
// liste von crops
//task generieren
//plant holen, task template mit tasktemplateklasse tasks erstellen
private GardenPlan gardenPlan;
private List<Crop> cropList;
private TaskListModel taskListModel;
/**
* Constructor of Gardenplan model
*
* @param taskListModel holds a reference to the task list object.
*/
public Gardenplanmodel(TaskListModel taskListModel) throws IOException {
this.taskListModel = taskListModel;
gardenPlan = new JsonGardenPlan();
cropList = new ArrayList<>();
cropList = gardenPlan.getCrops();
}
/**
* Creates a Crop with a {@link Plant} and the planting date of the plant. Then let the Tasklistmodel create the
* gardening {@link Task} for the crop. Store the crop in the gardenplan file and the cache.
*
* @param plant The plant which is wnated to be planted
* @param plantingDate The date, when the plant is planted
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If the hardinesszone could not be added
* @throws PlantNotFoundException If the plant is not found in the database.
*/
public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
Crop crop = new Crop(plant.id(),plantingDate);
//TODO Add Area to Plant
//crop.withArea(0);
gardenPlan.saveCrop(crop);
taskListModel.planTasksForCrop(crop);
cropList = gardenPlan.getCrops();
}
/**
* Removes a {@link Crop} from the file and the cache
*
* @param crop The plant which is wnated to be planted
* @throws IOException If the database cannot be accessed
*/
public void removeCrop(Crop crop) throws IOException {
gardenPlan.removeCrop(crop);
taskListModel.removeTasksForCrop(crop);
cropList = gardenPlan.getCrops();
}
/**
* Returns a list of {@link Crop}s which are currently in the gardenplan.
*
* @throws IOException If the database cannot be accessed
*/
public List<Crop> getCrops() throws IOException {
if(!cropList.isEmpty()){
cropList = gardenPlan.getCrops();
}
return cropList;
}
/**
* Returns an Optional of {@link Crop} if the crop is the gardenplan
*
* @param cropId The date, when the plant is planted
* @throws IOException If the database cannot be accessed
*/
public Optional<Crop> getCrop(Long cropId) throws IOException {
return gardenPlan.getCropById(cropId);
}
}
@@ -18,11 +18,11 @@ public interface GardenPlan {
/**
* Attempts to retrieve the {@link Crop} with the specified cropId.
*
* @param id The {@link Crop#cropId} to look for
* @param cropId The {@link Crop} to look for
* @return {@link Optional} of the found {@link Crop}, {@link Optional#empty()} if no entry matched the criteria
* @throws IOException If there is a problem reading from or writing to the database
*/
Optional<Crop> getCropById(long id) throws IOException;
Optional<Crop> getCropById(long cropId) throws IOException;
/**
* Saves a Crop to the Database.
@@ -1,13 +1,16 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Task;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
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;
@@ -24,6 +27,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();
@@ -34,7 +38,10 @@ public class JsonTaskDatabase implements TaskDatabase{
static {
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDateDeserializer dateDeserializer = new LocalDateDeserializer(dateFormat);
LocalDateSerializer dateSerializer = new LocalDateSerializer(dateFormat);
timeModule.addDeserializer(LocalDate.class, dateDeserializer);
timeModule.addSerializer(LocalDate.class, dateSerializer);
}
/**
@@ -51,6 +58,16 @@ public class JsonTaskDatabase implements TaskDatabase{
return taskMap.values().stream().filter(task -> task.isInTimePeriode(start, end)).toList();
}
@Override
public List<Task> getTaskForCrop(Crop crop) {
return null; //TODO implement
}
@Override
public void removeTasksForCrop(Crop crop) {
// TODO implement
}
/**
* If no data is currently loaded, data is loaded from {@link #dataSource}.
* If the {@link Task} has an id than the task is added to the {@link #taskMap}
@@ -95,12 +112,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);
}
}
}
@@ -112,7 +133,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);
@@ -1,5 +1,6 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task;
@@ -24,6 +25,10 @@ public interface TaskDatabase {
*/
List<Task> getTaskList(LocalDate start, LocalDate end) throws IOException;
List<Task> getTaskForCrop(Crop crop); //TODO Javadoc
void removeTasksForCrop(Crop crop); // TODO Javadoc
/**
* Saves the {@link Task} in the Cache.
*
@@ -167,4 +167,17 @@ public class PlantListModel {
public List<Plant> getFilteredPlantListByHarvestSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
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)));
}
}
@@ -0,0 +1,7 @@
package ch.zhaw.gartenverwaltung.taskList;
public class PlantNotFoundException extends Exception {
public PlantNotFoundException() {
super("The selected Plant was not found in Database!");
}
}
@@ -0,0 +1,82 @@
package ch.zhaw.gartenverwaltung.taskList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonTaskDatabase;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import ch.zhaw.gartenverwaltung.io.TaskDatabase;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task;
import java.io.IOException;
import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class TaskListModel {
private TaskDatabase taskDatabase;
private PlantDatabase plantDatabase;
static final Comparator<Task> sortByStartDate = Comparator.comparing(Task::getStartDate);
public TaskListModel(){
taskDatabase = new JsonTaskDatabase();
}
public TaskListModel(TaskDatabase taskDatabase, PlantDatabase plantDatabase) {
this.taskDatabase = taskDatabase;
this.plantDatabase = plantDatabase;
}
public void addTask(Task task) throws IOException {
taskDatabase.saveTask(task);
}
public void planTasksForCrop(Crop crop) throws PlantNotFoundException, HardinessZoneNotSetException, IOException {
Plant plant = plantDatabase.getPlantById(HardinessZone.ZONE_8A, crop.getPlantId()).orElseThrow(PlantNotFoundException::new);
// TODO new exception
// TODO HArdiness Zone
return;
}
public void removeTasksForCrop(Crop crop) {
//TODO implement
taskDatabase.removeTasksForCrop(crop);
}
public void removeTask(Task task) throws IOException {
taskDatabase.removeTask(task);
}
public List<Task> getTaskList() throws IOException {
return getFilteredTaskList(LocalDate.MIN, LocalDate.MAX);
}
public List<Task> getFutureTasks() throws IOException {
return getFilteredTaskList(LocalDate.now(), LocalDate.MAX);
}
public List<Task> getPastTasks() throws IOException {
return getFilteredTaskList(LocalDate.MIN, LocalDate.now());
}
public List<Task>[] getTasksUpcomingWeek() throws IOException {
List<Task>[] listArray = new List[7];
for(int i = 0; i < 7; i++) {
LocalDate date = LocalDate.now().plusDays(i);
listArray[i] = taskDatabase.getTaskList(date, date);
}
return listArray;
}
public List<Task> getFilteredTaskList(LocalDate start, LocalDate end) throws IOException {
return getSortedTaskList(taskDatabase.getTaskList(start, end), sortByStartDate);
}
private List<Task> getSortedTaskList(List<Task> taskList, Comparator<Task> comparator) {
return taskList.stream().sorted(comparator).collect(Collectors.toList());
}
}
@@ -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);
}
}
@@ -15,6 +15,7 @@ public class Task {
private final LocalDate startDate;
private Integer interval;
private LocalDate endDate;
private Crop cropId;
/**
* default constructor
@@ -3,7 +3,6 @@
<?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?>
@@ -16,8 +15,9 @@
<?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">
<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>
@@ -30,7 +30,7 @@
<Font name="System Bold" size="30.0" />
</font>
</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">
<children>
<ListView fx:id="list_plants" maxWidth="1.7976931348623157E308" prefHeight="497.0" prefWidth="580.0" HBox.hgrow="ALWAYS" />
@@ -75,30 +75,7 @@
<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>
<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>
</AnchorPane>
</content>
@@ -5,7 +5,8 @@
"description": "Plant the seeds, crops in de bed.",
"startDate" : "2022-05-01",
"endDate" : "2022-05-01",
"interval" : 0
"interval" : 0,
"cropID" : 0
},
{
"id" : 2,
@@ -13,7 +14,8 @@
"description": "water the plant, so that the soil is wet around the plant.",
"startDate" : "2022-05-01",
"endDate" : "2022-09-01",
"interval" : 2
"interval" : 2,
"cropID" : 0
},
{
"id" : 3,
@@ -21,7 +23,8 @@
"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
"interval" : 28,
"cropID" : 0
},
{
"id" : 4,
@@ -29,7 +32,8 @@
"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
"interval" : 0,
"cropID" : 0
},
{
"id" : 5,
@@ -37,7 +41,8 @@
"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
"interval" : 5,
"cropID" : 0
},
{
"id" : 6,
@@ -45,6 +50,7 @@
"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
"interval" : 0,
"cropID" : 0
}
]
@@ -0,0 +1,109 @@
package ch.zhaw.gartenverwaltung.gardenplan;
import ch.zhaw.gartenverwaltung.io.*;
import ch.zhaw.gartenverwaltung.taskList.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.taskList.TaskListModel;
import ch.zhaw.gartenverwaltung.types.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.internal.stubbing.answers.DoesNothing;
import java.io.IOException;
import java.time.LocalDate;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.*;
public class GardenPlanModelTest {
GardenPlan gardenPlan;
List<Crop> cropList;
Crop exampleCropOnion;
Crop exampleCropCarrot;
Crop exampleCrop1;
Crop exampleCrop2;
Crop exampleCrop3;
Plant examplePlantOnion;
Plant examplePlantCarrot;
Gardenplanmodel model;
@BeforeEach
void setUp() throws IOException {
examplePlantOnion = new Plant(
0,
"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<>(),
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<>())));
exampleCropOnion = new Crop(examplePlantOnion.id(), LocalDate.now());
exampleCropOnion.withId(13);
examplePlantCarrot = 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<>(),
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<>())));
exampleCropCarrot = new Crop(examplePlantCarrot.id(), LocalDate.now());
exampleCropCarrot.withId(5);
exampleCrop1 = new Crop(1, LocalDate.of(2023,2,25));
exampleCrop1.withId(0);
exampleCrop1.withArea(0.5);
exampleCrop2 = new Crop(1,LocalDate.of(2023,3,1));
exampleCrop2.withId(1);
exampleCrop2.withArea(0.5);
exampleCrop3 = new Crop(0,LocalDate.of(2023,3,25));
exampleCrop3.withId(2);
exampleCrop3.withArea(1.5);
cropList = new ArrayList<>();
cropList.add(exampleCrop1);
cropList.add(exampleCrop2);
cropList.add(exampleCrop3);
gardenPlan = mockGardenPlan(cropList);
TaskListModel taskListModel = new TaskListModel(new JsonTaskDatabase(), new JsonPlantDatabase());
model = new Gardenplanmodel(taskListModel);
}
GardenPlan mockGardenPlan(List<Crop> cropList) throws IOException {
GardenPlan gardenPlan = mock(GardenPlan.class);
when(gardenPlan.getCrops()).thenReturn(cropList);
when(gardenPlan.getCropById(5)).thenReturn(java.util.Optional.ofNullable(exampleCropCarrot));
when(gardenPlan.getCropById(13)).thenReturn(java.util.Optional.ofNullable(exampleCropOnion));
return gardenPlan;
}
@Test
void plantAsCrop() throws HardinessZoneNotSetException, IOException, PlantNotFoundException {
model.plantAsCrop(examplePlantOnion, LocalDate.of(2023,3,1));
assertTrue(model.getCrops().contains(exampleCropOnion));
}
@Test
void removeCrop() throws IOException {
exampleCrop1.withId(2);
exampleCrop1.withArea(1.500000);
model.removeCrop(exampleCrop1);
assertEquals(2,model.getCrops().size());
}
}
@@ -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);
}
}
}