Compare commits

...

5 Commits

Author SHA1 Message Date
gulerdav b70a758099 Merge pull request #61 from schrom01/refactor_gui_M3
Refactor gui m3
2022-11-18 12:22:13 +01:00
David Guler 3a69119eb7 refactor: bind croplist in schedule 2022-11-18 12:21:50 +01:00
David Guler 2f69c48800 refactor: dedicated loadPaneToDialog function replacing the previous workaround 2022-11-16 20:37:07 +01:00
David Guler 9ba252b828 refactor: fixed and simplified dayCellFactory even more
Added method to check if a date is within a GrowthPhaseType to plant, thus removing the need for the ugly getMinDate methods and moving knowledge of the phase-internals to the Plant class.

Also removed the need to specify the lifecycle-group to the sowDateFromHarvest method
2022-11-15 22:45:01 +01:00
David Guler 90d2de65de refactor: simplified dayCellFactory for date selector
Instead of generating a list of dates for every single visible date and checking if it is contained in that list, we now use a (admittedly scary-looking) predicate to compare the date to the start and enddates
2022-11-15 15:25:51 +01:00
8 changed files with 108 additions and 95 deletions

View File

@ -93,8 +93,9 @@ public class CropDetailController {
} }
public void setPlantFromCrop(Crop crop) throws HardinessZoneNotSetException, IOException, PlantNotFoundException { public void setPlantFromCrop(Crop crop) throws PlantNotFoundException {
this.crop = crop; this.crop = crop;
try {
Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()) Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId())
.orElseThrow(PlantNotFoundException::new); .orElseThrow(PlantNotFoundException::new);
@ -110,6 +111,9 @@ public class CropDetailController {
location_label.setText(""); location_label.setText("");
createTaskLists(crop); createTaskLists(crop);
createPestList(plant); createPestList(plant);
} catch (HardinessZoneNotSetException | IOException e) {
throw new PlantNotFoundException();
}
} }
private void createTaskLists(Crop crop) { private void createTaskLists(Crop crop) {

View File

@ -90,10 +90,12 @@ public class MyGardenController {
Label label = new Label(plant.name()); Label label = new Label(plant.name());
label.setMaxWidth(2000); label.setMaxWidth(2000);
HBox.setHgrow(label, Priority.ALWAYS); HBox.setHgrow(label, Priority.ALWAYS);
Button details = new Button("Details"); Button details = new Button("Details");
Button delete = new Button("delete"); Button delete = new Button("delete");
details.setOnAction(getGoToCropDetailEvent(crop)); details.setOnAction(getGoToCropDetailEvent(crop));
delete.setOnAction(getDeleteCropEvent(crop)); delete.setOnAction(getDeleteCropEvent(crop));
hBox.getChildren().addAll(imageView, label, details, delete); hBox.getChildren().addAll(imageView, label, details, delete);
return hBox; return hBox;
} }
@ -108,7 +110,7 @@ public class MyGardenController {
stage.initModality(Modality.APPLICATION_MODAL); stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(true); stage.setResizable(true);
stage.showAndWait(); stage.showAndWait();
} catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { } catch (IOException | PlantNotFoundException e) {
// TODO: show error alert // TODO: show error alert
LOG.log(Level.SEVERE, "Could not load plant details.", e); LOG.log(Level.SEVERE, "Could not load plant details.", e);
} }

View File

@ -9,9 +9,6 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task; 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.fxml.FXML;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import javafx.scene.control.ListCell; import javafx.scene.control.ListCell;
@ -37,8 +34,6 @@ public class MyScheduleController {
@Inject @Inject
private PlantList plantList; private PlantList plantList;
private final ListProperty<Crop> cropListProperty = new SimpleListProperty<>(FXCollections.observableArrayList());
@FXML @FXML
private Label day1_label; private Label day1_label;
@ -90,15 +85,8 @@ public class MyScheduleController {
@AfterInject @AfterInject
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void init() { public void init() {
List<Crop> cropList;
try {
cropList = garden.getCrops();
cropListProperty.addAll(cropList);
} catch (IOException e) {
e.printStackTrace();
}
setCellFactoryListView(); setCellFactoryListView();
scheduledPlants_listview.itemsProperty().bind(cropListProperty); scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
lookForSelectedListEntries(); lookForSelectedListEntries();
setDayLabels(); setDayLabels();
information_label.setText(""); information_label.setText("");

View File

@ -21,7 +21,6 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox; import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
@ -74,7 +73,6 @@ public class PlantsController {
*/ */
@FXML @FXML
void selectSowDate() throws IOException { void selectSowDate() throws IOException {
Stage stage = new Stage();
Dialog<LocalDate> dateSelection = new Dialog<>(); Dialog<LocalDate> dateSelection = new Dialog<>();
dateSelection.setTitle("Select Date"); dateSelection.setTitle("Select Date");
dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name())); dateSelection.setHeaderText(String.format("Select Harvest/Sow Date for %s:", selectedPlant.name()));
@ -85,12 +83,10 @@ public class PlantsController {
ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE); ButtonType sowButton = new ButtonType("Save", ButtonBar.ButtonData.OK_DONE);
dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL); dialogPane.getButtonTypes().addAll(sowButton, ButtonType.CANCEL);
if (appLoader.loadSceneToStage("SelectSowDay.fxml", stage) instanceof SelectSowDayController controller) { if (appLoader.loadPaneToDialog("SelectSowDay.fxml", dialogPane) instanceof SelectSowDayController controller) {
controller.initSaveButton((Button) dialogPane.lookupButton(sowButton)); controller.initSaveButton((Button) dialogPane.lookupButton(sowButton));
controller.setSelectedPlant(selectedPlant); controller.setSelectedPlant(selectedPlant);
dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null); dateSelection.setResultConverter(button -> button.equals(sowButton) ? controller.retrieveResult() : null);
}
dialogPane.setContent(stage.getScene().getRoot());
dateSelection.showAndWait() dateSelection.showAndWait()
.ifPresent(date -> { .ifPresent(date -> {
@ -102,6 +98,7 @@ public class PlantsController {
plantsRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "MyGarden.fxml")); plantsRoot.fireEvent(new ChangeViewEvent(ChangeViewEvent.CHANGE_MAIN_VIEW, "MyGarden.fxml"));
}); });
} }
}
/** /**
* fill list view with current hardiness zone * fill list view with current hardiness zone

View File

@ -7,7 +7,6 @@ import javafx.scene.control.*;
import javafx.util.Callback; import javafx.util.Callback;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List;
public class SelectSowDayController { public class SelectSowDayController {
private Plant selectedPlant; private Plant selectedPlant;
@ -17,12 +16,15 @@ public class SelectSowDayController {
@FXML @FXML
private RadioButton harvest_radio; private RadioButton harvest_radio;
@FXML
private RadioButton sow_radio;
@FXML
public ToggleGroup phase_group;
public LocalDate retrieveResult() { public LocalDate retrieveResult() {
LocalDate sowDate = datepicker.getValue(); LocalDate sowDate = datepicker.getValue();
if (harvest_radio.isSelected()) { if (harvest_radio.isSelected()) {
//ToDo method to get current lifecycle group in plant sowDate = selectedPlant.sowDateFromHarvestDate(sowDate);
sowDate = selectedPlant.sowDateFromHarvestDate(datepicker.getValue(), 0);
} }
return sowDate; return sowDate;
} }
@ -46,6 +48,9 @@ public class SelectSowDayController {
Callback<DatePicker, DateCell> dayCellFactory = getDayCellFactory(); Callback<DatePicker, DateCell> dayCellFactory = getDayCellFactory();
datepicker.setDayCellFactory(dayCellFactory); datepicker.setDayCellFactory(dayCellFactory);
datepicker.setEditable(false); datepicker.setEditable(false);
sow_radio.setUserData(GrowthPhaseType.SOW);
harvest_radio.setUserData(GrowthPhaseType.HARVEST);
} }
public void initSaveButton(Button saveButton) { public void initSaveButton(Button saveButton) {
@ -61,35 +66,28 @@ public class SelectSowDayController {
/** /**
* date picker disable/enable dates according to selected plant: sow or harvest day * date picker disable/enable dates according to selected plant: sow or harvest day
*
* @return cellFactory of datePicker * @return cellFactory of datePicker
*/ */
private Callback<DatePicker, DateCell> getDayCellFactory() { private Callback<DatePicker, DateCell> getDayCellFactory() {
return (datePicker) -> new DateCell() { return (datePicker) -> new DateCell() {
private final LocalDate today = LocalDate.now();
@Override @Override
public void updateItem(LocalDate item, boolean empty) { public void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty); super.updateItem(item, empty);
setDisable(true); setDisable(true);
setStyle("-fx-background-color: #ffc0cb;"); setStyle("-fx-background-color: #ffc0cb;");
List<LocalDate> dates;
LocalDate today = LocalDate.now(); if (item.compareTo(today) > 0 && (!harvest_radio.isSelected() || selectedPlant.sowDateFromHarvestDate(item).compareTo(today) >= 0)) {
if (harvest_radio.isSelected()) { GrowthPhaseType selectedPhase = (GrowthPhaseType) phase_group.getSelectedToggle().getUserData();
dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.HARVEST);
} else { if (selectedPlant.isDateInPhase(item, selectedPhase)) {
dates = selectedPlant.getDateListOfGrowthPhase(GrowthPhaseType.SOW);
}
for (LocalDate date : dates) {
if (item.getMonth() == date.getMonth()
&& item.getDayOfMonth() == date.getDayOfMonth()
&& item.compareTo(today) > 0) {
setDisable(false); setDisable(false);
setStyle("-fx-background-color: #32CD32;"); setStyle("-fx-background-color: #32CD32;");
} }
} }
if ((harvest_radio.isSelected() && selectedPlant.sowDateFromHarvestDate(item, 0).compareTo(today) < 0)) {
setDisable(true);
setStyle("-fx-background-color: #ffc0cb;");
}
} }
}; };
} }

View File

@ -12,6 +12,7 @@ import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.models.PlantListModel; import ch.zhaw.gartenverwaltung.models.PlantListModel;
import javafx.fxml.FXMLLoader; import javafx.fxml.FXMLLoader;
import javafx.scene.Scene; import javafx.scene.Scene;
import javafx.scene.control.DialogPane;
import javafx.scene.layout.Pane; import javafx.scene.layout.Pane;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -78,6 +79,24 @@ public class AppLoader {
return controller; return controller;
} }
/**
* Loads the given fxml-file from resources (no caching) and appendeds it's
* contents to the given {@link DialogPane}.
* Performs dependency-injection.
*
* @param fxmlFile The file name to be loaded
* @param appendee The {@link DialogPane} to which the FXML contents are to be appended.
* @return The controller of the loaded scene.
* @throws IOException if the file could not be loaded
*/
public Object loadPaneToDialog(String fxmlFile, DialogPane appendee) throws IOException {
FXMLLoader loader = new FXMLLoader(Objects.requireNonNull(HelloApplication.class.getResource(fxmlFile)));
appendee.setContent(loader.load());
Object controller = loader.getController();
annotationInject(controller);
return controller;
}
/** /**
* Loads the given fxml-file from resources and caches the pane. * Loads the given fxml-file from resources and caches the pane.
* Performs dependency-injection. * Performs dependency-injection.

View File

@ -3,7 +3,7 @@ package ch.zhaw.gartenverwaltung.types;
import javafx.scene.image.Image; import javafx.scene.image.Image;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.LinkedList; import java.time.MonthDay;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -42,11 +42,10 @@ public record Plant(
/** /**
* get sow date from given harvest day from lifecycle group * get sow date from given harvest day from lifecycle group
* @param harvestDate date of the harvest * @param harvestDate date of the harvest
* @param group lifecycle group
* @return LocaleDate of sow date * @return LocaleDate of sow date
*/ */
public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) { public LocalDate sowDateFromHarvestDate(LocalDate harvestDate) {
return harvestDate.minusDays(timeToHarvest(group)); return harvestDate.minusDays(timeToHarvest(lifecycleGroupFromHarvestDate(harvestDate)));
} }
/** /**
@ -69,37 +68,43 @@ public record Plant(
return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear)); return (int) DAYS.between(harvest.startDate().atYear(currentYear), sow.startDate().atYear(currentYear));
} }
/** public int lifecycleGroupFromHarvestDate(LocalDate harvestDate) {
* filter out the given growthPhase out of the lifecycle return lifecycle.stream()
* create list of dates for this growthPhase and return it .filter(growthPhase -> growthPhase.type().equals(GrowthPhaseType.HARVEST) &&
* @param growthPhase the wanted growthPhase dateInRange(harvestDate, growthPhase.startDate(), growthPhase.endDate()))
* @return a list of dates of the current year .map(GrowthPhase::group)
*/ .findFirst()
public List<LocalDate> getDateListOfGrowthPhase(GrowthPhaseType growthPhase) { .orElse(0);
List<LocalDate> dates = new LinkedList<>();
for (GrowthPhase growth : lifecycle) {
if (growth.type().equals(growthPhase)) {
dates = addDatesFromMonthDay(growth);
}
}
return dates;
} }
/** /**
* transform monthDay value of the given growthPhase to localDate * Checks if the given {@link LocalDate} is within a {@link GrowthPhase} of the given {@link GrowthPhaseType}
* return a list of dates from start to end of growth phase *
* @param growthPhase the current growthPhase * @param date The date to check.
* @return a list of dates of the current year * @param phase The {@link GrowthPhaseType} to match against
* @return Whether the date is within the given {@link GrowthPhaseType}
*/ */
private List<LocalDate> addDatesFromMonthDay(GrowthPhase growthPhase) { public boolean isDateInPhase(LocalDate date, GrowthPhaseType phase) {
List<LocalDate> dates = new LinkedList<>(); return lifecycle.stream()
LocalDate today = LocalDate.now(); .filter(growthPhase -> growthPhase.type().equals(phase))
LocalDate start = growthPhase.startDate().atYear(today.getYear()); .anyMatch(growthPhase -> dateInRange(date, growthPhase.startDate(), growthPhase.endDate()));
LocalDate end = growthPhase.endDate().atYear(today.getYear());
while (!start.isAfter(end)) {
dates.add(start);
start = start.plusDays(1);
} }
return dates;
/**
* Checks if the given {@link LocalDate} is within the given {@link MonthDay} range.
* (regardless of year)
*
* @param subject The date to check
* @param min The start of the date-range
* @param max The end of the date-range
* @return Whether the subject is within the range.
*/
private boolean dateInRange(LocalDate subject, MonthDay min, MonthDay max) {
return subject.getMonth().compareTo(min.getMonth()) >= 0 &&
subject.getMonth().compareTo(max.getMonth()) <= 0 &&
// if the day is less than the minimum day, the minimum month must not be equal
(subject.getDayOfMonth() >= min.getDayOfMonth() || !subject.getMonth().equals(min.getMonth())) &&
// if the day is greater than the maximum day, the maximum month must not be equal
(subject.getDayOfMonth() <= max.getDayOfMonth() || !subject.getMonth().equals(max.getMonth()));
} }
} }

View File

@ -18,15 +18,15 @@
<children> <children>
<VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0"> <VBox alignment="CENTER_LEFT" prefHeight="88.0" prefWidth="155.0">
<children> <children>
<RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow" toggleGroup="$group"> <RadioButton fx:id="sow_radio" mnemonicParsing="false" selected="true" text="Sow" toggleGroup="$phase_group">
<VBox.margin> <VBox.margin>
<Insets bottom="10.0" /> <Insets bottom="10.0" />
</VBox.margin> </VBox.margin>
<toggleGroup> <toggleGroup>
<ToggleGroup fx:id="group" /> <ToggleGroup fx:id="phase_group" />
</toggleGroup> </toggleGroup>
</RadioButton> </RadioButton>
<RadioButton fx:id="harvest_radio" mnemonicParsing="false" text="Harvest" toggleGroup="$group" /> <RadioButton fx:id="harvest_radio" mnemonicParsing="false" text="Harvest" toggleGroup="$phase_group" />
</children> </children>
<HBox.margin> <HBox.margin>
<Insets top="10.0" /> <Insets top="10.0" />