Compare commits

..
Author SHA1 Message Date
Roman SchenkandGitHub Enterprise 8b3a0c1570 Update issue templates 2022-10-18 11:19:24 +02:00
Roman SchenkandGitHub Enterprise 516a185546 Update issue templates 2022-10-18 11:18:36 +02:00
56 changed files with 105 additions and 2734 deletions
+38
View File
@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
+20
View File
@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
+18 -38
View File
@@ -1,43 +1,23 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
# Compiled class file
*.class
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
# Log file
*.log
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
# BlueJ files
*.ctxt
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
# Mobile Tools for Java (J2ME)
.mtj.tmp/
### VS Code ###
.vscode/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
### Mac OS ###
.DS_Store
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
+4
View File
@@ -0,0 +1,4 @@
package src.App;
public class App {
}
+4
View File
@@ -0,0 +1,4 @@
package src.UI;
public class Model {
}
@@ -0,0 +1,4 @@
package src.Weather;
public class Weather_Dummy {
}
+17 -23
View File
@@ -4,29 +4,23 @@ PM3 FivePlants Gartenverwaltung
## Class Diagram
Umletino: https://www.umletino.com/umletino.html
Draft File: doc/ClassDiagramDraft.uxf
## Branch model
- production branch: `main`
This branch has a working version of the code.
- development branch: `dev`
This branch should contain a running (although not necessarily working) version of the code. Working states are to be merged into the `main` branch regularly.
- feature: `feature_xy_<Milestone>`
These branches contain features in active development. When the code is ready it will be merged into the `dev` branch.
- bugfix: `bugfix_xy_<Milestone>`
These branches are for bugfixes.
- documentation: `doc_xy_<Milestone>`
These branches are for javadoc and project documentation (such as the readme, class diagrams etc.).
- active branch: *main*
## User Manual
- Search Plant List: if first Char is '#': only exact match in ID.
This branch has a running version of the code.
- feature: *feature_xy_"Milestone"*
This branches contain code for feature. When the code is ready it will be merged into the main branch.
- bugfix: *bugfix_xy_"Milestone"*
This branch are for bugfixes.
- documentation: *doc_xy_"Milestone"*
This branch is for documentation of the code and the readme.
Draft File: doc/ClassDiagramDraft.uxf
-60
View File
@@ -1,60 +0,0 @@
plugins {
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.13'
id 'org.beryx.jlink' version '2.25.0'
}
group 'ch.zhaw.gartenverwaltung'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
ext {
junitVersion = '5.8.2'
}
sourceCompatibility = '17'
targetCompatibility = '17'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
application {
mainModule = 'ch.zhaw.gartenverwaltung'
mainClass = 'ch.zhaw.gartenverwaltung.HelloApplication'
}
javafx {
version = '17.0.2'
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
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.+'
}
test {
useJUnitPlatform()
}
jlink {
imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
launcher {
name = 'app'
}
}
jlinkZip {
group = 'distribution'
}
@@ -1,70 +0,0 @@
<diagram program="umletino" version="15.0.0"><zoom_level>12</zoom_level><element><id>UMLClass</id><coordinates><x>852</x><y>372</y><w>120</w><h>72</h></coordinates><panel_attributes>Gardener
--
Name
Type</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>144</x><y>372</y><w>120</w><h>120</h></coordinates><panel_attributes>Plant
--
name
description</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>600</x><y>372</y><w>120</w><h>84</h></coordinates><panel_attributes>Garden
--
Location
hardiness zone</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>384</x><y>372</y><w>120</w><h>72</h></coordinates><panel_attributes>Bed
--
Area</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1152</x><y>624</y><w>120</w><h>36</h></coordinates><panel_attributes>Weather</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>816</y><w>120</w><h>36</h></coordinates><panel_attributes>Calendar</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>96</y><w>144</w><h>72</h></coordinates><panel_attributes>Community
--
Plant Information
</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>288</x><y>636</y><w>120</w><h>72</h></coordinates><panel_attributes>Growth phase
--
duration</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>852</x><y>624</y><w>120</w><h>84</h></coordinates><panel_attributes>Gardening task
--
start date
end date
interval</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>852</x><y>156</y><w>120</w><h>240</h></coordinates><panel_attributes>lt=-
m1=0..*
m2=1..*
&lt; is part of </panel_attributes><additional_attributes>10;180;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>708</x><y>372</y><w>168</w><h>60</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
&lt; has </panel_attributes><additional_attributes>120;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>252</x><y>372</y><w>156</w><h>60</h></coordinates><panel_attributes>lt=-
m1=1
m2=0..*
&lt; contains </panel_attributes><additional_attributes>110;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>252</x><y>444</y><w>156</w><h>216</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
has &gt;</panel_attributes><additional_attributes>10;10;80;10;80;160</additional_attributes></element><element><id>Relation</id><coordinates><x>492</x><y>372</y><w>132</w><h>60</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
&lt; contains </panel_attributes><additional_attributes>90;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>900</x><y>432</y><w>120</w><h>216</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
&lt; manages </panel_attributes><additional_attributes>10;10;10;160</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>624</y><w>216</w><h>60</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
&lt; manipulates</panel_attributes><additional_attributes>160;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>900</x><y>696</y><w>108</w><h>144</h></coordinates><panel_attributes>lt=-
m1=1
m2=0..*
&lt; contains</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>408</y><w>468</w><h>468</h></coordinates><panel_attributes>lt=-
m1=1
m2=1
&lt; informs </panel_attributes><additional_attributes>10;360;310;360;310;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>12</x><y>636</y><w>120</w><h>84</h></coordinates><panel_attributes>Need
--
start date
end date</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>60</x><y>432</y><w>108</w><h>228</h></coordinates><panel_attributes>lt=-
m1=1..*
m2=1..*
has &gt;</panel_attributes><additional_attributes>10;170;10;10;70;10</additional_attributes></element><element><id>Relation</id><coordinates><x>60</x><y>672</y><w>816</w><h>120</h></coordinates><panel_attributes>lt=-
m1=1
m2=1
requires &gt;</panel_attributes><additional_attributes>660;10;520;10;520;80;10;80;10;40</additional_attributes></element><element><id>UMLClass</id><coordinates><x>456</x><y>588</y><w>120</w><h>36</h></coordinates><panel_attributes>Team
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>564</x><y>432</y><w>312</w><h>180</h></coordinates><panel_attributes>lt=-
m1=1
m2=1..*
contains of &gt;</panel_attributes><additional_attributes>10;130;240;10</additional_attributes></element><element><id>Relation</id><coordinates><x>564</x><y>600</y><w>312</w><h>60</h></coordinates><panel_attributes>lt=-
m1=1
m2=0..*
manages &gt;</panel_attributes><additional_attributes>10;20;240;20</additional_attributes></element><element><id>Relation</id><coordinates><x>960</x><y>156</y><w>216</w><h>240</h></coordinates><panel_attributes>lt=-
m1=0..n
m2=1..n
exchanges Informatione &gt;</panel_attributes><additional_attributes>10;10;10;180</additional_attributes></element><element><id>Relation</id><coordinates><x>120</x><y>648</y><w>192</w><h>60</h></coordinates><panel_attributes>lt=-
m1=0..n
m2=1
&lt; contains </panel_attributes><additional_attributes>10;20;140;20</additional_attributes></element></diagram>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
-234
View File
@@ -1,234 +0,0 @@
#!/bin/sh
#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
-89
View File
@@ -1,89 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
-1
View File
@@ -1 +0,0 @@
rootProject.name = "PM3-HS22-IT21b_WIN-Team1"
@@ -1,23 +0,0 @@
package ch.zhaw.gartenverwaltung;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class HelloApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("MainFXML.fxml"));
Scene scene = new Scene(fxmlLoader.load());
stage.setTitle("Gartenverwaltung");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
@@ -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!");
}
}
@@ -1,5 +0,0 @@
package ch.zhaw.gartenverwaltung;
public class HomeController
{
}
@@ -1,94 +0,0 @@
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();
}
}
}
@@ -1,58 +0,0 @@
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
}
}
@@ -1,124 +0,0 @@
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());
}
}
});
}
}
@@ -1,186 +0,0 @@
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,42 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.Crop;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
public interface GardenPlan {
/**
* 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;
}
@@ -1,7 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
public class HardinessZoneNotSetException extends Exception {
public HardinessZoneNotSetException() {
super("HardinessZone must be set to retrieve plants!");
}
}
@@ -1,11 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
public class IdProvider {
private long currentId;
public IdProvider(long initialValue) {
currentId = initialValue;
}
public long incrementAndGet() {
return ++currentId;
}
}
@@ -1,9 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import java.io.IOException;
class InvalidJsonException extends IOException {
public InvalidJsonException(String reason) {
super(reason);
}
}
@@ -1,140 +0,0 @@
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);
}
}
}
}
@@ -1,95 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.MonthDayDeserializer;
import java.io.IOException;
import java.net.URL;
import java.time.MonthDay;
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;
/**
* Implements the {@link PlantDatabase} interface for loading {@link Plant} objects
* from a JSON file.
* The reads are cached to minimize file-io operations.
*/
public class JsonPlantDatabase implements PlantDatabase {
private final URL dataSource = getClass().getResource("plantdb.json");
private HardinessZone currentZone;
private Map<Long, Plant> plantMap = Collections.emptyMap();
/**
* Creating constant objects required to deserialize the {@link MonthDay} classes
*/
private final static JavaTimeModule timeModule = new JavaTimeModule();
static {
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("MM-dd");
MonthDayDeserializer dateDeserializer = new MonthDayDeserializer(dateFormat);
timeModule.addDeserializer(MonthDay.class, dateDeserializer);
}
/**
* If no data is currently loaded, or the specified zone differs
* from the {@link #currentZone}, data is loaded from {@link #dataSource}.
* In any case, the values of {@link #plantMap} are returned.
*
* @see PlantDatabase#getPlantList(HardinessZone)
*/
@Override
public List<Plant> getPlantList(HardinessZone zone) throws IOException, HardinessZoneNotSetException {
if (plantMap.isEmpty() || zone != currentZone) {
loadPlantList(zone);
}
return plantMap.values().stream().toList();
}
/**
* @see PlantDatabase#getPlantById(long)
*/
@Override
public Optional<Plant> getPlantById(HardinessZone zone, long id) throws HardinessZoneNotSetException, IOException {
if (plantMap.isEmpty()) {
loadPlantList(zone);
}
return Optional.ofNullable(plantMap.get(id));
}
/**
* Loads the database from {@link #dataSource} and updates the cached data.
*
* @param zone The {@link HardinessZone} for which data is to be loaded
* @throws IOException If the database cannot be accessed
*/
private void loadPlantList(HardinessZone zone) throws IOException, HardinessZoneNotSetException {
if (zone == null) {
throw new HardinessZoneNotSetException();
}
if (dataSource != null) {
currentZone = zone;
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(timeModule);
List<Plant> result;
result = mapper.readerForListOf(Plant.class).readValue(dataSource);
for (Plant plant : result) {
plant.inZone(currentZone);
}
// Turn list into a HashMap with structure id => Plant
plantMap = result.stream()
.collect(HashMap::new,
(res, plant) -> res.put(plant.id(), plant),
(existing, replacement) -> { });
}
}
}
@@ -1,34 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
/**
* A database of {@link Plant}s.
* The interface specifies the minimal required operations.
*/
public interface PlantDatabase {
/**
* Yields a list of all {@link Plant}s in the database with only data relevant to the specfied {@link HardinessZone}
*
* @param zone The zone for which data should be fetched
* @return A list of {@link Plant}s with data for the specified zone
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
List<Plant> getPlantList(HardinessZone zone) throws IOException, HardinessZoneNotSetException;
/**
* Attempts to retrieve the {@link Plant} with the specified id.
*
* @param id The {@link Plant#id()} to look for
* @return {@link Optional} of the found {@link Plant}, {@link Optional#empty()} if no entry matched the criteria
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
Optional<Plant> getPlantById(HardinessZone zone, long id) throws IOException, HardinessZoneNotSetException;
}
@@ -1,13 +0,0 @@
package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.types.Task;
import java.io.IOException;
import java.util.Date;
import java.util.List;
public interface TaskDatabase {
List<Task> getTaskList(Date start, Date end);
void saveTask(Task task) throws IOException;
void removeTask(Task task) throws IOException;
}
@@ -1,28 +0,0 @@
package ch.zhaw.gartenverwaltung.json;
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class GrowthPhaseTypeDeserializer extends StdDeserializer<GrowthPhaseType> {
public GrowthPhaseTypeDeserializer(Class<?> vc) {
super(vc);
}
public GrowthPhaseTypeDeserializer() { this(null); }
@Override
public GrowthPhaseType deserialize(JsonParser parser, DeserializationContext context) throws IOException {
GrowthPhaseType result = null;
try {
result = GrowthPhaseType.valueOf(parser.getText().toUpperCase());
} catch (IllegalArgumentException e) {
// TODO: Log
System.err.println("bad growth phase type");
}
return result;
}
}
@@ -1,29 +0,0 @@
package ch.zhaw.gartenverwaltung.json;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
public class HardinessZoneDeserializer extends StdDeserializer<HardinessZone> {
public HardinessZoneDeserializer(Class<?> vc) {
super(vc);
}
public HardinessZoneDeserializer() {
this(null);
}
@Override
public HardinessZone deserialize(JsonParser parser, DeserializationContext context) throws IOException {
HardinessZone result = null;
try {
result = HardinessZone.valueOf(parser.getText().toUpperCase());
} catch (IllegalArgumentException e) {
// TODO: Log
System.err.println("bad growth phase type");
}
return result;
}
}
@@ -1,165 +0,0 @@
package ch.zhaw.gartenverwaltung.plantList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonPlantDatabase;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
import ch.zhaw.gartenverwaltung.types.HardinessZone;
import ch.zhaw.gartenverwaltung.types.Plant;
import java.io.IOException;
import java.time.MonthDay;
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;
private HardinessZone currentZone;
/**
* Comparators to create sorted Plant List
*/
static final Comparator<Plant> sortByName = Comparator.comparing(Plant::name);
static final Comparator<Plant> SortById = Comparator.comparingLong(Plant::id);
/**
* Constructor to create Database Object.
*/
public PlantListModel() {
plantDatabase = new JsonPlantDatabase();
setDefaultZone();
}
public PlantListModel(PlantDatabase plantDatabase){
this.plantDatabase = plantDatabase;
setDefaultZone();
}
private void setDefaultZone(){
currentZone = HardinessZone.ZONE_8A; // TODO: get Default Zone from Config
}
public void setCurrentZone(HardinessZone currentZone) {
this.currentZone = currentZone;
}
public HardinessZone getCurrentZone() {
return currentZone;
}
/**
* Method to get actual Plant List in alphabetic Order
* @return actual Plant List in alphabetic Order
*/
public List<Plant> getPlantList(HardinessZone zone) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
return getSortedPlantList(zone, sortByName);
}
/**
* Method to get the actual Plant list in custom Order
* @param zone selected hardiness zone
* @param comparator comparator to sort the list
* @return sorted list with plants in the given hardiness zone
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getSortedPlantList(HardinessZone zone, Comparator<Plant> comparator) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
return plantDatabase.getPlantList(zone).stream().sorted(comparator).collect(Collectors.toList());
}
/**
* Method to get Filtered plant list
* @param predicate predicate to filter the list
* @param zone selected hardiness zone
* @return filterd list with plants in the hardinness zone
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getFilteredPlantList(HardinessZone zone, Predicate<Plant> predicate) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
return getPlantList(zone).stream().filter(predicate).collect(Collectors.toList());
}
/**
* Method to get Filtered plant list by id by exact match
* @param zone selected hardiness zone
* @param id id of plant
* @return if id doesn't exist: empty List, else list with 1 plant entry.
* @throws IOException If the database cannot be accessed
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
*/
public List<Plant> getFilteredPlantListById(HardinessZone zone, Long id) throws HardinessZoneNotSetException, IOException {
setCurrentZone(zone);
List<Plant> plantList = new ArrayList<>();
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.length() == 0){
return getPlantList(zone);
} else 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));
}
}
/**
*
* @param type GrowPhaseType to filter
* @param zone selected hardiness zone
* @param from the earliest date to for the filter
* @param to the lastest date for the filter
* @return List of Plants with selected saison
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
* @throws IOException If the database cannot be accessed
*/
private List<Plant> getFilteredPlantListBySaison(GrowthPhaseType type, HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantList(zone, plant -> plant.lifecycle().stream().anyMatch(growthPhase -> growthPhase.startDate().compareTo(from) >= 0 && (growthPhase.startDate().compareTo(to) <= 0) && growthPhase.type() == type));
}
/**
*
* @param zone selected hardiness zone
* @param from the earliest date to for the filter
* @param to the lastest date for the filter
* @return List of Plants with selected saison
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
* @throws IOException If the database cannot be accessed
*/
public List<Plant> getFilteredPlantListByPlantingSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantListBySaison(GrowthPhaseType.PLANT, zone, from, to);
}
/**
*
* @param zone selected hardiness zone
* @param from the earliest date to for the filter
* @param to the lastest date for the filter
* @return List of Plants with selected saison
* @throws HardinessZoneNotSetException If no {@link HardinessZone} was specified
* @throws IOException If the database cannot be accessed
*/
public List<Plant> getFilteredPlantListByHarvestSaison(HardinessZone zone, MonthDay from, MonthDay to) throws HardinessZoneNotSetException, IOException {
return getFilteredPlantListBySaison(GrowthPhaseType.HARVEST, zone, from, to);
}
}
@@ -1,52 +0,0 @@
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);
}
}
@@ -1,19 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
import ch.zhaw.gartenverwaltung.json.GrowthPhaseTypeDeserializer;
import ch.zhaw.gartenverwaltung.json.HardinessZoneDeserializer;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.MonthDay;
import java.util.List;
public record GrowthPhase(
MonthDay startDate,
MonthDay endDate,
int group,
WateringCycle wateringCycle,
@JsonDeserialize(using = GrowthPhaseTypeDeserializer.class) GrowthPhaseType type,
@JsonDeserialize(using = HardinessZoneDeserializer.class) HardinessZone zone,
List<TaskTemplate> taskTemplates) {
}
@@ -1,5 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
public enum GrowthPhaseType {
SOW, PLANT, REPLANT, HARVEST
}
@@ -1,10 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
/**
* Represents the available hardiness zones
* (Subject to later expansion)
*/
public enum HardinessZone {
ZONE_1A,
ZONE_8A
}
@@ -1,4 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
public record Pest(String name, String description, String measures) {
}
@@ -1,47 +0,0 @@
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;
public record Plant(
long id,
String name,
String description,
String spacing,
int light,
String soil,
List<Pest> pests,
List<GrowthPhase> lifecycle) {
public void inZone(HardinessZone zone) {
lifecycle.removeIf(growthPhase -> !growthPhase.zone().equals(zone));
}
public List<GrowthPhase> lifecycleForGroup(int group) {
return lifecycle.stream()
.filter(growthPhase -> growthPhase.group() != group)
.collect(Collectors.toList());
}
public LocalDate sowDateFromHarvestDate(LocalDate harvestDate, int group) {
return harvestDate.minusDays(timeToHarvest(group));
}
public int timeToHarvest(int group) {
List<GrowthPhase> activeLifecycle = lifecycleForGroup(group);
GrowthPhase sow = activeLifecycle.stream()
.filter(growthPhase -> !growthPhase.type().equals(GrowthPhaseType.SOW))
.findFirst()
.orElseThrow();
GrowthPhase harvest = activeLifecycle.stream()
.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));
}
}
@@ -1,58 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
import java.time.LocalDate;
import java.util.Optional;
/**
* Models a Task
* May be created using the builder pattern.
*/
public class Task {
private long id;
private final String name;
private final String description;
private final LocalDate startDate;
private Integer interval;
private LocalDate endDate;
public Task(String name, String description, LocalDate startDate) {
this.name = name;
this.description = description;
this.startDate = startDate;
}
public Task(String name, String description, LocalDate startDate, LocalDate endDate, int interval) {
this.name = name;
this.description = description;
this.startDate = startDate;
this.endDate = endDate;
this.interval = interval;
}
// Builder-pattern-style setters
public Task withId(long id) {
this.id = id;
return this;
}
public Task withInterval(int interval) {
this.interval = interval;
return this;
}
public Task withEndDate(LocalDate endDate) {
this.endDate = endDate;
return this;
}
// Getters
public long getId() { return id; }
public String getName() { return name; }
public String getDescription() { return description; }
public LocalDate getStartDate() { return startDate; }
public Optional<Integer> getInterval() {
return Optional.ofNullable(interval);
}
public Optional<LocalDate> getEndDate() {
return Optional.ofNullable(endDate);
}
}
@@ -1,57 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDate;
public class TaskTemplate {
@JsonProperty
private final String name;
@JsonProperty
private final String description;
@JsonProperty
private final int relativeStartDate;
@JsonProperty
private Integer relativeEndDate;
@JsonProperty
private Integer interval;
// TODO: reconsider if we need this
@JsonProperty
private boolean isOptional = false;
/**
* Default constructor
* (Used by deserializer)
*/
public TaskTemplate() {
this.name = "";
this.description = "";
this.relativeStartDate = 0;
}
// Setters
public void setRelativeEndDate(Integer relativeEndDate) {
this.relativeEndDate = relativeEndDate;
}
public void setInterval(Integer interval) {
this.interval = interval;
}
public TaskTemplate(String name, String description, int relativeStartDate) {
this.name = name;
this.description = description;
this.relativeStartDate = relativeStartDate;
}
public Task generateTask(LocalDate realStartDate) {
Task task = new Task(name, description, realStartDate.plusDays(relativeStartDate));
if (relativeEndDate != null) {
task.withEndDate(realStartDate.plusDays(relativeEndDate));
}
if (interval != null) {
task.withInterval(interval);
}
return task;
}
}
@@ -1,8 +0,0 @@
package ch.zhaw.gartenverwaltung.types;
public record WateringCycle(
int litersPerSqM,
int interval,
String[] notes
) {
}
-13
View File
@@ -1,13 +0,0 @@
module ch.zhaw.gartenverwaltung {
requires javafx.controls;
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;
exports ch.zhaw.gartenverwaltung;
exports ch.zhaw.gartenverwaltung.types;
exports ch.zhaw.gartenverwaltung.json;
}
@@ -1,43 +0,0 @@
<?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>
@@ -1,21 +0,0 @@
<?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>
@@ -1,36 +0,0 @@
<?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>
@@ -1,74 +0,0 @@
<?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>
@@ -1,125 +0,0 @@
<?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>
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Button?>
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
fx:controller="ch.zhaw.gartenverwaltung.HelloController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label fx:id="welcomeText"/>
<Button text="Hello!" onAction="#onHelloButtonClick"/>
</VBox>
@@ -1,254 +0,0 @@
[
{
"id": 0,
"name": "Potato",
"description": "The potato is a tuber, round or oval, with small white roots called 'eyes', that are growth buds. The size varies depending on the variety; the colour of the skin can be white, yellow or even purple.",
"light": 6,
"spacing": "35",
"soil": "sandy",
"pests": [
{
"name": "Rot",
"description": "Rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
"measures": "Less water."
}
],
"lifecycle": [
{
"startDate": "03-10",
"endDate": "04-10",
"type": "SOW",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 0,
"interval": null,
"notes": []
},
"taskTemplates": [
{
"name": "Germinate",
"relativeStartDate": -14,
"relativeEndDate": null,
"description": "\"Take an egg carton and fill it with soil. Put the seedling deep enaugh so its half covered with soil. Keep it in 10-15 * Celsius with lots of light.\"",
"interval": null,
"isOptional": false
}
]
},
{
"startDate": "04-10",
"endDate": "07-10",
"type": "PLANT",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 25,
"interval": 7,
"notes": []
},
"taskTemplates": [
{
"name": "hilling",
"relativeStartDate": 0,
"relativeEndDate": null,
"description": "\"When the plants are 20 cm tall, begin hilling the potatoes by gently mounding the soil from the center of your rows around the stems of the plant. Mound up the soil around the plant until just the top few leaves show above the soil. Two weeks later, hill up the soil again when the plants grow another 20 cm.\"",
"interval": 21,
"isOptional": false
}
]
},
{
"startDate": "06-10",
"endDate": "08-10",
"type": "HARVEST",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 0,
"interval": null,
"notes": []
},
"taskTemplates": [
{
"name": "Harvest",
"relativeStartDate": 0,
"relativeEndDate": null,
"description": "Once the foliage has wilted and dried completely, harvest on a dry day. Store in a dark and cool location.",
"interval": null,
"isOptional": false
}
]
}
]
},
{
"id": 1,
"name": "Early Carrot",
"description": "Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
"lifecycle": [
{
"startDate": "02-20",
"endDate": "03-10",
"zone": "ZONE_8A",
"type": "SOW",
"wateringCycle": {
"litersPerSqM": 15,
"interval": 3,
"notes": []
},
"taskTemplates": [
{
"name": "hilling",
"relativeStartDate": 0,
"relativeEndDate": 0,
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
"interval": null,
"isOptional": false
}
]
},
{
"startDate": "03-10",
"endDate": "05-10",
"zone": "ZONE_8A",
"type": "PLANT",
"wateringCycle": {
"litersPerSqM": 25,
"interval": 3,
"notes": [
"Be careful not to pour water over the leaves, as this will lead to sunburn."
]
},
"taskTemplates": [
{
"name": "hilling",
"relativeStartDate": 0,
"relativeEndDate": null,
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
"interval": 15,
"isOptional": true
}
]
},
{
"startDate": "05-10",
"endDate": "05-20",
"zone": "ZONE_8A",
"type": "HARVEST",
"wateringCycle": {
"litersPerSqM": 0,
"interval": null,
"notes": []
},
"taskTemplates": [
{
"name": "Harvesting",
"relativeStartDate": 0,
"relativeEndDate": 14,
"description": "When the leaves turn to a yellowish brown. Do not harvest earlier. The plant will show when it's ready.",
"interval": null,
"isOptional": false
}
]
}
],
"soil": "sandy to loamy, loose soil, free of stones",
"spacing": "5,35,2.5",
"pests": [
{
"name": "Rot",
"description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
"measures": "less water"
}
]
},
{
"id": 2,
"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": [
{
"startDate": "03-15",
"endDate": "04-10",
"type": "SOW",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 15,
"interval": 4,
"notes": [
]
},
"taskTemplates": [
{
"name": "hilling",
"relativeStartDate": 0,
"relativeEndDate": 0,
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
"interval": null,
"isOptional": false
}
]
},
{
"startDate": "04-10",
"endDate": "07-10",
"type": "PLANT",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 25,
"interval": 3,
"notes": [
""
]
},
"taskTemplates": [
{
"name": "hilling",
"relativeStartDate": 0,
"relativeEndDate": null,
"description": "Mound up the soil around the plant until just the top few leaves show above the soil. ",
"interval": 15,
"isOptional": true
}
]
},
{
"startDate": "07-10",
"endDate": "09-20",
"type": "HARVEST",
"zone": "ZONE_8A",
"group": 0,
"wateringCycle": {
"litersPerSqM": 0,
"interval": null,
"notes": [
]
},
"taskTemplates": [
{
"name": "Harvesting",
"relativeStartDate": 0,
"relativeEndDate": 14,
"description": "When ready for harvest, the leaves on your onion plants will start to flop over. This happens at the \"neck\" of the onion and it signals that the plant has stopped growing and is ready for storage. Onions should be harvested soon thereafter",
"interval": null,
"isOptional": false
}
]
}
],
"soil": "sandy to loamy, loose soil, free of stones",
"spacing": "15,30,2",
"pests": [
{
"name": "Rot",
"description": "rot, any of several plant diseases, caused by any of hundreds of species of soil-borne bacteria, fungi, and funguslike organisms (Oomycota). Rot diseases are characterized by plant decomposition and putrefaction. The decay may be hard, dry, spongy, watery, mushy, or slimy and may affect any plant part.",
"measures": "less water"
}
]
}
]
@@ -1,20 +0,0 @@
[
{
"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.

Before

Width:  |  Height:  |  Size: 4.6 KiB

@@ -1,79 +0,0 @@
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());
}
}
@@ -1,196 +0,0 @@
package ch.zhaw.gartenverwaltung.plantList;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.JsonPlantDatabase;
import ch.zhaw.gartenverwaltung.io.PlantDatabase;
import ch.zhaw.gartenverwaltung.types.*;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Predicate;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class PlantListModelTest {
PlantDatabase plantDatabase;
List<Plant> examplePlantList;
PlantListModel model;
@BeforeEach
void setUp() throws HardinessZoneNotSetException, IOException {
createExamplePlantList();
plantDatabase = mockPlantDatabase(examplePlantList);
model = new PlantListModel(plantDatabase);
}
@AfterEach
void tearDown() {
}
void createExamplePlantList(){
examplePlantList = new ArrayList<>();
examplePlantList.add(new Plant(
20,
"summertime onion",
"Onion, (Allium cepa), herbaceous biennial plant in the amaryllis family (Amaryllidaceae) grown for its edible bulb. The onion is likely native to southwestern Asia but is now grown throughout the world, chiefly in the temperate zones. Onions are low in nutrients but are valued for their flavour and are used widely in cooking. They add flavour to such dishes as stews, roasts, soups, and salads and are also served as a cooked vegetable.",
"15,30,2",
0,
"sandy to loamy, loose soil, free of stones",
new ArrayList<>(),
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(4, 3), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(8, 5), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(2, 8), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(10, 2), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
examplePlantList.add(new Plant(
0,
"Potato",
"The potato is a tuber, round or oval, with small white roots called 'eyes', that are growth buds. The size varies depending on the variety; the colour of the skin can be white, yellow or even purple.",
"35",
6,
"sandy",
new ArrayList<>(),
List.of(new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.HARVEST, HardinessZone.ZONE_8A, new ArrayList<>()),
new GrowthPhase(MonthDay.of(6, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
examplePlantList.add(new Plant(
1,
"Early Carrot",
"Carrot, (Daucus carota), herbaceous, generally biennial plant of the Apiaceae family that produces an edible taproot. Among common varieties root shapes range from globular to long, with lower ends blunt to pointed. Besides the orange-coloured roots, white-, yellow-, and purple-fleshed varieties are known.",
"5,35,2.5",
0,
"sandy to loamy, loose soil, free of stones",
new ArrayList<>(),
List.of(new GrowthPhase(MonthDay.of(4, 4), MonthDay.of(12, 4), 0, new WateringCycle(0, 0, null), GrowthPhaseType.PLANT, HardinessZone.ZONE_8A, new ArrayList<>())))
);
}
PlantDatabase mockPlantDatabase(List<Plant> plantList) throws HardinessZoneNotSetException, IOException {
PlantDatabase plantDatabase = mock(JsonPlantDatabase.class);
when(plantDatabase.getPlantList(HardinessZone.ZONE_8A)).thenReturn(plantList);
when(plantDatabase.getPlantList(HardinessZone.ZONE_1A)).thenReturn(new ArrayList<>());
when(plantDatabase.getPlantById(HardinessZone.ZONE_8A, 0)).thenReturn(Optional.of(plantList.get(1)));
when(plantDatabase.getPlantById(HardinessZone.ZONE_8A, 1)).thenReturn(Optional.of(plantList.get(2)));
when(plantDatabase.getPlantById(HardinessZone.ZONE_8A, 20)).thenReturn(Optional.of(plantList.get(0)));
when(plantDatabase.getPlantById(HardinessZone.ZONE_8A, 2)).thenReturn(Optional.empty());
return plantDatabase;
}
void checkCurrentZone(HardinessZone expectedZone) {
assertEquals(expectedZone, model.getCurrentZone());
}
@Test
void setCurrentZone() {
checkCurrentZone(HardinessZone.ZONE_8A); // TODO change to get default zone from config
model.setCurrentZone(HardinessZone.ZONE_1A);
checkCurrentZone(HardinessZone.ZONE_1A);
model.setCurrentZone(HardinessZone.ZONE_8A);
checkCurrentZone(HardinessZone.ZONE_8A);
}
@Test
void getPlantList() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getPlantList(HardinessZone.ZONE_8A);
checkCurrentZone(HardinessZone.ZONE_8A);
assertEquals(examplePlantList.size(), plantListResult.size());
assertEquals(examplePlantList.get(2), plantListResult.get(0));
assertEquals(examplePlantList.get(1), plantListResult.get(1));
assertEquals(examplePlantList.get(0), plantListResult.get(2));
assertEquals(0, model.getPlantList(HardinessZone.ZONE_1A).size());
}
@Test
void getSortedPlantList() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getSortedPlantList(HardinessZone.ZONE_8A, PlantListModel.sortByName);
checkCurrentZone(HardinessZone.ZONE_8A);
assertEquals(examplePlantList.size(), plantListResult.size());
assertEquals(examplePlantList.get(2), plantListResult.get(0));
assertEquals(examplePlantList.get(1), plantListResult.get(1));
assertEquals(examplePlantList.get(0), plantListResult.get(2));
plantListResult = model.getSortedPlantList(HardinessZone.ZONE_8A, PlantListModel.SortById);
assertEquals(examplePlantList.size(), plantListResult.size());
assertEquals(examplePlantList.get(1), plantListResult.get(0));
assertEquals(examplePlantList.get(2), plantListResult.get(1));
assertEquals(examplePlantList.get(0), plantListResult.get(2));
}
@Test
void getFilteredPlantList() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
Predicate<Plant> predicate = plant -> plant.name().toUpperCase(Locale.ROOT).contains("E");
List<Plant> plantListResult = model.getFilteredPlantList(HardinessZone.ZONE_8A, predicate);
checkCurrentZone(HardinessZone.ZONE_8A);
assertEquals(2, plantListResult.size());
assertEquals(examplePlantList.get(2), plantListResult.get(0));
assertEquals(examplePlantList.get(0), plantListResult.get(1));
}
@Test
void getFilteredPlantListById() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListById(HardinessZone.ZONE_8A, 2L);
assertEquals(0, plantListResult.size());
plantListResult = model.getFilteredPlantListById(HardinessZone.ZONE_8A, 20L);
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());
plantListResult = model.getFilteredPlantListByString(HardinessZone.ZONE_8A, "");
assertEquals(3, plantListResult.size());
}
@Test
void getFilteredPlantListByPlantingSaison() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListByPlantingSaison(HardinessZone.ZONE_8A, MonthDay.of(4, 4), MonthDay.of(8, 4));
assertEquals(2, plantListResult.size());
assertEquals(examplePlantList.get(2), plantListResult.get(0));
assertEquals(examplePlantList.get(1), plantListResult.get(1));
}
@Test
void getFilteredPlantListByHarvestSaison() throws HardinessZoneNotSetException, IOException {
model.setCurrentZone(HardinessZone.ZONE_1A);
List<Plant> plantListResult = model.getFilteredPlantListByHarvestSaison(HardinessZone.ZONE_8A, MonthDay.of(4, 4), MonthDay.of(8, 4));
assertEquals(2, plantListResult.size());
assertEquals(examplePlantList.get(1), plantListResult.get(0));
assertEquals(examplePlantList.get(0), plantListResult.get(1));
}
}