Compare commits
11 Commits
4e15a706fb
...
da7a31f512
Author | SHA1 | Date |
---|---|---|
schrom01 | da7a31f512 | |
schrom01 | 3e586093ba | |
David Guler | b6b5138e9f | |
giavaphi | 7fd18f3830 | |
Roman Schenk | f5fcfa78f6 | |
gulerdav | 1e14a07ef8 | |
David Guler | 629e64143b | |
gulerdav | b851c11f7d | |
David Guler | 72b0d029d5 | |
Elias Csomor | aceb6aa1e6 | |
David Guler | a29f8c7db7 |
|
@ -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.
|
||||
|
|
|
@ -39,6 +39,7 @@ dependencies {
|
|||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
|
||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.4'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4'
|
||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.4'
|
||||
testImplementation 'org.mockito:mockito-core:4.3.+'
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
public class HomeController
|
||||
{
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
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.Objects;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class MainFXMLController implements Initializable {
|
||||
|
||||
@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;
|
||||
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
|
||||
node = (Node)loader.load();
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
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.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.InputMethodEvent;
|
||||
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 PlantsController implements Initializable {
|
||||
private final PlantListModel plantListModel = new PlantListModel();
|
||||
private Plant selectedPlant = null;
|
||||
private final HardinessZone DEFAULT_HARDINESS_ZONE = HardinessZone.ZONE_8A;
|
||||
|
||||
@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(InputMethodEvent event) {
|
||||
viewFilteredListBySearch(search_plants.getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||
List<Plant> plantList = new LinkedList<>();
|
||||
try {
|
||||
plantList = plantListModel.getPlantList(DEFAULT_HARDINESS_ZONE);
|
||||
} catch (HardinessZoneNotSetException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
fillListViewWithData(plantList);
|
||||
|
||||
description_plant.setText("");
|
||||
saveToMyPlant_button.setDisable(true);
|
||||
|
||||
createFilterHardinessZone();
|
||||
lookForSelectedListEntry();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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>))
|
||||
//List<Plant> plantList = new LinkedList<>();
|
||||
//fillListViewWithData(plantList);
|
||||
}
|
||||
|
||||
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() {
|
||||
list_plants.getItems().clear();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,42 @@
|
|||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.types.UserPlanting;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface GardenPlan {
|
||||
List<UserPlanting> getPlantings();
|
||||
void savePlanting(UserPlanting planting) throws IOException;
|
||||
void removePlanting(UserPlanting planting) throws IOException;
|
||||
/**
|
||||
* Yields a list of all {@link Crop}s in the database.
|
||||
*
|
||||
* @return A list of all {@link Crop}s in the database
|
||||
* @throws IOException If there is a problem reading from or writing to the database
|
||||
*/
|
||||
List<Crop> getCrops() throws IOException;
|
||||
|
||||
/**
|
||||
* Attempts to retrieve the {@link Crop} with the specified cropId.
|
||||
*
|
||||
* @param id The {@link Crop#cropId} 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;
|
||||
|
||||
/**
|
||||
* Saves a Crop to the Database.
|
||||
*
|
||||
* @param crop The {@link Crop} to be saved
|
||||
* @throws IOException If there is a problem reading from or writing to the database
|
||||
*/
|
||||
void saveCrop(Crop crop) throws IOException;
|
||||
|
||||
/**
|
||||
* Removes a Crop from the Database.
|
||||
*
|
||||
* @param crop The {@link Crop} to be removed
|
||||
* @throws IOException If there is a problem reading from or writing to the database
|
||||
*/
|
||||
void removeCrop(Crop crop) throws IOException;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
public class IdProvider {
|
||||
private long currentId;
|
||||
public IdProvider(long initialValue) {
|
||||
currentId = initialValue;
|
||||
}
|
||||
public long incrementAndGet() {
|
||||
return ++currentId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class InvalidJsonException extends IOException {
|
||||
public InvalidJsonException(String reason) {
|
||||
super(reason);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
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;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class JsonGardenPlan implements GardenPlan {
|
||||
private final URL dataSource = getClass().getResource("user-crops.json");
|
||||
|
||||
private IdProvider idProvider;
|
||||
private Map<Long, Crop> cropMap = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* Creating constant objects required to deserialize the {@link LocalDate} classes
|
||||
*/
|
||||
private final static JavaTimeModule timeModule = new JavaTimeModule();
|
||||
private final static String INVALID_DATASOURCE_MSG = "Invalid datasource specified!";
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GardenPlan#getCrops()
|
||||
*/
|
||||
@Override
|
||||
public List<Crop> getCrops() throws IOException {
|
||||
if (idProvider == null) {
|
||||
loadCropList();
|
||||
}
|
||||
return cropMap.values().stream().toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GardenPlan#getCropById(long)
|
||||
*/
|
||||
@Override
|
||||
public Optional<Crop> getCropById(long id) throws IOException {
|
||||
if (idProvider == null) {
|
||||
loadCropList();
|
||||
}
|
||||
return Optional.ofNullable(cropMap.get(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GardenPlan#saveCrop(Crop)
|
||||
*
|
||||
* Saves a crop to the database.
|
||||
* If no {@link Crop#cropId} is set, one will be generated and
|
||||
* the Crop is stored as a new entry.
|
||||
*/
|
||||
@Override
|
||||
public void saveCrop(Crop crop) throws IOException {
|
||||
if (idProvider == null) {
|
||||
loadCropList();
|
||||
}
|
||||
Long cropId = crop.getCropId().orElse(idProvider.incrementAndGet());
|
||||
cropMap.put(cropId, crop.withId(cropId));
|
||||
writeCropList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GardenPlan#removeCrop(Crop)
|
||||
*/
|
||||
@Override
|
||||
public void removeCrop(Crop crop) throws IOException {
|
||||
if (idProvider == null) {
|
||||
loadCropList();
|
||||
}
|
||||
Optional<Long> cropId = crop.getCropId();
|
||||
if (cropId.isPresent()) {
|
||||
cropMap.remove(cropId.get());
|
||||
writeCropList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the database from {@link #dataSource} and updates the cached data.
|
||||
*
|
||||
* @throws IOException If the database cannot be accessed or invalid data was read.
|
||||
*/
|
||||
private void loadCropList() throws IOException {
|
||||
if (dataSource != null) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.registerModule(timeModule);
|
||||
|
||||
List<Crop> result;
|
||||
result = mapper.readerForListOf(Crop.class).readValue(dataSource);
|
||||
|
||||
// Turn list into a HashMap with structure cropId => Crop
|
||||
cropMap = new HashMap<>(result.size());
|
||||
for (Crop crop : result) {
|
||||
Long id = crop.getCropId()
|
||||
.orElseThrow(() -> new InvalidJsonException(String.format("Invalid value for \"cropId\" in %s!", crop)));
|
||||
cropMap.put(id, crop);
|
||||
}
|
||||
Long maxId = cropMap.isEmpty() ? 0L : Collections.max(cropMap.keySet());
|
||||
idProvider = new IdProvider(maxId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the values from {@link #cropMap} to the {@link #dataSource}
|
||||
*
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
private void writeCropList() throws IOException {
|
||||
if (dataSource != null) {
|
||||
try {
|
||||
new ObjectMapper()
|
||||
.registerModule(timeModule)
|
||||
.registerModule(new Jdk8Module())
|
||||
.writeValue(new File(dataSource.toURI()), cropMap.values());
|
||||
} catch (URISyntaxException e) {
|
||||
// TODO: Log
|
||||
throw new IOException(INVALID_DATASOURCE_MSG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ 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 +20,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.
|
||||
|
@ -67,7 +68,7 @@ public class PlantListModel {
|
|||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,7 +81,7 @@ public class PlantListModel {
|
|||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,4 +98,24 @@ 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.charAt(0) == '#') {
|
||||
try {
|
||||
return getFilteredPlantListById(zone, Long.parseLong(searchString.substring(1)));
|
||||
} catch (NumberFormatException e) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
} else {
|
||||
return getFilteredPlantList(zone, plant -> plant.name().contains(searchString) || plant.description().contains(searchString));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
package ch.zhaw.gartenverwaltung.types;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Crop {
|
||||
private Long cropId = null;
|
||||
private final long plantId;
|
||||
private final LocalDate startDate;
|
||||
private double area = 1;
|
||||
|
||||
/**
|
||||
* Default Constructor (needed for deserialization)
|
||||
*/
|
||||
public Crop() {
|
||||
plantId = 0;
|
||||
startDate = null;
|
||||
}
|
||||
|
||||
public Crop(long plantId, LocalDate startDate) {
|
||||
this.plantId = plantId;
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
// Builder-Style setter
|
||||
public Crop withId(long cropId) {
|
||||
this.cropId = cropId;
|
||||
return this;
|
||||
}
|
||||
public Crop withArea(double area) {
|
||||
this.area = area;
|
||||
return this;
|
||||
}
|
||||
|
||||
// Getters
|
||||
public Optional<Long> getCropId() {
|
||||
return Optional.ofNullable(cropId);
|
||||
}
|
||||
|
||||
public long getPlantId() { return plantId; }
|
||||
public LocalDate getStartDate() { return startDate; }
|
||||
public double getArea() { return area; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Crop [ cropId: %d, plantId: %d, startDate: %s, area: %f ]",
|
||||
cropId,
|
||||
plantId,
|
||||
startDate,
|
||||
area);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package ch.zhaw.gartenverwaltung.types;
|
|||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.time.temporal.ChronoUnit.DAYS;
|
||||
|
||||
|
@ -22,7 +23,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) {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package ch.zhaw.gartenverwaltung.types;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public record UserPlanting(
|
||||
long plantId,
|
||||
Date startDate,
|
||||
int area
|
||||
) {
|
||||
}
|
|
@ -3,10 +3,10 @@ module ch.zhaw.gartenverwaltung {
|
|||
requires javafx.fxml;
|
||||
requires com.fasterxml.jackson.databind;
|
||||
requires com.fasterxml.jackson.datatype.jsr310;
|
||||
requires com.fasterxml.jackson.datatype.jdk8;
|
||||
|
||||
opens ch.zhaw.gartenverwaltung to javafx.fxml;
|
||||
opens ch.zhaw.gartenverwaltung.types to com.fasterxml.jackson.databind;
|
||||
// opens ch.zhaw.gartenverwaltung.types to com.fasterxml.jackson.databind;
|
||||
exports ch.zhaw.gartenverwaltung;
|
||||
exports ch.zhaw.gartenverwaltung.types;
|
||||
exports ch.zhaw.gartenverwaltung.json;
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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" onInputMethodTextChanged="#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>
|
|
@ -165,7 +165,7 @@
|
|||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "summertime onion",
|
||||
"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.",
|
||||
"lifecycle": [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"cropId": 0,
|
||||
"plantId": 1,
|
||||
"startDate": "2023-02-25",
|
||||
"area": 0.5
|
||||
},
|
||||
{
|
||||
"cropId": 1,
|
||||
"plantId": 1,
|
||||
"startDate": "2023-03-01",
|
||||
"area": 0.5
|
||||
},
|
||||
{
|
||||
"cropId": 2,
|
||||
"plantId": 0,
|
||||
"startDate": "2023-03-25",
|
||||
"area": 1.5
|
||||
}
|
||||
]
|
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -0,0 +1,79 @@
|
|||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.types.HardinessZone;
|
||||
import ch.zhaw.gartenverwaltung.types.Plant;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JsonPlantDatabaseTest {
|
||||
PlantDatabase testDatabase;
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
|
||||
|
||||
@BeforeEach
|
||||
void connectToDb() {
|
||||
testDatabase = new JsonPlantDatabase();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@DisplayName("Check if results are retrieved completely")
|
||||
void getPlantList() {
|
||||
List<Plant> testList;
|
||||
try {
|
||||
testList = testDatabase.getPlantList(HardinessZone.ZONE_8A);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (HardinessZoneNotSetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Assertions.assertEquals(3, testList.size());
|
||||
|
||||
List<String> names = testList.stream().map(Plant::name).collect(Collectors.toList());
|
||||
List<String> expected = Arrays.asList("Potato","Early Carrot","Summertime Onion");
|
||||
Assertions.assertEquals(expected,names);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Check whether single access works.")
|
||||
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) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Assertions.assertTrue(testPlant.isPresent());
|
||||
Assertions.assertEquals("Early Carrot", testPlant.get().name());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Check for a nonexisting plant.")
|
||||
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) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Assertions.assertFalse(testPlant.isPresent());
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -146,4 +146,24 @@ 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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue