Merge branch 'dev' into feature_weather
# Conflicts: # src/test/java/ch/zhaw/gartenverwaltung/models/GardenScheduleTest.java
This commit is contained in:
@@ -22,6 +22,7 @@ import javafx.scene.control.*;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
@@ -87,7 +88,7 @@ public class CropDetailController {
|
||||
private ListView<Pest> pests_listView;
|
||||
|
||||
@FXML
|
||||
void addTask() throws IOException {
|
||||
void addTask() throws IOException, HardinessZoneNotSetException {
|
||||
createTaskDialog(true, null);
|
||||
}
|
||||
|
||||
@@ -136,7 +137,7 @@ public class CropDetailController {
|
||||
if (plant.image() != null) {
|
||||
imageView.setImage(plant.image());
|
||||
}
|
||||
area_label.setText("");
|
||||
area_label.setText(String.valueOf(crop.getArea()));
|
||||
location_label.setText("");
|
||||
|
||||
setTaskListProperty(crop);
|
||||
@@ -205,22 +206,28 @@ public class CropDetailController {
|
||||
}
|
||||
|
||||
private HBox createTaskHBox(Task task) {
|
||||
HBox hBox = new HBox();
|
||||
HBox hBox = new HBox(10);
|
||||
Label taskName = new Label(task.getName()+": ");
|
||||
taskName.setMinWidth(100);
|
||||
taskName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
taskName.setStyle("-fx-font-weight: bold");
|
||||
Label taskDescription = new Label(task.getDescription());
|
||||
taskDescription.setWrapText(true);
|
||||
taskDescription.setMaxWidth(2000);
|
||||
HBox.setHgrow(taskDescription, Priority.ALWAYS);
|
||||
taskDescription.setMaxSize(600, Double.MAX_VALUE);
|
||||
Pane puffer = new Pane();
|
||||
HBox.setHgrow(puffer, Priority.ALWAYS);
|
||||
|
||||
|
||||
Button edit = new Button();
|
||||
Button delete = new Button();
|
||||
HBox.setHgrow(edit, Priority.NEVER);
|
||||
HBox.setHgrow(delete, Priority.NEVER);
|
||||
setIconToButton(edit, "editIcon.png");
|
||||
setIconToButton(delete, "deleteIcon.png");
|
||||
edit.setOnAction(getEditTaskEvent(task));
|
||||
delete.setOnAction(deleteTask(task));
|
||||
|
||||
hBox.getChildren().addAll(taskName, taskDescription, edit, delete);
|
||||
hBox.getChildren().addAll(taskName, taskDescription, puffer, edit, delete);
|
||||
return hBox;
|
||||
}
|
||||
|
||||
@@ -229,12 +236,15 @@ public class CropDetailController {
|
||||
label.setStyle("-fx-font-weight: bold");
|
||||
HBox hBox = new HBox();
|
||||
hBox.fillHeightProperty();
|
||||
Label label1 = new Label(pest.description());
|
||||
label1.setAlignment(Pos.TOP_LEFT);
|
||||
label1.setWrapText(true);
|
||||
label1.setMaxWidth(600);
|
||||
Label description = new Label(pest.description());
|
||||
description.setAlignment(Pos.TOP_LEFT);
|
||||
description.setWrapText(true);
|
||||
description.setMaxWidth(600);
|
||||
Pane puffer = new Pane();
|
||||
HBox.setHgrow(puffer, Priority.ALWAYS);
|
||||
Button button = new Button("Get Counter Measures");
|
||||
hBox.getChildren().addAll(label, label1, button);
|
||||
HBox.setHgrow(button, Priority.NEVER);
|
||||
hBox.getChildren().addAll(label, description, puffer, button);
|
||||
return hBox;
|
||||
}
|
||||
|
||||
@@ -255,7 +265,7 @@ public class CropDetailController {
|
||||
return (event) -> {
|
||||
try {
|
||||
createTaskDialog(false, task);
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | HardinessZoneNotSetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
};
|
||||
@@ -267,7 +277,7 @@ public class CropDetailController {
|
||||
};
|
||||
}
|
||||
|
||||
private void createTaskDialog(boolean newTask, Task givenTask) throws IOException {
|
||||
private void createTaskDialog(boolean newTask, Task givenTask) throws IOException, HardinessZoneNotSetException {
|
||||
Dialog<Task> dialog = new Dialog<>();
|
||||
dialog.setTitle("Set Task");
|
||||
dialog.setHeaderText("Add/Edit Task:");
|
||||
@@ -289,7 +299,7 @@ public class CropDetailController {
|
||||
if (!newTask) {
|
||||
controller.setTaskValue(givenTask);
|
||||
}
|
||||
dialog.setResultConverter(button -> button.equals(saveTask) ? controller.returnResult() : null);
|
||||
dialog.setResultConverter(button -> button.equals(saveTask) ? controller.returnResult(this.crop) : null);
|
||||
|
||||
dialog.showAndWait()
|
||||
.ifPresent(task -> {
|
||||
@@ -334,8 +344,11 @@ public class CropDetailController {
|
||||
//ToDo method to set location
|
||||
location_label.setText(string);
|
||||
} else {
|
||||
System.out.println(string);
|
||||
//ToDo method to set area of crop in garden
|
||||
try {
|
||||
garden.updateCrop(this.crop.withArea(Double.parseDouble(string)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
area_label.setText(string);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
public class HelloController {
|
||||
@FXML
|
||||
private Label welcomeText;
|
||||
|
||||
@FXML
|
||||
protected void onHelloButtonClick() {
|
||||
welcomeText.setText("Welcome to JavaFX Application!");
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ public class MyGardenController {
|
||||
@AfterInject
|
||||
@SuppressWarnings("unused")
|
||||
public void init() {
|
||||
System.out.println("once");
|
||||
setIconToButton(addPlant_button, "addIcon.png");
|
||||
myGarden_listView.itemsProperty().bind(garden.getPlantedCrops());
|
||||
setCellFactory();
|
||||
|
||||
@@ -9,11 +9,14 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import ch.zhaw.gartenverwaltung.types.Plant;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
import javafx.beans.property.ListProperty;
|
||||
import javafx.beans.property.SimpleListProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -24,6 +27,7 @@ import java.util.logging.Logger;
|
||||
|
||||
public class MyScheduleController {
|
||||
private static final Logger LOG = Logger.getLogger(MyScheduleController.class.getName());
|
||||
private final ListProperty<List<Task>> taskListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
|
||||
|
||||
private Crop selectedCrop = null;
|
||||
|
||||
@@ -35,46 +39,7 @@ public class MyScheduleController {
|
||||
private PlantList plantList;
|
||||
|
||||
@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;
|
||||
private ListView<List<Task>> week_listView;
|
||||
|
||||
@FXML
|
||||
private Label information_label;
|
||||
@@ -85,10 +50,11 @@ public class MyScheduleController {
|
||||
@AfterInject
|
||||
@SuppressWarnings("unused")
|
||||
public void init() {
|
||||
setCellFactoryListView();
|
||||
setCellFactoryCropListView();
|
||||
setCellFactoryTaskListView();
|
||||
scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
|
||||
week_listView.itemsProperty().bind(taskListProperty);
|
||||
lookForSelectedListEntries();
|
||||
setDayLabels();
|
||||
information_label.setText("");
|
||||
try {
|
||||
loadTaskList();
|
||||
@@ -108,18 +74,7 @@ public class MyScheduleController {
|
||||
});
|
||||
}
|
||||
|
||||
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 setCellFactoryListView() {
|
||||
private void setCellFactoryCropListView() {
|
||||
scheduledPlants_listview.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(Crop crop, boolean empty) {
|
||||
@@ -141,6 +96,23 @@ public class MyScheduleController {
|
||||
});
|
||||
}
|
||||
|
||||
private void setCellFactoryTaskListView() {
|
||||
week_listView.setCellFactory(param -> new ListCell<>() {
|
||||
@Override
|
||||
protected void updateItem(List<Task> taskList, boolean empty) {
|
||||
super.updateItem(taskList, empty);
|
||||
|
||||
if (empty || taskList == null) {
|
||||
setGraphic(null);
|
||||
setText(null);
|
||||
} else {
|
||||
setText("");
|
||||
setGraphic(weekTaskVBox(taskList, this.getIndex()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadTaskList() throws IOException {
|
||||
List<List<Task>> taskLists;
|
||||
if (selectedCrop != null) {
|
||||
@@ -148,25 +120,66 @@ public class MyScheduleController {
|
||||
} else {
|
||||
taskLists = gardenSchedule.getTasksUpcomingWeek();
|
||||
}
|
||||
if (!taskLists.isEmpty()) {
|
||||
viewTaskListOfDay(day1_pane, taskLists.get(0));
|
||||
viewTaskListOfDay(day2_pane, taskLists.get(1));
|
||||
viewTaskListOfDay(day3_pane, taskLists.get(2));
|
||||
viewTaskListOfDay(day4_pane, taskLists.get(3));
|
||||
viewTaskListOfDay(day5_pane, taskLists.get(4));
|
||||
viewTaskListOfDay(day6_pane, taskLists.get(5));
|
||||
viewTaskListOfDay(day7_pane, taskLists.get(6));
|
||||
}
|
||||
taskListProperty.clear();
|
||||
taskListProperty.addAll(taskLists);
|
||||
}
|
||||
|
||||
private void viewTaskListOfDay(Pane pane, List<Task> tasks) {
|
||||
//ToDo update pane with task list
|
||||
VBox vBox = new VBox();
|
||||
private VBox weekTaskVBox(List<Task> tasks, int dayIndex) {
|
||||
VBox vBox = new VBox(10);
|
||||
LocalDate today = LocalDate.now();
|
||||
Label weekDay = new Label(today.plusDays(dayIndex).getDayOfWeek().toString());
|
||||
weekDay.setStyle("-fx-font-weight: bold; -fx-underline: true");
|
||||
vBox.getChildren().add(weekDay);
|
||||
for (Task task : tasks) {
|
||||
Label label = new Label(task.getDescription());
|
||||
vBox.getChildren().add(label);
|
||||
HBox hBox = new HBox(10);
|
||||
Label taskName = new Label(task.getName() + ":");
|
||||
taskName.setStyle("-fx-font-weight: bold");
|
||||
taskName.setMinWidth(100);
|
||||
taskName.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
|
||||
hBox.getChildren().addAll(taskName);
|
||||
|
||||
HBox hBoxDescription = new HBox();
|
||||
Label taskDescription = new Label(task.getDescription());
|
||||
taskDescription.setWrapText(true);
|
||||
taskDescription.setMaxSize(600, Double.MAX_VALUE);
|
||||
Pane puffer = new Pane();
|
||||
HBox.setHgrow(puffer, Priority.ALWAYS);
|
||||
CheckBox checkBox = new CheckBox("Task completed?");
|
||||
checkBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue) {
|
||||
showConfirmation(task, checkBox);
|
||||
}
|
||||
});
|
||||
HBox.setHgrow(checkBox, Priority.NEVER);
|
||||
hBoxDescription.getChildren().addAll(taskDescription, puffer, checkBox);
|
||||
vBox.getChildren().addAll(hBox, hBoxDescription);
|
||||
}
|
||||
pane.getChildren().add(vBox);
|
||||
return vBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert to confirm that task has been completed.
|
||||
* @param task {@link Task} which is selected
|
||||
*/
|
||||
private void showConfirmation(Task task, CheckBox checkBox) {
|
||||
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
|
||||
alert.setTitle("Task Completed?");
|
||||
alert.setHeaderText("Are you sure you have completed this task?");
|
||||
alert.setContentText("Confirming that you have completed the task will remove it from the schedule.");
|
||||
|
||||
alert.showAndWait()
|
||||
.ifPresent(buttonType -> {
|
||||
if (buttonType == ButtonType.OK) {
|
||||
task.done();
|
||||
try {
|
||||
loadTaskList();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
checkBox.setSelected(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -233,11 +233,11 @@ public class PlantsController {
|
||||
RadioButton radioButton = new RadioButton(season.getName());
|
||||
radioButton.setToggleGroup(seasonGroup);
|
||||
radioButton.setPadding(new Insets(0, 0, 10, 0));
|
||||
if (season.equals(Seasons.AllSEASONS)) {
|
||||
if (season.equals(Seasons.ALLSEASONS)) {
|
||||
radioButton.setSelected(true);
|
||||
}
|
||||
radioButton.selectedProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (season.equals(Seasons.AllSEASONS)) {
|
||||
if (season.equals(Seasons.ALLSEASONS)) {
|
||||
fillPlantListWithHardinessZone();
|
||||
} else {
|
||||
try {
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
package ch.zhaw.gartenverwaltung;
|
||||
|
||||
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
|
||||
import ch.zhaw.gartenverwaltung.bootstrap.Inject;
|
||||
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
|
||||
import ch.zhaw.gartenverwaltung.io.PlantList;
|
||||
import ch.zhaw.gartenverwaltung.models.Garden;
|
||||
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
|
||||
import ch.zhaw.gartenverwaltung.types.Crop;
|
||||
import ch.zhaw.gartenverwaltung.types.Plant;
|
||||
import ch.zhaw.gartenverwaltung.types.Task;
|
||||
import javafx.beans.binding.Binding;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.util.Callback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class TaskFormularController implements Initializable {
|
||||
private Crop crop;
|
||||
private Plant plant;
|
||||
private Task task = null;
|
||||
|
||||
@Inject
|
||||
private GardenSchedule gardenSchedule;
|
||||
@Inject
|
||||
private Garden garden;
|
||||
@Inject
|
||||
private PlantList plantList;
|
||||
|
||||
@FXML
|
||||
private TextArea description_area;
|
||||
@@ -34,19 +46,28 @@ public class TaskFormularController implements Initializable {
|
||||
@FXML
|
||||
private TextField taskName_field;
|
||||
|
||||
@AfterInject
|
||||
@SuppressWarnings("unused")
|
||||
|
||||
public Task returnResult() {
|
||||
public Task returnResult(Crop crop) {
|
||||
int interval = 0;
|
||||
if (!(interval_field.getText().isEmpty() || interval_field.getText().equals(""))) {
|
||||
interval = Integer.parseInt(interval_field.getText());
|
||||
}
|
||||
Task task = new Task(taskName_field.getText(), description_area.getText(),
|
||||
start_datePicker.getValue(), end_datePicker.getValue(),
|
||||
Integer.parseInt(interval_field.getText()), crop.getCropId().get());
|
||||
interval, crop.getCropId().get());
|
||||
if (this.task != null) return this.task.updateTask(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
public void setCorp(Crop crop) {
|
||||
public void setCorp(Crop crop) throws HardinessZoneNotSetException, IOException {
|
||||
this.crop = crop;
|
||||
this.plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
|
||||
}
|
||||
|
||||
public void setTaskValue(Task task) {
|
||||
this.task = task;
|
||||
taskName_field.setText(task.getName());
|
||||
description_area.setText(task.getDescription());
|
||||
start_datePicker.setValue(task.getStartDate());
|
||||
@@ -69,7 +90,7 @@ public class TaskFormularController implements Initializable {
|
||||
setDisable(true);
|
||||
setStyle("-fx-background-color: #ffc0cb;");
|
||||
|
||||
if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0) {
|
||||
if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0 && item.compareTo(crop.getStartDate().plusDays(plant.timeToHarvest(0))) < 0) {
|
||||
setDisable(false);
|
||||
setStyle("-fx-background-color: #32CD32;");
|
||||
}
|
||||
@@ -93,7 +114,7 @@ public class TaskFormularController implements Initializable {
|
||||
setDisable(true);
|
||||
setStyle("-fx-background-color: #ffc0cb;");
|
||||
|
||||
if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0) {
|
||||
if (item.compareTo(today) > 0 && item.compareTo(crop.getStartDate()) > 0 && item.compareTo(crop.getStartDate().plusDays(plant.timeToHarvest(0))) < 0) {
|
||||
setDisable(false);
|
||||
setStyle("-fx-background-color: #32CD32;");
|
||||
}
|
||||
@@ -114,12 +135,8 @@ public class TaskFormularController implements Initializable {
|
||||
});
|
||||
|
||||
button.disableProperty().bind(start_datePicker.valueProperty().isNull()
|
||||
.or(end_datePicker.valueProperty().isNull())
|
||||
.or(taskName_field.textProperty().isEmpty())
|
||||
.or(description_area.textProperty().isEmpty())
|
||||
.or(interval_field.textProperty().isEmpty()));
|
||||
|
||||
|
||||
.or(description_area.textProperty().isEmpty()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,6 +27,15 @@ public class TextFieldFormularController {
|
||||
}
|
||||
|
||||
public void initSaveButton(Button button) {
|
||||
text_area.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
if (newValue.matches("\\d*\\.?\\d*")) {
|
||||
text_area.setText(newValue);
|
||||
} else {
|
||||
text_area.setText(oldValue);
|
||||
}
|
||||
});
|
||||
|
||||
button.disableProperty().bind(text_area.textProperty().isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a method to be executed after all dependencies annotates with {@link Inject}
|
||||
* Annotates a method to be executed after all dependencies annotated with {@link Inject}
|
||||
* have been injected.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -18,6 +18,10 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Class responsible for bootstrapping the application wide dependencies
|
||||
* and injecting them into JavaFX Controllers.
|
||||
*/
|
||||
public class AppLoader {
|
||||
/**
|
||||
* Caching the panes
|
||||
@@ -27,17 +31,24 @@ public class AppLoader {
|
||||
/**
|
||||
* Application-wide dependencies
|
||||
*/
|
||||
private final PlantList plantList = new JsonPlantList();
|
||||
private final CropList cropList = new JsonCropList();
|
||||
private final TaskList taskList = new JsonTaskList();
|
||||
|
||||
private final GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList);
|
||||
private final Garden garden = new Garden(gardenSchedule, cropList);
|
||||
|
||||
private final Map<String, Object> dependencies = new HashMap<>();
|
||||
|
||||
public AppLoader() throws IOException {
|
||||
}
|
||||
PlantList plantList = new JsonPlantList();
|
||||
CropList cropList = new JsonCropList();
|
||||
TaskList taskList = new JsonTaskList();
|
||||
GardenSchedule gardenSchedule = new GardenSchedule(taskList, plantList);
|
||||
|
||||
dependencies.put(PlantList.class.getSimpleName(), plantList);
|
||||
dependencies.put(CropList.class.getSimpleName(), cropList);
|
||||
dependencies.put(TaskList.class.getSimpleName(), taskList);
|
||||
|
||||
dependencies.put(PlantListModel.class.getSimpleName(), new PlantListModel(plantList));
|
||||
|
||||
dependencies.put(GardenSchedule.class.getSimpleName(), gardenSchedule);
|
||||
dependencies.put(Garden.class.getSimpleName(), new Garden(gardenSchedule, cropList));
|
||||
dependencies.put(AppLoader.class.getSimpleName(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns a {@link Pane} (cached).
|
||||
@@ -130,26 +141,18 @@ public class AppLoader {
|
||||
});
|
||||
|
||||
Arrays.stream(controller.getClass().getMethods())
|
||||
.filter(method -> method.isAnnotationPresent(AfterInject.class))
|
||||
.filter(method -> method.isAnnotationPresent(AfterInject.class) && method.getParameterCount() == 0)
|
||||
.forEach(afterInjectMethod -> {
|
||||
if (afterInjectMethod.getParameterCount() == 0) {
|
||||
try {
|
||||
afterInjectMethod.invoke(controller);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
afterInjectMethod.invoke(controller);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
// TODO: Log
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Object getAppDependency(Class<?> type) {
|
||||
return switch (type.getSimpleName()) {
|
||||
case "Garden" -> garden;
|
||||
case "PlantList" -> plantList;
|
||||
case "PlantListModel" -> new PlantListModel(plantList);
|
||||
case "GardenSchedule" -> gardenSchedule;
|
||||
case "AppLoader" -> this;
|
||||
default -> null;
|
||||
};
|
||||
return dependencies.get(type.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,20 @@ package ch.zhaw.gartenverwaltung.bootstrap;
|
||||
import javafx.event.Event;
|
||||
import javafx.event.EventType;
|
||||
|
||||
/**
|
||||
* Represents an event that should lead to a view being changed.
|
||||
*/
|
||||
public class ChangeViewEvent extends Event {
|
||||
private final String view;
|
||||
|
||||
public static final EventType<ChangeViewEvent> CHANGE_MAIN_VIEW = new EventType<>("CHANGE_MAIN_VIEW");
|
||||
|
||||
/**
|
||||
* Creates an Event that should lead to the main view being changed.
|
||||
*
|
||||
* @param eventType The {@link EventType<ChangeViewEvent>} specifying which view should be changed.
|
||||
* @param view The filename of the View to be changed to
|
||||
*/
|
||||
public ChangeViewEvent(EventType<? extends Event> eventType, String view) {
|
||||
super(eventType);
|
||||
this.view = view;
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotates a Field to be injected from the application-dependencies
|
||||
* Annotates a Field to be injected from the application-dependencies.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
|
||||
@@ -6,6 +6,10 @@ import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Represents a List of {@link Crop}s.
|
||||
* The interface specifies the operations to add/update and remove entries.
|
||||
*/
|
||||
public interface CropList {
|
||||
/**
|
||||
* Yields a list of all {@link Crop}s in the database.
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
package ch.zhaw.gartenverwaltung.io;
|
||||
|
||||
/**
|
||||
* Provides an sequential ID starting from the given initial Value.
|
||||
*/
|
||||
public class IdProvider {
|
||||
private long currentId;
|
||||
public IdProvider(long initialValue) {
|
||||
currentId = initialValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields the next ID in the sequence.
|
||||
* @return The next ID
|
||||
*/
|
||||
public long incrementAndGet() {
|
||||
return ++currentId;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Implements the {@link CropList} interface for reading and writing {@link Crop} objects
|
||||
* from and to a local JSON file.
|
||||
* The reads are cached to minimize file-io operations.
|
||||
*/
|
||||
public class JsonCropList implements CropList {
|
||||
private final URL dataSource;
|
||||
|
||||
@@ -40,7 +45,7 @@ public class JsonCropList implements CropList {
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
* Default constructor. Uses a file from the app resources.
|
||||
*/
|
||||
public JsonCropList() {
|
||||
this.dataSource = getClass().getResource("user-crops.json");
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Implements the {@link PlantList} interface for loading {@link Plant} objects
|
||||
* from a JSON file.
|
||||
* Implements the {@link PlantList} interface for reading {@link Plant} objects
|
||||
* from a local JSON file.
|
||||
* The reads are cached to minimize file-io operations.
|
||||
*/
|
||||
public class JsonPlantList implements PlantList {
|
||||
@@ -44,9 +44,17 @@ public class JsonPlantList implements PlantList {
|
||||
imageModule.addDeserializer(Image.class, new PlantImageDeserializer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor. Uses a file from the app resources.
|
||||
*/
|
||||
public JsonPlantList() {
|
||||
this.dataSource = getClass().getResource("plantdb.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to use a specified {@link URL} as a {@link #dataSource}
|
||||
* @param dataSource A {@link URL} to the file to be used as a data source
|
||||
*/
|
||||
public JsonPlantList(URL dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
@@ -67,7 +75,7 @@ public class JsonPlantList implements PlantList {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PlantList#getPlantById(long)
|
||||
* @see PlantList#getPlantById(HardinessZone, long)
|
||||
*/
|
||||
@Override
|
||||
public Optional<Plant> getPlantById(HardinessZone zone, long id) throws HardinessZoneNotSetException, IOException {
|
||||
|
||||
@@ -20,8 +20,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Implements the {@link TaskList} interface for loading and writing {@link Task} objects
|
||||
* from and to a JSON file.
|
||||
* Implements the {@link TaskList} interface for reading and writing {@link Task} objects
|
||||
* from and to a local JSON file.
|
||||
* The reads are cached to minimize file-io operations.
|
||||
*/
|
||||
public class JsonTaskList implements TaskList {
|
||||
@@ -45,9 +45,17 @@ public class JsonTaskList implements TaskList {
|
||||
timeModule.addSerializer(LocalDate.class, dateSerializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor. Uses a file from the app resources.
|
||||
*/
|
||||
public JsonTaskList() {
|
||||
this.dataSource = getClass().getResource("taskdb.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor to use a specified {@link URL} as a {@link #dataSource}
|
||||
* @param dataSource A {@link URL} to the file to be used as a data source
|
||||
*/
|
||||
public JsonTaskList(URL dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
@@ -88,7 +96,8 @@ public class JsonTaskList implements TaskList {
|
||||
if(taskMap.isEmpty()) {
|
||||
loadTaskListFromFile();
|
||||
}
|
||||
taskMap.values().removeIf(task -> task.getCropId() == cropId);
|
||||
taskMap.entrySet().removeIf(entry -> entry.getValue().getCropId() == cropId);
|
||||
writeTaskListToFile();
|
||||
notifySubscribers();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A database of {@link Plant}s.
|
||||
* A List of {@link Plant}s.
|
||||
* The interface specifies the minimal required operations.
|
||||
*/
|
||||
public interface PlantList {
|
||||
|
||||
@@ -7,8 +7,8 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A database of {@link Task}s.
|
||||
* The interface specifies the minimal required operations.
|
||||
* Represents a List of {@link Task}s.
|
||||
* The interface specifies the operations to add/update and remove entries.
|
||||
*/
|
||||
public interface TaskList {
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Used by the Jackson Library to deserialize a String to a {@link GrowthPhaseType}
|
||||
*/
|
||||
public class GrowthPhaseTypeDeserializer extends StdDeserializer<GrowthPhaseType> {
|
||||
public GrowthPhaseTypeDeserializer(Class<?> vc) {
|
||||
super(vc);
|
||||
|
||||
@@ -7,6 +7,9 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Used by the Jackson Library to deserialize a String to a {@link HardinessZone}
|
||||
*/
|
||||
public class HardinessZoneDeserializer extends StdDeserializer<HardinessZone> {
|
||||
public HardinessZoneDeserializer(Class<?> vc) {
|
||||
super(vc);
|
||||
|
||||
@@ -13,6 +13,9 @@ import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Used by the Jackson Library to deserialize a String to a {@link Image}
|
||||
*/
|
||||
public class PlantImageDeserializer extends JsonDeserializer<Image> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -70,6 +70,19 @@ public class Garden {
|
||||
plantedCrops.clear();
|
||||
plantedCrops.addAll(cropList.getCrops());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the {@link Crop} from the file and the cache
|
||||
*
|
||||
* @param crop The crop which is being updated
|
||||
* @throws IOException If the database cannot be accessed
|
||||
*/
|
||||
public void updateCrop(Crop crop) throws IOException {
|
||||
cropList.saveCrop(crop);
|
||||
plantedCrops.clear();
|
||||
plantedCrops.addAll(cropList.getCrops());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of {@link Crop}s which are currently in the gardenplan.
|
||||
*
|
||||
|
||||
@@ -150,13 +150,18 @@ public class GardenSchedule {
|
||||
dayTaskList.add(new ArrayList<>());
|
||||
final int finalI = i;
|
||||
weekTasks.forEach(task -> {
|
||||
LocalDate checkDate = task.getNextExecution();
|
||||
do {
|
||||
if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) {
|
||||
dayTaskList.get(finalI).add(task);
|
||||
}
|
||||
checkDate = checkDate.plusDays(task.getInterval().orElse(0));
|
||||
} while (task.getInterval().isPresent() && checkDate.isBefore(LocalDate.now().plusDays(listLength)));
|
||||
if (task.getNextExecution() == null) {
|
||||
task.isDone();
|
||||
} else {
|
||||
LocalDate checkDate = task.getNextExecution();
|
||||
|
||||
do {
|
||||
if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) {
|
||||
dayTaskList.get(finalI).add(task);
|
||||
}
|
||||
checkDate = checkDate.plusDays(task.getInterval().orElse(0));
|
||||
} while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength)));
|
||||
}
|
||||
});
|
||||
}
|
||||
return dayTaskList;
|
||||
@@ -191,6 +196,6 @@ public class GardenSchedule {
|
||||
* @return a sorted coppy of the given Tasklist
|
||||
*/
|
||||
private List<Task> getSortedTaskList(List<Task> taskList, Comparator<Task> comparator) {
|
||||
return taskList.stream().sorted(comparator).collect(Collectors.toList());
|
||||
return taskList.stream().filter(task -> task.getNextExecution() != null).sorted(comparator).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,16 +67,16 @@ public record Plant(
|
||||
public int timeToHarvest(int group) {
|
||||
List<GrowthPhase> activeLifecycle = lifecycleForGroup(group);
|
||||
GrowthPhase sow = activeLifecycle.stream()
|
||||
.filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.SOW))
|
||||
.filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.SOW))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
GrowthPhase harvest = activeLifecycle.stream()
|
||||
.filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.HARVEST))
|
||||
.filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.HARVEST))
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
|
||||
int currentYear = LocalDate.now().getYear();
|
||||
return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear));
|
||||
return (int) DAYS.between(sow.startDate().atYear(currentYear),harvest.startDate().atYear(currentYear));
|
||||
}
|
||||
|
||||
public int lifecycleGroupFromHarvestDate(LocalDate harvestDate) {
|
||||
|
||||
@@ -3,7 +3,7 @@ package ch.zhaw.gartenverwaltung.types;
|
||||
import java.time.MonthDay;
|
||||
|
||||
public enum Seasons {
|
||||
AllSEASONS("--01-01", "--12-31", "All Seasons"),
|
||||
ALLSEASONS("--01-01", "--12-31", "All Seasons"),
|
||||
SPRING("--03-01", "--05-30", "Spring"),
|
||||
SUMMER("--06-01", "--08-30", "Summer"),
|
||||
AUTUMN("--09-01", "--11-30", "Autumn"),
|
||||
|
||||
@@ -10,14 +10,15 @@ import java.util.Optional;
|
||||
*/
|
||||
public class Task {
|
||||
private Long id;
|
||||
private final String name;
|
||||
private final String description;
|
||||
private final LocalDate startDate;
|
||||
private String name;
|
||||
private String description;
|
||||
private LocalDate startDate;
|
||||
private Integer interval;
|
||||
private LocalDate endDate;
|
||||
private LocalDate nextExecution;
|
||||
private LocalDate nextNotification;
|
||||
private long cropId;
|
||||
private boolean done;
|
||||
|
||||
/**
|
||||
* default constructor
|
||||
@@ -78,7 +79,7 @@ public class Task {
|
||||
}
|
||||
|
||||
public void done(){
|
||||
if(interval != null && !nextExecution.plusDays(interval).isAfter(endDate)){
|
||||
if(interval != null && interval != 0 && !nextExecution.plusDays(interval).isAfter(endDate)){
|
||||
nextExecution = nextExecution.plusDays(interval);
|
||||
} else {
|
||||
nextExecution = null;
|
||||
@@ -112,4 +113,14 @@ public class Task {
|
||||
public Optional<LocalDate> getEndDate() {
|
||||
return Optional.ofNullable(endDate);
|
||||
}
|
||||
|
||||
public Task updateTask(Task task) {
|
||||
this.name = task.getName();
|
||||
this.description = task.getDescription();
|
||||
this.startDate = task.getStartDate();
|
||||
this.endDate = task.getEndDate().orElse(null);
|
||||
this.interval = task.getInterval().orElse(0);
|
||||
this.cropId = task.getCropId();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class TaskTemplate {
|
||||
}
|
||||
|
||||
public Task generateTask(LocalDate realStartDate, long cropId) {
|
||||
LocalDate endDate = relativeEndDate != null ? realStartDate.plusDays(relativeEndDate) : null;
|
||||
LocalDate endDate = relativeEndDate != null ? realStartDate.plusDays(relativeEndDate) : realStartDate;
|
||||
|
||||
if (interval == null) {
|
||||
this.interval = 0;
|
||||
|
||||
Reference in New Issue
Block a user