Compare commits
4 Commits
8a2119028c
...
27b8d1754e
Author | SHA1 | Date |
---|---|---|
schrom01 | 27b8d1754e | |
giavaphi | dc0830120f | |
giavaphi | 39bff805ac | |
giavaphi | 3ebbb0e0e3 |
|
@ -12,6 +12,7 @@ import ch.zhaw.gartenverwaltung.types.Crop;
|
||||||
import ch.zhaw.gartenverwaltung.types.Pest;
|
import ch.zhaw.gartenverwaltung.types.Pest;
|
||||||
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.application.Platform;
|
||||||
import javafx.beans.property.ListProperty;
|
import javafx.beans.property.ListProperty;
|
||||||
import javafx.beans.property.SimpleListProperty;
|
import javafx.beans.property.SimpleListProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
|
@ -133,8 +134,14 @@ public class CropDetailController {
|
||||||
initializeTaskListProperty(crop);
|
initializeTaskListProperty(crop);
|
||||||
|
|
||||||
TaskList.TaskListObserver taskListObserver = newTaskList -> {
|
TaskList.TaskListObserver taskListObserver = newTaskList -> {
|
||||||
taskListProperty.clear();
|
Platform.runLater(() -> {
|
||||||
taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
|
taskListProperty.clear();
|
||||||
|
try {
|
||||||
|
taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
gardenSchedule.setTaskListObserver(taskListObserver);
|
gardenSchedule.setTaskListObserver(taskListObserver);
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import javafx.scene.layout.VBox;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@ -208,6 +209,12 @@ public class MyScheduleController {
|
||||||
alert.setHeaderText("Are you sure you have completed this task?");
|
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.setContentText("Confirming that you have completed the task will remove it from the schedule.");
|
||||||
|
|
||||||
|
DialogPane dialogPane = alert.getDialogPane();
|
||||||
|
|
||||||
|
dialogPane.getStylesheets().add(
|
||||||
|
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
|
||||||
|
dialogPane.getStyleClass().add("myDialog");
|
||||||
|
|
||||||
alert.showAndWait()
|
alert.showAndWait()
|
||||||
.ifPresent(buttonType -> {
|
.ifPresent(buttonType -> {
|
||||||
if (buttonType == ButtonType.OK) {
|
if (buttonType == ButtonType.OK) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import javafx.scene.image.Image;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller class for the Tutorial.fxml file
|
* Controller class for the Tutorial.fxml file
|
||||||
|
@ -32,17 +33,27 @@ public class TutorialController {
|
||||||
switchViews();
|
switchViews();
|
||||||
setButtonAbilities();
|
setButtonAbilities();
|
||||||
|
|
||||||
Image addNewPlantImage = new Image(String.valueOf(PlantsController.class.getResource("add-new-plant.png")));
|
setImageView(imgAddNewPlant, "add-new-plant.png");
|
||||||
Image selectSowHarvestImage = new Image(String.valueOf(PlantsController.class.getResource("select-sow-harvest.png")));
|
setImageView(imgSelectDate, "select-sow-harvest.png");
|
||||||
Image scheduleImage = new Image(String.valueOf(PlantsController.class.getResource("schedule.png")));
|
setImageView(imgDetailDeleteButtons, "details-delete.png");
|
||||||
Image detailDeleteButtonsImage = new Image(String.valueOf(PlantsController.class.getResource("details-delete.png")));
|
setImageView(imgTaskList, "schedule.png");
|
||||||
Image addTaskImage = new Image(String.valueOf(PlantsController.class.getResource("add-task.png")));
|
setImageView(imgAddTaskButton, "add-task.png");
|
||||||
|
}
|
||||||
|
|
||||||
imgAddNewPlant.setImage(addNewPlantImage);
|
/**
|
||||||
imgSelectDate.setImage(selectSowHarvestImage);
|
* update the given image view with screenshot or placeholder image.
|
||||||
imgDetailDeleteButtons.setImage(detailDeleteButtonsImage);
|
* @param imageView the image view to update
|
||||||
imgAddTaskButton.setImage(addTaskImage);
|
* @param fileName the file name of the source
|
||||||
imgTaskList.setImage(scheduleImage);
|
*/
|
||||||
|
private void setImageView(ImageView imageView, String fileName) {
|
||||||
|
File file = new File(String.valueOf(PlantsController.class.getResource(fileName)));
|
||||||
|
Image image;
|
||||||
|
if (file.exists()) {
|
||||||
|
image = new Image(String.valueOf(PlantsController.class.getResource(fileName)));
|
||||||
|
} else {
|
||||||
|
image = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
|
||||||
|
}
|
||||||
|
imageView.setImage(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void viewNextPage() {
|
public void viewNextPage() {
|
||||||
|
|
|
@ -17,14 +17,27 @@ import java.util.TimerTask;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class with tasks which must be executed periodic and not triggered by user. Method run must be called in a fix interval.
|
||||||
|
*/
|
||||||
public class BackgroundTasks extends TimerTask {
|
public class BackgroundTasks extends TimerTask {
|
||||||
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
|
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
|
||||||
private final TaskList taskList;
|
private final TaskList taskList;
|
||||||
private final Notifier notifier;
|
private final Notifier notifier;
|
||||||
private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
|
private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
|
||||||
|
|
||||||
|
public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
|
||||||
|
this.taskList = taskList;
|
||||||
|
notifier = new Notifier(taskList, plantList, cropList);
|
||||||
|
weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the field "nextExecution" of all tasks if it's in the past to the actual date as long as they are not done.
|
||||||
|
* @throws IOException if the taskList can't be read.
|
||||||
|
*/
|
||||||
private void movePastTasks() throws IOException {
|
private void movePastTasks() throws IOException {
|
||||||
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN, LocalDate.now().minusDays(1));
|
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN.plusDays(1), LocalDate.now().minusDays(1));
|
||||||
for (Task task : taskList) {
|
for (Task task : taskList) {
|
||||||
if (!task.isDone()) {
|
if (!task.isDone()) {
|
||||||
task.setNextExecution(LocalDate.now());
|
task.setNextExecution(LocalDate.now());
|
||||||
|
@ -33,12 +46,9 @@ public class BackgroundTasks extends TimerTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
|
/**
|
||||||
this.taskList = taskList;
|
* Method to call if Tasks should be executed. It calls all Background tasks after each other.
|
||||||
notifier = new Notifier(taskList, plantList, cropList);
|
*/
|
||||||
weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -13,6 +13,9 @@ import javax.mail.MessagingException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to send Notifications to the user
|
||||||
|
*/
|
||||||
public class Notifier {
|
public class Notifier {
|
||||||
private final TaskList taskList;
|
private final TaskList taskList;
|
||||||
private final CropList cropList;
|
private final CropList cropList;
|
||||||
|
@ -25,6 +28,13 @@ public class Notifier {
|
||||||
this.plantList = plantList;
|
this.plantList = plantList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to send a Notification to the user for e specific Task
|
||||||
|
* @param task The task to use for notification
|
||||||
|
* @throws IOException if tasklist can not be read
|
||||||
|
* @throws MessagingException if E-Mail can not be sent for any reason
|
||||||
|
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
|
||||||
|
*/
|
||||||
private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
|
private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||||
String plantName = "unkown plant";
|
String plantName = "unkown plant";
|
||||||
if(cropList.getCropById((task.getCropId())).isPresent()){
|
if(cropList.getCropById((task.getCropId())).isPresent()){
|
||||||
|
@ -38,6 +48,12 @@ public class Notifier {
|
||||||
eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
|
eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a notification to the user for each task which is due and not done every day as long as it's not done.
|
||||||
|
* @throws IOException if tasklist can not be read
|
||||||
|
* @throws MessagingException if E-Mail can not be sent for any reason
|
||||||
|
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
|
||||||
|
*/
|
||||||
public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
|
public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
|
||||||
for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
|
for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
|
||||||
if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
|
if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {
|
||||||
|
|
|
@ -10,16 +10,20 @@ import java.util.Arrays;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to send E-Mails
|
||||||
|
*/
|
||||||
public class EMailSender {
|
public class EMailSender {
|
||||||
|
|
||||||
|
/**
|
||||||
public EMailSender(){
|
* Method to send E-Mail to one or multiple recipients
|
||||||
|
* @param recipients recipients E-Mail addresses separated by ";"
|
||||||
}
|
* @param subject Subject of the E-Mail
|
||||||
|
* @param text E-Mail message Text as rear text or html
|
||||||
|
* @throws MessagingException If sending the E-Mail fails for any reason
|
||||||
|
*/
|
||||||
public void sendMails(String recipients, String subject, String text) throws MessagingException {
|
public void sendMails(String recipients, String subject, String text) throws MessagingException {
|
||||||
// TODO replace printMail with implementation
|
printMail(recipients, subject, text);
|
||||||
printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it
|
|
||||||
MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
|
MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
|
||||||
message.addHeader("Content-type", "text/HTML; charset=UTF-8");
|
message.addHeader("Content-type", "text/HTML; charset=UTF-8");
|
||||||
message.addHeader("format", "flowed");
|
message.addHeader("format", "flowed");
|
||||||
|
|
|
@ -5,6 +5,10 @@ import javax.mail.Session;
|
||||||
import java.net.Authenticator;
|
import java.net.Authenticator;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to store SMTP Credentials to send E-Mails and create
|
||||||
|
* corresponding Session Object
|
||||||
|
*/
|
||||||
public record SmtpCredentials(
|
public record SmtpCredentials(
|
||||||
String host,
|
String host,
|
||||||
String port,
|
String port,
|
||||||
|
@ -14,6 +18,10 @@ public record SmtpCredentials(
|
||||||
boolean startTLS
|
boolean startTLS
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Properties Object with SMTP Server Information
|
||||||
|
* @return the created Properties Object
|
||||||
|
*/
|
||||||
private Properties getProperties() {
|
private Properties getProperties() {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.put("mail.smtp.host", host);
|
properties.put("mail.smtp.host", host);
|
||||||
|
@ -23,6 +31,10 @@ public record SmtpCredentials(
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a javax.mail.Authenticator Object with username and password for SMTP Server
|
||||||
|
* @return the created javax.mail.Authenticator Object
|
||||||
|
*/
|
||||||
private javax.mail.Authenticator getAuthenticator() {
|
private javax.mail.Authenticator getAuthenticator() {
|
||||||
return new javax.mail.Authenticator() {
|
return new javax.mail.Authenticator() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -32,10 +44,11 @@ public record SmtpCredentials(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get the Session Instance with the given SMTP Credentials
|
||||||
|
* @return the Session Instance
|
||||||
|
*/
|
||||||
public Session getSession() {
|
public Session getSession() {
|
||||||
return Session.getInstance(getProperties(), getAuthenticator());
|
return Session.getInstance(getProperties(), getAuthenticator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum of possible Weather events
|
||||||
|
*/
|
||||||
public enum SevereWeather {
|
public enum SevereWeather {
|
||||||
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
|
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
|
* The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class WeatherGradenTaskPlanner {
|
public class WeatherGradenTaskPlanner {
|
||||||
private final TaskList taskList;
|
private final TaskList taskList;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
|
||||||
/**
|
/**
|
||||||
* The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
|
* The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class WeatherService {
|
public class WeatherService {
|
||||||
private static final int NO_RAIN = 0;
|
private static final int NO_RAIN = 0;
|
||||||
|
@ -9,6 +8,11 @@ public class WeatherService {
|
||||||
private static final int RAIN = 25;
|
private static final int RAIN = 25;
|
||||||
private static final int HEAVY_RAIN = 50;
|
private static final int HEAVY_RAIN = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to simmulate a Weather Service for testing
|
||||||
|
* @param randomWeather random int. Range: 1-3
|
||||||
|
* @return the selected SevereWeather
|
||||||
|
*/
|
||||||
public SevereWeather causeSevereWeather(int randomWeather) {
|
public SevereWeather causeSevereWeather(int randomWeather) {
|
||||||
return switch (randomWeather) {
|
return switch (randomWeather) {
|
||||||
case 1 -> SevereWeather.HAIL;
|
case 1 -> SevereWeather.HAIL;
|
||||||
|
@ -19,6 +23,11 @@ public class WeatherService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to simulate a Weather Service for testing
|
||||||
|
* @param randomRainAmount random int. Range: 1-4
|
||||||
|
* @return the selected rain amount
|
||||||
|
*/
|
||||||
public int causeRainAmount(int randomRainAmount) {
|
public int causeRainAmount(int randomRainAmount) {
|
||||||
return switch (randomRainAmount) {
|
return switch (randomRainAmount) {
|
||||||
case 1 -> NO_RAIN;
|
case 1 -> NO_RAIN;
|
||||||
|
|
|
@ -152,6 +152,11 @@ public class AppLoader {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to get any AppDependency
|
||||||
|
* @param type Class of Dependency
|
||||||
|
* @return the App dependency
|
||||||
|
*/
|
||||||
public Object getAppDependency(Class<?> type) {
|
public Object getAppDependency(Class<?> type) {
|
||||||
return dependencies.get(type.getSimpleName());
|
return dependencies.get(type.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package ch.zhaw.gartenverwaltung.io;
|
package ch.zhaw.gartenverwaltung.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exceptionm which is thrown if Hardiness zone is not set in plant list.
|
||||||
|
*/
|
||||||
public class HardinessZoneNotSetException extends Exception {
|
public class HardinessZoneNotSetException extends Exception {
|
||||||
public HardinessZoneNotSetException() {
|
public HardinessZoneNotSetException() {
|
||||||
super("HardinessZone must be set to retrieve plants!");
|
super("HardinessZone must be set to retrieve plants!");
|
||||||
|
|
|
@ -2,6 +2,9 @@ package ch.zhaw.gartenverwaltung.io;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Excption which is thrown if a JSON file has a invalid File format.
|
||||||
|
*/
|
||||||
class InvalidJsonException extends IOException {
|
class InvalidJsonException extends IOException {
|
||||||
public InvalidJsonException(String reason) {
|
public InvalidJsonException(String reason) {
|
||||||
super(reason);
|
super(reason);
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package ch.zhaw.gartenverwaltung.models;
|
package ch.zhaw.gartenverwaltung.models;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception which is thrown if there is no plant in plant Database with the given id.
|
||||||
|
*/
|
||||||
public class PlantNotFoundException extends Exception {
|
public class PlantNotFoundException extends Exception {
|
||||||
public PlantNotFoundException() {
|
public PlantNotFoundException() {
|
||||||
super("The selected Plant was not found in Database!");
|
super("The selected Plant was not found in Database!");
|
||||||
|
|
|
@ -40,7 +40,6 @@ public class Crop {
|
||||||
public Optional<Long> getCropId() {
|
public Optional<Long> getCropId() {
|
||||||
return Optional.ofNullable(cropId);
|
return Optional.ofNullable(cropId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getPlantId() { return plantId; }
|
public long getPlantId() { return plantId; }
|
||||||
public LocalDate getStartDate() { return startDate; }
|
public LocalDate getStartDate() { return startDate; }
|
||||||
public double getArea() { return area; }
|
public double getArea() { return area; }
|
||||||
|
|
|
@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class which represents a Task if the start and enddate is not known yet.
|
||||||
|
*/
|
||||||
public class TaskTemplate {
|
public class TaskTemplate {
|
||||||
@JsonProperty
|
@JsonProperty
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
<?import javafx.scene.text.Text?>
|
<?import javafx.scene.text.Text?>
|
||||||
<?import javafx.scene.text.TextFlow?>
|
<?import javafx.scene.text.TextFlow?>
|
||||||
|
|
||||||
<BorderPane maxHeight="470.0" maxWidth="724.0" minHeight="470.0" minWidth="724.0" prefHeight="470.0" prefWidth="724.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.TutorialController">
|
<BorderPane maxHeight="470.0" maxWidth="724.0" minHeight="470.0" minWidth="724.0" prefHeight="470.0" prefWidth="724.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.TutorialController">
|
||||||
<bottom>
|
<bottom>
|
||||||
<HBox alignment="CENTER" prefHeight="0.0" prefWidth="724.0" BorderPane.alignment="CENTER">
|
<HBox alignment="CENTER" prefHeight="0.0" prefWidth="724.0" BorderPane.alignment="CENTER">
|
||||||
<children>
|
<children>
|
||||||
|
|
Loading…
Reference in New Issue