Compare commits

...

34 Commits

Author SHA1 Message Date
giavaphi 6e98517013 Merge pull request #90 from schrom01/dev
Update of Readme and removed old Documents
2022-12-11 17:53:11 +01:00
schrom01 a81c073407 updated README.md 2022-12-11 17:50:39 +01:00
schrom01 aa9c543624 Merge remote-tracking branch 'origin/dev' into dev 2022-12-11 17:49:44 +01:00
schrom01 95748c79b1 updated README.md 2022-12-11 17:49:20 +01:00
giavaphi 01ddb38ccb Merge pull request #89 from schrom01/dev
Final Version for M3 Beta Release
2022-12-11 17:15:50 +01:00
giavaphi 3a50c2655d delete of unused todos 2022-12-11 17:09:49 +01:00
giavaphi de01503598 Merge pull request #88 from schrom01/feature_weather
Feature weather
2022-12-11 17:02:59 +01:00
giavaphi a8a693296e delete unused function 2022-12-11 16:45:07 +01:00
giavaphi a519393fc7 small change garden plant description 2022-12-11 16:23:05 +01:00
Gian-Andrea Hutter 2864c54c72 Merge branch 'dev' into feature_weather 2022-12-11 16:16:34 +01:00
Gian-Andrea Hutter a20edae4b8 #23 refactoring of the WeatherGradenTaskPlanner 2022-12-11 16:16:06 +01:00
giavaphi 2dd8cffda2 delete unused imports 2022-12-11 16:06:16 +01:00
giavaphi 3f51adcbd0 show screenshots in tutorial 2022-12-11 16:04:28 +01:00
giavaphi 4acd328286 Merge pull request #87 from schrom01/feature_tutorial-screenshots_M3
added screenshot pngs (whoops)
2022-12-11 15:29:36 +01:00
Gian-Andrea Hutter dbba4e2662 Merge branch 'dev' into feature_weather 2022-12-11 15:15:19 +01:00
schrom01 6aeda395c3 Javadocs and code cleanup 2022-12-11 14:58:15 +01:00
schrom01 7741569659 Javadocs and code cleanup 2022-12-11 14:57:59 +01:00
schrom01 27b8d1754e Javadocs and code cleanup 2022-12-11 14:25:57 +01:00
giavaphi dc0830120f small fixes 2022-12-11 07:59:34 +01:00
giavaphi 39bff805ac small fixes 2022-12-11 07:44:03 +01:00
giavaphi 3ebbb0e0e3 small fixes 2022-12-11 07:19:06 +01:00
Roman Schenk 8a2119028c Merge pull request #86 from schrom01/fix_tasklist_filteringPastTasks
Fix tasklist filtering past tasks
2022-12-10 14:00:24 +01:00
giavaphi 083d934472 Merge pull request #85 from schrom01/feature_weather
#23 bugfix testclass WeatherGradenTaskPlannerTest and bugfix Task and…
2022-12-10 13:58:26 +01:00
schrom01 1b096035a7 Merge branch 'dev' into fix_tasklist_filteringPastTasks 2022-12-10 13:54:42 +01:00
schrom01 0074d43364 fixed problem "showing task multiple times in in schedule" 2022-12-10 13:52:33 +01:00
Gian-Andrea Hutter 08d40d8b80 Merge branch 'dev' into feature_weather 2022-12-10 13:48:50 +01:00
Gian-Andrea Hutter 3bda390708 #23 bugfix testclass WeatherGradenTaskPlannerTest and bugfix Task and WeatherGradenTaskPlanner 2022-12-10 13:47:54 +01:00
Roman Schenk c6952aba55 Merge pull request #81 from schrom01/feature_updaeTaskListViewOnUpdate_M3
show all tasks in scheduler
2022-12-10 13:41:04 +01:00
Roman Schenk 807a9017ad Merge pull request #82 from schrom01/fix_tasklist_filteringPastTasks
Fix tasklist filtering past tasks
2022-12-10 13:40:55 +01:00
Roman Schenk c134025408 Merge pull request #83 from schrom01/tests_extended_M3
extending tests and adding integration test
2022-12-10 13:40:46 +01:00
Roman Schenk 1e95e0ff30 Merge pull request #84 from schrom01/feature_tutorial-screenshots_M3
added screenshots to tutorial
2022-12-10 13:40:38 +01:00
Elias Csomor 76197a19df extending tests and adding integration test
and better precision when comparing results
2022-12-10 12:48:06 +01:00
schrom01 5f7d690875 fixed not showing past tasks 2022-12-09 21:27:13 +01:00
giavaphi 96dc0ad827 fix show all tasks 2022-12-09 19:38:22 +01:00
47 changed files with 466 additions and 495 deletions

View File

@ -1,32 +1,19 @@
# PM3-HS22-IT21b_WIN-Team1 # GardenPlanner
PM3 FivePlants Gartenverwaltung
## Class Diagram ## Installations- und Gebrauchsanweisung
Umletino: https://www.umletino.com/umletino.html ### Vorbedingungen
- Das Java Runtime Environment (JRE) muss in der Version 17 auf Ihrem Computer installiert sein.
- Das Java Development Kit (JDK) muss in der Version 17 auf Ihrem Computer installiert sein.
Draft File: doc/ClassDiagramDraft.uxf ### Installation und Starten der Applikation
1. Laden sie die neuste Version der Applikation herunter. Sie finden die Applikation hier:
https://github.zhaw.ch/schrom01/PM3-HS22-IT21b_WIN-Team1/tags
2. Extrahieren sie die heruntergeladene ZIP-Datei
3. Öffnen sie ein Kommandozeilenfenster und navigieren sie an den Speicherort der Entpack-ten Applikation.
4. Führen sie den Befehl: «./gradlew.bat run» (auf Windows) oder «./gradlew run» (auf ma-cOS und Linux) aus.
## Branch model ### Anwendung
- production branch: `main` Eine Bedienungsanleitung finden Sie im Dokument ["Technischer Bericht II"](doc/PM3-HS22-IT21b_WIN-Technischer_Bericht_II-Team1.pdf) im Kapitel 6.3.3.
This branch has a working version of the code. ## Projektdokumentation
Die gesamte Projektdokumentation ist im Dokument ["Technischer Bericht II"](doc/PM3-HS22-IT21b_WIN-Technischer_Bericht_II-Team1.pdf) zu finden.
- 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.).
## User Manual
- Search Plant List: if first Char is '#': only exact match in ID.

View File

@ -1,92 +0,0 @@
<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLClass</id><coordinates><x>720</x><y>30</y><w>100</w><h>30</h></coordinates><panel_attributes>Main</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1240</x><y>250</y><w>300</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
PlantDatabase
--
+ getPlantList(zone: HardinessZone): List&lt;Plant&gt;
+ getPlant(id: long): Optional&lt;Plant&gt;</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>940</x><y>580</y><w>220</w><h>40</h></coordinates><panel_attributes>TaskListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1240</x><y>10</y><w>300</w><h>180</h></coordinates><panel_attributes>&lt;&lt;Record&gt;&gt;
Plant
--
+ id: long
+ name: String
+ description: String
+ spacing: int
+ lifecycle: List&lt;GrowthPhase&gt;
--
+ calculateStartDate(harvestDate: Date): Date
+ generateTasks()
</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1210</x><y>580</y><w>210</w><h>120</h></coordinates><panel_attributes>TaskListModel
--
- tasks: ListProperty&lt;Task&gt;
- taskDb: TaskDatabase
--
+ getTask(id: long): Optional&lt;Task&gt;
+ saveTask(task: Task)
+ removeTask(task: Task)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>590</x><y>560</y><w>250</w><h>110</h></coordinates><panel_attributes>GardenPlanModel
--
- tasks: ListProperty&lt;Task&gt;
- gardenPlan: GardenPlan
--
+ savePlanting(planting: UserPlanting)
+ removePlanting(planting: UserPlanting)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>340</x><y>550</y><w>180</w><h>80</h></coordinates><panel_attributes>GardenPlanController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1660</x><y>720</y><w>490</w><h>240</h></coordinates><panel_attributes>Task
--
+ id: long
+ name: String {readOnly}
+ description: String {readOnly}
+ startDate: Date {readOnly}
+ isReadOnly: boolean {readOnly}
- interval: int
- endDate: Date
--
+ Task(name: String, description: String, startDate: String, isReadOnly: boolean): Task
+ withInterval(interval: int): Task
+ withEndDate(endDate: Date): Task
+ withId(id: long): Task
--
+ getInterval(): Optional&lt;int&gt;
+ getEndDate(): Optional&lt;Date&gt;</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1170</x><y>760</y><w>280</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
TaskDatabase
--
+ getTaskList(start: Date, end: Date): List&lt;Task&gt;
+ saveTask(Task task) throws ??Exception
+ removeTask(Task task) throws ??Exception</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>780</x><y>310</y><w>100</w><h>100</h></coordinates><panel_attributes>MainWindow</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>440</x><y>180</y><w>180</w><h>130</h></coordinates><panel_attributes>MainWindowController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1340</x><y>1070</y><w>210</w><h>70</h></coordinates><panel_attributes>NotificationService
--
- taskDb: TaskDatabase
--
+ tick()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1640</x><y>1210</y><w>240</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
WeatherProvider
--
+ getWeatherForecast: WeatherForecast</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>1040</y><w>400</w><h>100</h></coordinates><panel_attributes>WeatherService
--
- weatherPovider: WeatherProvider
- taskDb: TaskDatabase
--
+ WeatherService(provider: WeatherProvider, taskDb: TaskDatabase)
- updateTasks()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>10</y><w>260</w><h>150</h></coordinates><panel_attributes>&lt;&lt;Record&gt;&gt;
GrowthPhase
--
+ startDate: Date
+ endDate: Date
+ type: GrowthPhaseType
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1530</x><y>80</y><w>110</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>90;10;10;10</additional_attributes></element><element><id>Text</id><coordinates><x>420</x><y>0</y><w>190</w><h>70</h></coordinates><panel_attributes>Note:
--
{final, readOnly} omitted on public data fields in &lt;&lt;Record&gt;&gt; Entities for clarity
style=wordwrap</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1440</x><y>820</y><w>240</w><h>30</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>220;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1300</x><y>690</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;70;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>600</x><y>980</y><w>210</w><h>120</h></coordinates><panel_attributes>&lt;&lt;Record&gt;&gt;
UserPlanting
--
+ plantId: long
+ asSowing: boolean
+ startDate: Date
+ area: int</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1380</x><y>180</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;10;70</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1950</x><y>10</y><w>140</w><h>120</h></coordinates><panel_attributes>&lt;&lt;Enumeration&gt;&gt;
GrowthPhaseType
--
SOW
PLANT
HARVEST</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1870</x><y>70</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1150</x><y>590</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>60;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>700</x><y>890</y><w>30</w><h>110</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>510</x><y>580</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>570</x><y>760</y><w>280</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
GardenPlan
--
+ getPlantings(): List&lt;UserPlanting&gt;
+ addPlanting(plantId: long, startDate)
+ savePlanting(planting: UserPlanting)
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>690</x><y>660</y><w>30</w><h>120</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;100;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>60</x><y>390</y><w>180</w><h>80</h></coordinates><panel_attributes>PlantingCell
{extends ListCell&lt;&gt;}</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>0</x><y>540</y><w>290</w><h>80</h></coordinates><panel_attributes>PlantingCellFactory
{implements Callback&lt;ListView&lt;UserPlanting&gt; &gt;}</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>140</x><y>460</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;10;80</additional_attributes></element><element><id>Relation</id><coordinates><x>1750</x><y>1130</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;80;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1350</x><y>890</y><w>120</w><h>200</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;100;180</additional_attributes></element><element><id>Relation</id><coordinates><x>1380</x><y>890</y><w>260</w><h>220</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;240;200</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1090</x><y>1060</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonTaskDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1180</x><y>890</y><w>30</w><h>190</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>10;10;10;170</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1620</x><y>310</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonPlantDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1530</x><y>320</y><w>110</w><h>30</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>10;10;90;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>300</x><y>800</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonGardenPlan</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>490</x><y>810</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>280</x><y>570</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;60;10</additional_attributes></element><element><id>Relation</id><coordinates><x>850</x><y>400</y><w>220</w><h>200</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>200;180;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>440</x><y>400</y><w>390</w><h>170</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;150;370;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>850</x><y>120</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>760</x><y>50</y><w>90</w><h>280</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>70;260;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>610</x><y>230</y><w>190</w><h>140</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;10;170;120</additional_attributes></element><element><id>Relation</id><coordinates><x>870</x><y>170</y><w>80</w><h>210</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>60;10;10;190</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1020</x><y>290</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListModel</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1000</x><y>150</y><w>110</w><h>160</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>90;140;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1170</x><y>310</y><w>90</w><h>30</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>70;10;10;10</additional_attributes></element></diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,7 +0,0 @@
<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLPackage</id><coordinates><x>390</x><y>60</y><w>340</w><h>100</h></coordinates><panel_attributes>UI</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>180</y><w>460</w><h>120</h></coordinates><panel_attributes>Domain</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>390</x><y>330</y><w>460</w><h>120</h></coordinates><panel_attributes>Technical Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>90</y><w>100</w><h>60</h></coordinates><panel_attributes>Views (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>IO</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>400</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Jackson</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Types</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>220</y><w>100</w><h>60</h></coordinates><panel_attributes>Models</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>90</y><w>110</w><h>60</h></coordinates><panel_attributes>Controllers (JFX)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>510</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>Logging</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>620</x><y>370</y><w>100</w><h>60</h></coordinates><panel_attributes>JavaFX</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>220</y><w>110</w><h>60</h></coordinates><panel_attributes>Services</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLPackage</id><coordinates><x>730</x><y>370</y><w>110</w><h>60</h></coordinates><panel_attributes>HTTP/API</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>150</y><w>90</w><h>70</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>70;10;10;50</additional_attributes></element><element><id>Relation</id><coordinates><x>570</x><y>290</y><w>110</w><h>80</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>90;10;10;60</additional_attributes></element><element><id>Relation</id><coordinates><x>340</x><y>120</y><w>350</w><h>400</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>60;10;10;10;10;380;330;380;330;310</additional_attributes></element><element><id>Relation</id><coordinates><x>770</x><y>270</y><w>30</w><h>120</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>Relation</id><coordinates><x>360</x><y>250</y><w>60</w><h>180</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>40;10;10;10;10;160;40;160</additional_attributes></element><element><id>Relation</id><coordinates><x>610</x><y>120</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=.&gt;
</panel_attributes><additional_attributes>10;10;50;10;50;100</additional_attributes></element></diagram>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

View File

@ -1,144 +0,0 @@
<diagram program="umletino" version="15.0.0"><zoom_level>10</zoom_level><element><id>UMLClass</id><coordinates><x>482</x><y>360</y><w>100</w><h>30</h></coordinates><panel_attributes>Main</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1082</x><y>380</y><w>370</w><h>100</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
PlantDatabase
--
+ getPlantList(zone: HardinessZone): List&lt;Plant&gt;
+ getPlantById(zone: HardinessZone id: long): Optional&lt;Plant&gt;</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>672</x><y>710</y><w>220</w><h>40</h></coordinates><panel_attributes>TaskListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1132</x><y>110</y><w>300</w><h>180</h></coordinates><panel_attributes>&lt;&lt;Record&gt;&gt;
Plant
--
+ id: long
+ name: String
+ description: String
+ spacing: int
+ lifecycle: List&lt;GrowthPhase&gt;
--
+ calculateStartDate(harvestDate: Date): Date
+ generateTasks()
</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>942</x><y>710</y><w>210</w><h>120</h></coordinates><panel_attributes>TaskListModel
--
- tasks: ListProperty&lt;Task&gt;
- taskDb: TaskDatabase
--
+ getTask(id: long): Optional&lt;Task&gt;
+ saveTask(task: Task)
+ removeTask(task: Task)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>322</x><y>690</y><w>250</w><h>120</h></coordinates><panel_attributes>GardenPlanModel
--
- tasks: ListProperty&lt;Crop&gt;
- gardenPlan: GardenPlan
--
+ plantAsCrop(planting: UserPlanting)
+ removePlanting(planting: UserPlanting)</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>72</x><y>680</y><w>180</w><h>80</h></coordinates><panel_attributes>GardenPlanController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1362</x><y>830</y><w>490</w><h>240</h></coordinates><panel_attributes>Task
--
+ id: long
+ name: String {readOnly}
+ description: String {readOnly}
+ startDate: Date {readOnly}
+ isOptional: boolean {readOnly}
- interval: int
- endDate: Date
--
+ Task(name: String, description: String, startDate: String, isReadOnly: boolean): Task
+ withInterval(interval: int): Task
+ withEndDate(endDate: Date): Task
+ withId(id: long): Task
--
+ getInterval(): Optional&lt;int&gt;
+ getEndDate(): Optional&lt;Date&gt;</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>902</x><y>930</y><w>280</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
TaskDatabase
--
+ getTaskList(start: Date, end: Date): List&lt;Task&gt;
+ saveTask(Task task) throws ??Exception
+ removeTask(Task task) throws ??Exception</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>442</x><y>440</y><w>170</w><h>80</h></coordinates><panel_attributes>MainWindowController</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>962</x><y>1310</y><w>210</w><h>70</h></coordinates><panel_attributes>NotificationService
--
- taskDb: TaskDatabase
--
+ tick()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1412</x><y>1310</y><w>240</w><h>90</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
WeatherProvider
--
+ getWeatherForecast: WeatherForecast</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1392</x><y>1150</y><w>400</w><h>100</h></coordinates><panel_attributes>WeatherService
--
- weatherPovider: WeatherProvider
- taskDb: TaskDatabase
--
+ WeatherService(provider: WeatherProvider, taskDb: TaskDatabase)
- updateTasks()</panel_attributes><additional_attributes></additional_attributes></element><element><id>UMLClass</id><coordinates><x>1502</x><y>110</y><w>260</w><h>150</h></coordinates><panel_attributes>&lt;&lt;Record&gt;&gt;
GrowthPhase
--
+ startDate: MonthDay
+ endDate: MonthDay
+ type: GrowthPhaseType
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1422</x><y>180</y><w>100</w><h>40</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;&gt;
m1=*
m2=1</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Text</id><coordinates><x>152</x><y>130</y><w>190</w><h>70</h></coordinates><panel_attributes>Note:
--
{final, readOnly} omitted on public data fields in &lt;&lt;Record&gt;&gt; Entities for clarity
style=wordwrap</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1172</x><y>970</y><w>210</w><h>50</h></coordinates><panel_attributes>lt=&lt;.
m1=*
m2=1
returns &gt;</panel_attributes><additional_attributes>190;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>1032</x><y>820</y><w>140</w><h>130</h></coordinates><panel_attributes>lt=&lt;-
m1=1 external database
m2=1 internal list
accesses</panel_attributes><additional_attributes>10;110;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>322</x><y>1120</y><w>240</w><h>150</h></coordinates><panel_attributes>Crop
--
- cropId: Long
+ plantId: long {final, readOnly}
+ startDate: LocalDate {final, readOnly}
+ area: Double
--
+ withId(long): Crop
+ withArea(double): Crop
--
+ getCropId(): Optional&lt;Long&gt;</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1262</x><y>280</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=&lt;.
m1=*
m2=1
returns</panel_attributes><additional_attributes>10;10;10;100</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1632</x><y>290</y><w>130</w><h>100</h></coordinates><panel_attributes>&lt;&lt;Enumeration&gt;&gt;
GrowthPhaseType
--
SOW
PLANT
HARVEST</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1582</x><y>250</y><w>70</w><h>120</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;
m1=1
m2=*</panel_attributes><additional_attributes>50;90;10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>882</x><y>720</y><w>80</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>60;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>432</x><y>1020</y><w>110</w><h>120</h></coordinates><panel_attributes>lt=&lt;.
m1=*
m2=1
returns / saves</panel_attributes><additional_attributes>10;100;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>242</x><y>710</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>302</x><y>890</y><w>280</w><h>140</h></coordinates><panel_attributes>&lt;&lt;Interface&gt;&gt;
GardenPlan
--
+ getPlantings(): List&lt;UserPlanting&gt;
+ addPlanting(plantId: long, startDate)
+ savePlanting(planting: UserPlanting)
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>422</x><y>800</y><w>80</w><h>110</h></coordinates><panel_attributes>lt=&lt;.
m1=1
m2=1
accesses</panel_attributes><additional_attributes>10;90;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1522</x><y>1240</y><w>30</w><h>90</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;70;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1062</x><y>1060</y><w>80</w><h>270</h></coordinates><panel_attributes>lt=&lt;-
m1=1
m2=1
accesses</panel_attributes><additional_attributes>10;10;10;250</additional_attributes></element><element><id>Relation</id><coordinates><x>1142</x><y>1060</y><w>270</w><h>170</h></coordinates><panel_attributes>lt=&lt;-
m1=1
m2=1
adds Tasks</panel_attributes><additional_attributes>10;10;10;140;250;140</additional_attributes></element><element><id>UMLClass</id><coordinates><x>822</x><y>1140</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonTaskDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>912</x><y>1060</y><w>30</w><h>100</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>10;10;10;80</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1562</x><y>430</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonPlantDatabase</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1442</x><y>440</y><w>140</w><h>30</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>10;10;120;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>32</x><y>930</y><w>200</w><h>50</h></coordinates><panel_attributes>JsonGardenPlan</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>222</x><y>940</y><w>100</w><h>30</h></coordinates><panel_attributes>lt=&lt;&lt;-</panel_attributes><additional_attributes>80;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>582</x><y>510</y><w>220</w><h>220</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>200;200;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>172</x><y>510</y><w>340</w><h>190</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;170;320;10</additional_attributes></element><element><id>UMLClass</id><coordinates><x>582</x><y>250</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListController</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>522</x><y>380</y><w>30</w><h>80</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>10;60;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>602</x><y>300</y><w>80</w><h>210</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>60;10;10;190</additional_attributes></element><element><id>UMLClass</id><coordinates><x>732</x><y>390</y><w>160</w><h>60</h></coordinates><panel_attributes>PlantListModel</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>732</x><y>280</y><w>90</w><h>130</h></coordinates><panel_attributes>lt=&lt;.</panel_attributes><additional_attributes>70;110;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>882</x><y>400</y><w>220</w><h>70</h></coordinates><panel_attributes>lt=&lt;-
m1=1\nexternal\ndatabase
m2=1\ninternal\nlist
accesses &gt;</panel_attributes><additional_attributes>200;20;10;20</additional_attributes></element><element><id>Relation</id><coordinates><x>582</x><y>0</y><w>190</w><h>50</h></coordinates><panel_attributes>lt=-
m1=0..n
m2=0..1
teaches to &gt;</panel_attributes><additional_attributes>10;20;170;20</additional_attributes></element><element><id>UMLClass</id><coordinates><x>1412</x><y>530</y><w>420</w><h>200</h></coordinates><panel_attributes>TaskTemplate
--
+ name: String {readOnly}
+ description: String {readOnly}
+ relativeStartDate: int {readOnly}
- interval: Integer
- relativeEndDate: Integer
- isOptional: boolean
--
+ Task(name: String, description: String, startDate: String): TaskTemplate
+ setRelativeEndDate(relativeEndDate: int)
+ setInterval(interval: Integer)
+ generateTask(realStartDate: LocalDate): Task
</panel_attributes><additional_attributes></additional_attributes></element><element><id>Relation</id><coordinates><x>1752</x><y>180</y><w>130</w><h>490</h></coordinates><panel_attributes>lt=&lt;-&gt;&gt;&gt;&gt;&gt;
m1=*
m2=1</panel_attributes><additional_attributes>80;460;110;460;110;10;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>1602</x><y>720</y><w>90</w><h>130</h></coordinates><panel_attributes>lt=&lt;.
m1=*
m2=1
generates</panel_attributes><additional_attributes>10;110;10;10</additional_attributes></element><element><id>Relation</id><coordinates><x>562</x><y>770</y><w>400</w><h>40</h></coordinates><panel_attributes>lt=&lt;-
delegates generating Tasks</panel_attributes><additional_attributes>380;20;10;20</additional_attributes></element></diagram>

File diff suppressed because one or more lines are too long

View File

@ -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

View File

@ -12,6 +12,7 @@ import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Pest; import ch.zhaw.gartenverwaltung.types.Pest;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task; import ch.zhaw.gartenverwaltung.types.Task;
import javafx.application.Platform;
import javafx.beans.property.ListProperty; import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections; import javafx.collections.FXCollections;
@ -133,8 +134,14 @@ public class CropDetailController {
initializeTaskListProperty(crop); initializeTaskListProperty(crop);
TaskList.TaskListObserver taskListObserver = newTaskList -> { TaskList.TaskListObserver taskListObserver = newTaskList -> {
Platform.runLater(() -> {
taskListProperty.clear(); taskListProperty.clear();
try {
taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get())); taskListProperty.addAll(gardenSchedule.getTaskListForCrop(crop.getCropId().get()));
} catch (IOException e) {
e.printStackTrace();
}
});
}; };
gardenSchedule.setTaskListObserver(taskListObserver); gardenSchedule.setTaskListObserver(taskListObserver);
@ -205,7 +212,6 @@ public class CropDetailController {
taskListProperty.clear(); taskListProperty.clear();
taskListProperty.addAll(taskList); taskListProperty.addAll(taskList);
} catch (IOException e) { } catch (IOException e) {
// TODO: Alert
LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause()); LOG.log(Level.SEVERE, "Could not get task list for crop", e.getCause());
} }
}); });
@ -414,9 +420,7 @@ public class CropDetailController {
if (buttonType == ButtonType.OK) { if (buttonType == ButtonType.OK) {
try { try {
gardenSchedule.removeTask(task); gardenSchedule.removeTask(task);
//setTaskListProperty(this.crop);
} catch (IOException e) { } catch (IOException e) {
// TODO: Show error alert
LOG.log(Level.SEVERE, "Could not remove crop.", e); LOG.log(Level.SEVERE, "Could not remove crop.", e);
} }
} }

View File

@ -13,30 +13,46 @@ import javafx.stage.Stage;
import java.io.IOException; import java.io.IOException;
import java.util.Timer; import java.util.Timer;
/**
* Main class of the Application
*/
public class Main extends Application { public class Main extends Application {
Timer backGroundTaskTimer = new Timer(); Timer backGroundTaskTimer = new Timer();
BackgroundTasks backgroundTasks; BackgroundTasks backgroundTasks;
/**
* Method which is automatically called if Application is starting. It loads the scenes to stage and shows the stage.
* It creates a new Instance of BackgroundTasks and schedules them with a Timer instance to execute them every minute.
* @param stage Stage to show
* @throws IOException If loading Scenes can not access the fxml Resource File
*/
@Override @Override
public void start(Stage stage) throws IOException { public void start(Stage stage) throws IOException {
AppLoader appLoader = new AppLoader(); AppLoader appLoader = new AppLoader();
backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class));
appLoader.loadSceneToStage("MainFXML.fxml", stage); appLoader.loadSceneToStage("MainFXML.fxml", stage);
stage.setTitle("Gartenverwaltung"); stage.setTitle("Gartenverwaltung");
stage.show(); stage.show();
backgroundTasks = new BackgroundTasks((TaskList) appLoader.getAppDependency(TaskList.class),(CropList) appLoader.getAppDependency(CropList.class), (PlantList) appLoader.getAppDependency(PlantList.class));
backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 60000); backGroundTaskTimer.scheduleAtFixedRate(backgroundTasks, 0, 60000);
} }
/**
* Method which is automatically called when application is stopped.
* It cancels the timer to not execute the background tasks anymore.
*/
@Override @Override
public void stop(){ public void stop(){
backGroundTaskTimer.cancel(); backGroundTaskTimer.cancel();
} }
/**
* The Main method launches the application
* @param args There are no arguments needed.
*/
public static void main(String[] args) { public static void main(String[] args) {
launch(); launch();
} }

View File

@ -56,7 +56,6 @@ public class MainFXMLController {
@FXML @FXML
void goToHome() { void goToHome() {
showPaneAsMainView("Home.fxml"); showPaneAsMainView("Home.fxml");
styleChangeButton(home_button);
} }
/** /**
@ -65,7 +64,6 @@ public class MainFXMLController {
@FXML @FXML
void goToMyPlants() { void goToMyPlants() {
showPaneAsMainView("MyGarden.fxml"); showPaneAsMainView("MyGarden.fxml");
styleChangeButton(myGarden_button);
} }
/** /**
@ -74,7 +72,6 @@ public class MainFXMLController {
@FXML @FXML
void goToMySchedule() { void goToMySchedule() {
showPaneAsMainView("MySchedule.fxml"); showPaneAsMainView("MySchedule.fxml");
styleChangeButton(mySchedule_button);
} }
/** /**
@ -160,15 +157,6 @@ public class MainFXMLController {
appLoader.loadAndCacheFxml("Plants.fxml"); appLoader.loadAndCacheFxml("Plants.fxml");
} }
private void styleChangeButton(Button button) {
/*home_button.setStyle("-fx-background-color: rgb(0,128,0)");
myGarden_button.setStyle("-fx-background-color: rgb(0,128,0)");
mySchedule_button.setStyle("-fx-background-color: rgb(0,128,0)");
settings_button.setStyle("-fx-background-color: rgb(0,128,0)");
tutorial_button.setStyle("-fx-background-color: rgb(0,128,0)");
button.setStyle("-fx-background-color: darkgreen");*/
}
/** /**
* loads the default FXML File * loads the default FXML File
* {@inheritDoc} * {@inheritDoc}
@ -179,7 +167,6 @@ public class MainFXMLController {
try { try {
preloadPanes(); preloadPanes();
showPaneAsMainView("MyGarden.fxml"); showPaneAsMainView("MyGarden.fxml");
styleChangeButton(myGarden_button);
} catch (IOException e) { } catch (IOException e) {
LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e); LOG.log(Level.SEVERE, "Failed to load FXML-Pane!", e);
} }

View File

@ -19,6 +19,7 @@ import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane; import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox; import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority; import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Modality; import javafx.stage.Modality;
import javafx.stage.Stage; import javafx.stage.Stage;
@ -99,7 +100,6 @@ public class MyGardenController {
* @throws IOException exception * @throws IOException exception
*/ */
private HBox createHBoxForListView(Crop crop) throws HardinessZoneNotSetException, IOException { private HBox createHBoxForListView(Crop crop) throws HardinessZoneNotSetException, IOException {
//ToDo add better design
Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get(); Plant plant = plantList.getPlantById(Settings.getInstance().getCurrentHardinessZone(), crop.getPlantId()).get();
HBox hBox = new HBox(10); HBox hBox = new HBox(10);
ImageView imageView = new ImageView(); ImageView imageView = new ImageView();
@ -112,8 +112,23 @@ public class MyGardenController {
} }
hBox.setMinHeight(100); hBox.setMinHeight(100);
Label label = new Label(plant.name()); Label label = new Label(plant.name());
label.setMaxWidth(2000); label.setMinWidth(100);
HBox.setHgrow(label, Priority.ALWAYS);
VBox vbox = new VBox(10);
HBox startDateHBox = new HBox(10);
Label startDateDescription = new Label("Start Date:");
startDateDescription.setMinWidth(75);
Label startDate = new Label(crop.getStartDate().toString());
startDateHBox.getChildren().addAll(startDateDescription, startDate);
HBox endDateHBox = new HBox(10);
Label endDateDescription = new Label("End Date:");
endDateDescription.setMinWidth(75);
Label endDate = new Label(crop.getStartDate().plusDays(plant.timeToHarvest(0)).toString());
endDateHBox.getChildren().addAll(endDateDescription, endDate);
vbox.getChildren().addAll(startDateHBox, endDateHBox);
vbox.setMaxWidth(2000);
HBox.setHgrow(vbox, Priority.ALWAYS);
Button details = new Button(); Button details = new Button();
Button delete = new Button(); Button delete = new Button();
@ -125,7 +140,7 @@ public class MyGardenController {
details.setOnAction(getGoToCropDetailEvent(crop)); details.setOnAction(getGoToCropDetailEvent(crop));
delete.setOnAction(getDeleteCropEvent(crop)); delete.setOnAction(getDeleteCropEvent(crop));
hBox.getChildren().addAll(imageView, label, details, delete); hBox.getChildren().addAll(imageView, label, vbox, details, delete);
return hBox; return hBox;
} }
@ -158,7 +173,6 @@ public class MyGardenController {
stage.setResizable(true); stage.setResizable(true);
stage.showAndWait(); stage.showAndWait();
} catch (IOException | PlantNotFoundException e) { } catch (IOException | PlantNotFoundException e) {
// TODO: show error alert
LOG.log(Level.SEVERE, "Could not load plant details.", e); LOG.log(Level.SEVERE, "Could not load plant details.", e);
} }
}; };
@ -204,7 +218,6 @@ public class MyGardenController {
try { try {
garden.removeCrop(crop); garden.removeCrop(crop);
} catch (IOException e) { } catch (IOException e) {
// TODO: Show error alert
LOG.log(Level.SEVERE, "Could not remove crop.", e); LOG.log(Level.SEVERE, "Could not remove crop.", e);
} }
} }

View File

@ -3,15 +3,15 @@ package ch.zhaw.gartenverwaltung;
import ch.zhaw.gartenverwaltung.bootstrap.AfterInject; import ch.zhaw.gartenverwaltung.bootstrap.AfterInject;
import ch.zhaw.gartenverwaltung.bootstrap.Inject; import ch.zhaw.gartenverwaltung.bootstrap.Inject;
import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.io.PlantList;
import ch.zhaw.gartenverwaltung.io.TaskList;
import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.Garden;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.models.GardenSchedule; import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.types.Crop; import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Plant; import ch.zhaw.gartenverwaltung.types.Plant;
import ch.zhaw.gartenverwaltung.types.Task; import ch.zhaw.gartenverwaltung.types.Task;
import javafx.application.Platform;
import javafx.beans.property.ListProperty; import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.event.EventHandler; import javafx.event.EventHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -24,6 +24,7 @@ import javafx.scene.layout.VBox;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -51,9 +52,15 @@ public class MyScheduleController {
@FXML @FXML
private ListView<Crop> scheduledPlants_listview; private ListView<Crop> scheduledPlants_listview;
@FXML
private void showAllTasks(ActionEvent actionEvent) throws IOException {
gardenSchedule.getTasksUpcomingWeek();
scheduledPlants_listview.getSelectionModel().clearSelection();
}
@AfterInject @AfterInject
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void init() { public void init() throws IOException {
setCellFactoryCropListView(); setCellFactoryCropListView();
setCellFactoryTaskListView(); setCellFactoryTaskListView();
scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops()); scheduledPlants_listview.itemsProperty().bind(garden.getPlantedCrops());
@ -61,6 +68,19 @@ public class MyScheduleController {
week_listView.itemsProperty().bind(taskListProperty); week_listView.itemsProperty().bind(taskListProperty);
lookForSelectedListEntries(); lookForSelectedListEntries();
information_label.setText(""); information_label.setText("");
gardenSchedule.getTasksUpcomingWeek();
TaskList.TaskListObserver taskListObserver = newTaskList -> {
Platform.runLater(() -> {
try {
gardenSchedule.getTasksUpcomingWeek();
scheduledPlants_listview.getSelectionModel().clearSelection();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
};
gardenSchedule.setTaskListObserver(taskListObserver);
} }
/** /**
@ -81,6 +101,8 @@ public class MyScheduleController {
* set cellFactory for the crops. * set cellFactory for the crops.
*/ */
private void setCellFactoryCropListView() { private void setCellFactoryCropListView() {
MultipleSelectionModel<Crop> selectionModel = scheduledPlants_listview.getSelectionModel();
selectionModel.setSelectionMode(SelectionMode.MULTIPLE);
scheduledPlants_listview.setCellFactory(param -> new ListCell<>() { scheduledPlants_listview.setCellFactory(param -> new ListCell<>() {
@Override @Override
protected void updateItem(Crop crop, boolean empty) { protected void updateItem(Crop crop, boolean empty) {
@ -133,8 +155,6 @@ public class MyScheduleController {
} else { } else {
gardenSchedule.getTasksUpcomingWeek(); gardenSchedule.getTasksUpcomingWeek();
} }
//taskListProperty.clear();
//taskListProperty.addAll(taskLists);
} }
/** /**
@ -189,6 +209,12 @@ public class MyScheduleController {
alert.setHeaderText("Are you sure you have completed this task?"); alert.setHeaderText("Are you sure you have completed this task?");
alert.setContentText("Confirming that you have completed the task will remove it from the schedule."); alert.setContentText("Confirming that you have completed the task will remove it from the schedule.");
DialogPane dialogPane = alert.getDialogPane();
dialogPane.getStylesheets().add(
Objects.requireNonNull(getClass().getResource("bootstrap/dialogStyle.css")).toExternalForm());
dialogPane.getStyleClass().add("myDialog");
alert.showAndWait() alert.showAndWait()
.ifPresent(buttonType -> { .ifPresent(buttonType -> {
if (buttonType == ButtonType.OK) { if (buttonType == ButtonType.OK) {
@ -202,5 +228,4 @@ public class MyScheduleController {
}); });
} }
} }

View File

@ -6,21 +6,58 @@ import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import java.util.List; import java.util.List;
import java.util.Objects;
/**
* Singleton Class to store default Settings and User Settings
*/
public class Settings { public class Settings {
private static final Settings instance; /*
private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A; * The Class instance to use everywhere
private final BooleanProperty showTutorial = new SimpleBooleanProperty(false); */
private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true);
// Gmail Address: pm3.hs22.it21b.win.team1@gmail.com
// Gmail Passwort: Gartenverwaltung.PM3.2022
// E-Mail Inbox: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1
private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com";
private String mailNotificationSubjectTemplate = "Task %s is due!"; // {0} = Task Name
private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s"; // {0} = Task Name, {1} = plantname, {2} = nextExecution, {3} = Task description
private static final Settings instance;
/**
* The current Hardiness zone initialized as default value Zone_8A
*/
private HardinessZone currentHardinessZone = HardinessZone.ZONE_8A;
/**
* Setting to show or hide the Tutorial in Main Menu
*/
private final BooleanProperty showTutorial = new SimpleBooleanProperty(false);
/**
* The SMTP Credentials which are used to send E-Mail Notifications
* The following Google Account is created for Testing:
* E-Mail Address: pm3.hs22.it21b.win.team1@gmail.com
* Account Password: Gartenverwaltung.PM3.2022
* SMTP Password: bisefhhjtrrhtoqr
*/
private SmtpCredentials smtpCredentials = new SmtpCredentials("imap.gmail.com", "587", "pm3.hs22.it21b.win.team1@gmail.com", "pm3.hs22.it21b.win.team1@gmail.com", "bisefhhjtrrhtoqr", true);
/**
* List of Receivers for E-Mailnotifications. Multiple E-Mailadresses can be separated by ";"
* Following Public E-mail address was used for Testing: pm3.hs22.it21b.win.team1@mailinator.com
* The E-Mail inbox of this address can be found here: https://www.mailinator.com/v4/public/inboxes.jsp?to=pm3.hs22.it21b.win.team1
*/
private String mailNotificationReceivers = "pm3.hs22.it21b.win.team1@mailinator.com";
/**
* String Template to create E-Mail Subject for Notifications
* Variables: Task Name
*/
private String mailNotificationSubjectTemplate = "Task %s is due!";
/**
* String Template to create E-Mail Text for Notifications
* Variables: Task Name, plant Name, nextExecution, Task description
*/
private String mailNotificationTextTemplate = "Dear user\nYour gardentask %s for plant %s is due at %tF. Don't forget to confirm in your application if the task is done.\nTask description:\n%s";
/**
* Location of the garden can be set by user (Used for Weather Service)
*/
private String location = ""; private String location = "";
/*
Create Instance of Settings
*/
static { static {
instance = new Settings(); instance = new Settings();
} }
@ -29,14 +66,21 @@ public class Settings {
return Settings.instance; return Settings.instance;
} }
/**
* Private constructor to prevent Classes from creating more instances
*/
private Settings() {} private Settings() {}
public HardinessZone getCurrentHardinessZone() { public HardinessZone getCurrentHardinessZone() {
return currentHardinessZone; return currentHardinessZone;
} }
/**
* Method to set the current Hardiness Zone. If no Hardiness Zone is given the default zone (ZONE_8A) will be used.
* @param currentHardinessZone the new Hardiness Zone
*/
public void setCurrentHardinessZone(HardinessZone currentHardinessZone) { public void setCurrentHardinessZone(HardinessZone currentHardinessZone) {
this.currentHardinessZone = currentHardinessZone; this.currentHardinessZone = Objects.requireNonNullElse(currentHardinessZone, HardinessZone.ZONE_8A);
} }
public void setShowTutorial (boolean showTutorial) { public void setShowTutorial (boolean showTutorial) {

View File

@ -7,6 +7,7 @@ import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane; import javafx.scene.layout.StackPane;
import javafx.stage.Stage; import javafx.stage.Stage;
import java.io.InputStream;
/** /**
* Controller class for the Tutorial.fxml file * Controller class for the Tutorial.fxml file
@ -32,17 +33,27 @@ public class TutorialController {
switchViews(); switchViews();
setButtonAbilities(); setButtonAbilities();
Image addNewPlantImage = new Image(String.valueOf(PlantsController.class.getResource("add-new-plant.png"))); setImageView(imgAddNewPlant, "add-new-plant.png");
Image selectSowHarvestImage = new Image(String.valueOf(PlantsController.class.getResource("select-sow-harvest.png"))); setImageView(imgSelectDate, "select-sow-harvest.png");
Image scheduleImage = new Image(String.valueOf(PlantsController.class.getResource("schedule.png"))); setImageView(imgDetailDeleteButtons, "details-delete.png");
Image detailDeleteButtonsImage = new Image(String.valueOf(PlantsController.class.getResource("details-delete.png"))); setImageView(imgTaskList, "schedule.png");
Image addTaskImage = new Image(String.valueOf(PlantsController.class.getResource("add-task.png"))); setImageView(imgAddTaskButton, "add-task.png");
}
imgAddNewPlant.setImage(addNewPlantImage); /**
imgSelectDate.setImage(selectSowHarvestImage); * update the given image view with screenshot or placeholder image.
imgDetailDeleteButtons.setImage(detailDeleteButtonsImage); * @param imageView the image view to update
imgAddTaskButton.setImage(addTaskImage); * @param fileName the file name of the source
imgTaskList.setImage(scheduleImage); */
private void setImageView(ImageView imageView, String fileName) {
InputStream is = PlantsController.class.getResourceAsStream("screenshots/" + fileName);
Image image;
if (is != null) {
image = new Image(String.valueOf(PlantsController.class.getResource("screenshots/" + fileName)));
} else {
image = new Image(String.valueOf(PlantsController.class.getResource("placeholder.png")));
}
imageView.setImage(image);
} }
public void viewNextPage() { public void viewNextPage() {

View File

@ -17,46 +17,57 @@ import java.util.TimerTask;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* Class with tasks which must be executed periodic and not triggered by user. Method run must be called in a fix interval.
*/
public class BackgroundTasks extends TimerTask { public class BackgroundTasks extends TimerTask {
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName()); private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
private final TaskList taskList; private final TaskList taskList;
private final Notifier notifier; private final Notifier notifier;
private final WeatherGradenTaskPlanner weatherGardenTaskPlaner; private final WeatherGradenTaskPlanner weatherGardenTaskPlaner;
private void movePastTasks() throws IOException {
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN, LocalDate.now().minusDays(1));
taskList.forEach(task -> {
if (!task.isDone()) {
task.setNextExecution(LocalDate.now());
}
});
}
public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) { public BackgroundTasks(TaskList taskList, CropList cropList, PlantList plantList) {
this.taskList = taskList; this.taskList = taskList;
notifier = new Notifier(taskList, plantList, cropList); notifier = new Notifier(taskList, plantList, cropList);
weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList); weatherGardenTaskPlaner = new WeatherGradenTaskPlanner(taskList, plantList, cropList);
} }
/**
* Changes the field "nextExecution" of all tasks if it's in the past to the actual date as long as they are not done.
* @throws IOException if the taskList can't be read.
*/
private void movePastTasks() throws IOException {
List<Task> taskList = this.taskList.getTaskList(LocalDate.MIN.plusDays(1), LocalDate.now().minusDays(1));
for (Task task : taskList) {
if (!task.isDone()) {
task.setNextExecution(LocalDate.now());
this.taskList.saveTask(task);
}
}
}
/**
* Method to call if Tasks should be executed. It calls all Background tasks after each other.
*/
@Override @Override
public void run() { public void run() {
try { try {
movePastTasks(); movePastTasks();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
LOG.log(Level.SEVERE, "Could not execute Background Task: move past Tasks ", e.getCause()); LOG.log(Level.WARNING, "Could not execute Background Task: move past Tasks ", e.getCause());
} }
try { try {
weatherGardenTaskPlaner.refreshTasks(); weatherGardenTaskPlaner.refreshTasks();
} catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) { } catch (IOException | HardinessZoneNotSetException | PlantNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
LOG.log(Level.SEVERE, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause()); LOG.log(Level.WARNING, "Could not execute Background Task: Refresh Tasks by WeatherGardenTaskPlaner ", e.getCause());
} }
try { try {
notifier.sendNotifications(); notifier.sendNotifications();
} catch (IOException | MessagingException | HardinessZoneNotSetException e) { } catch (IOException | MessagingException | HardinessZoneNotSetException e) {
e.printStackTrace(); e.printStackTrace();
LOG.log(Level.SEVERE, "Could not execute Background Task: send Notification for due Tasks", e.getCause()); LOG.log(Level.WARNING, "Could not execute Background Task: send Notification for due Tasks", e.getCause());
} }
} }
} }

View File

@ -13,6 +13,9 @@ import javax.mail.MessagingException;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
/**
* Class to send Notifications to the user
*/
public class Notifier { public class Notifier {
private final TaskList taskList; private final TaskList taskList;
private final CropList cropList; private final CropList cropList;
@ -25,6 +28,13 @@ public class Notifier {
this.plantList = plantList; this.plantList = plantList;
} }
/**
* Method to send a Notification to the user for e specific Task
* @param task The task to use for notification
* @throws IOException if tasklist can not be read
* @throws MessagingException if E-Mail can not be sent for any reason
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
*/
private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException { private void sendNotification(Task task) throws IOException, MessagingException, HardinessZoneNotSetException {
String plantName = "unkown plant"; String plantName = "unkown plant";
if(cropList.getCropById((task.getCropId())).isPresent()){ if(cropList.getCropById((task.getCropId())).isPresent()){
@ -38,6 +48,12 @@ public class Notifier {
eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText); eMailSender.sendMails(Settings.getInstance().getMailNotificationReceivers(), messageSubject, messageText);
} }
/**
* Sends a notification to the user for each task which is due and not done every day as long as it's not done.
* @throws IOException if tasklist can not be read
* @throws MessagingException if E-Mail can not be sent for any reason
* @throws HardinessZoneNotSetException if hardiness zone is not set in plant list.
*/
public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException { public void sendNotifications() throws IOException, MessagingException, HardinessZoneNotSetException {
for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) { for (Task task : taskList.getTaskList(LocalDate.MIN, LocalDate.MAX)) {
if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) { if (task.getNextNotification() != null && task.getNextNotification().isBefore(LocalDate.now().minusDays(1))) {

View File

@ -10,16 +10,20 @@ import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
/**
* Class to send E-Mails
*/
public class EMailSender { public class EMailSender {
/**
public EMailSender(){ * Method to send E-Mail to one or multiple recipients
* @param recipients recipients E-Mail addresses separated by ";"
} * @param subject Subject of the E-Mail
* @param text E-Mail message Text as rear text or html
* @throws MessagingException If sending the E-Mail fails for any reason
*/
public void sendMails(String recipients, String subject, String text) throws MessagingException { public void sendMails(String recipients, String subject, String text) throws MessagingException {
// TODO replace printMail with implementation printMail(recipients, subject, text);
printMail(recipients, subject, text); // TODO Remove Printing E-Mail to console to test it
MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession()); MimeMessage message = new MimeMessage(Settings.getInstance().getSmtpCredentials().getSession());
message.addHeader("Content-type", "text/HTML; charset=UTF-8"); message.addHeader("Content-type", "text/HTML; charset=UTF-8");
message.addHeader("format", "flowed"); message.addHeader("format", "flowed");

View File

@ -5,6 +5,10 @@ import javax.mail.Session;
import java.net.Authenticator; import java.net.Authenticator;
import java.util.Properties; import java.util.Properties;
/**
* Class to store SMTP Credentials to send E-Mails and create
* corresponding Session Object
*/
public record SmtpCredentials( public record SmtpCredentials(
String host, String host,
String port, String port,
@ -14,6 +18,10 @@ public record SmtpCredentials(
boolean startTLS boolean startTLS
) { ) {
/**
* Creates a Properties Object with SMTP Server Information
* @return the created Properties Object
*/
private Properties getProperties() { private Properties getProperties() {
Properties properties = new Properties(); Properties properties = new Properties();
properties.put("mail.smtp.host", host); properties.put("mail.smtp.host", host);
@ -23,6 +31,10 @@ public record SmtpCredentials(
return properties; return properties;
} }
/**
* Creates a javax.mail.Authenticator Object with username and password for SMTP Server
* @return the created javax.mail.Authenticator Object
*/
private javax.mail.Authenticator getAuthenticator() { private javax.mail.Authenticator getAuthenticator() {
return new javax.mail.Authenticator() { return new javax.mail.Authenticator() {
@Override @Override
@ -32,10 +44,11 @@ public record SmtpCredentials(
}; };
} }
/**
* Method to get the Session Instance with the given SMTP Credentials
* @return the Session Instance
*/
public Session getSession() { public Session getSession() {
return Session.getInstance(getProperties(), getAuthenticator()); return Session.getInstance(getProperties(), getAuthenticator());
} }
} }

View File

@ -1,5 +1,8 @@
package ch.zhaw.gartenverwaltung.backgroundtasks.weather; package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
/**
* Enum of possible Weather events
*/
public enum SevereWeather { public enum SevereWeather {
FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN FROST,SNOW,HAIL,NO_SEVERE_WEATHER,RAIN
} }

View File

@ -9,11 +9,11 @@ import ch.zhaw.gartenverwaltung.types.*;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days * The WeatherGardenTaskPlanner creates Tasks based on weather events and the rain amount from the last days
*
*/ */
public class WeatherGradenTaskPlanner { public class WeatherGradenTaskPlanner {
private final TaskList taskList; private final TaskList taskList;
@ -42,13 +42,19 @@ public class WeatherGradenTaskPlanner {
private void getSevereWeatherEvents() throws IOException { private void getSevereWeatherEvents() throws IOException {
SevereWeather actualWeather = weatherService.causeSevereWeather(1); SevereWeather actualWeather = weatherService.causeSevereWeather(1);
List<Crop> actualCrops = cropList.getCrops();
for (Crop crop : actualCrops) {
List<Task> actualCropTasks = taskList.getTaskForCrop(crop.getCropId().orElse(-1L));
if (SevereWeather.HAIL.equals(actualWeather)) { if (SevereWeather.HAIL.equals(actualWeather)) {
//ToDo creates hail task all 3 seconds, pls fix createPreHailTask(crop, actualCropTasks);
//createPreHailTask();
} else if (SevereWeather.FROST.equals(actualWeather)) { } else if (SevereWeather.FROST.equals(actualWeather)) {
createPreFrostTask(); createPreFrostTask(crop, actualCropTasks);
} else if (SevereWeather.SNOW.equals(actualWeather)) { } else if (SevereWeather.SNOW.equals(actualWeather)) {
createPreSnowTask(); createPreSnowTask(crop, actualCropTasks);
}
} }
} }
@ -58,39 +64,70 @@ public class WeatherGradenTaskPlanner {
} }
/** /**
* Method to create a PreHailTask * Method to create a PreHailTask and saves it in the tasklist
* @throws IOException If the database cannot be accessed * @throws IOException If the database cannot be accessed
*/ */
private void createPreHailTask() throws IOException { private void createPreHailTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
Task preHailTask = new Task("Hail", Task preHailTask = new Task("Hail",
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin", "During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L); dateSevereWeather,dateSevereWeather.plusDays(1L),crop.getCropId().orElse(-1L));
taskList.saveTask(preHailTask);
List<Task> hailTasks = actualTasksForCrop.stream().filter(task -> task.getName().equals("Hail")).toList();
if(isNoSevereWeatherTaskAtDate(preHailTask, hailTasks) && hailTasks.isEmpty()){
taskList.saveTask(preHailTask);
}
} }
/** /**
* Method to create a PreFrosttask * Method to create a PreFrosttask and saves it in the tasklist
* @throws IOException If the database cannot be accessed * @throws IOException If the database cannot be accessed
*/ */
private void createPreFrostTask() throws IOException { private void createPreFrostTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
Task preFrostTask = new Task("Frost", Task preFrostTask = new Task("Frost",
"The temperatur falls below zero degrees, cover especially the root with wool", "The temperatur falls below zero degrees, cover especially the root with wool",
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L); dateSevereWeather,dateSevereWeather.plusDays(1L),crop.getCropId().orElse(-1L));
List<Task> frostTasks = actualTasksForCrop.stream().filter(task -> task.getName().equals("Frost")).toList();
if(isNoSevereWeatherTaskAtDate(preFrostTask, frostTasks) && frostTasks.isEmpty()){
taskList.saveTask(preFrostTask); taskList.saveTask(preFrostTask);
} }
}
/** /**
* Method to create a PreSnowTask * Method to create a PreSnowTask and saves it in the tasklist
* @throws IOException If the database cannot be accessed * @throws IOException If the database cannot be accessed
*/ */
private void createPreSnowTask() throws IOException { private void createPreSnowTask(Crop crop, List<Task> actualTasksForCrop) throws IOException {
Task preSnowTask = new Task("Snow", Task preSnowTask = new Task("Snow",
"The weather brings little snowfall. Cover your crops", "The weather brings little snowfall. Cover your crops",
dateSevereWeather.minusDays(1L),dateSevereWeather.plusDays(1L),1L); dateSevereWeather, dateSevereWeather.plusDays(1L), crop.getCropId().orElse(-1L));
List<Task> snowTasklist = actualTasksForCrop.stream().filter(task -> task.getName().equals("Snow")).toList();
if(isNoSevereWeatherTaskAtDate(preSnowTask, snowTasklist) && snowTasklist.isEmpty()){
taskList.saveTask(preSnowTask); taskList.saveTask(preSnowTask);
} }
}
/**
* Method to create a PreSnowTask and saves it in the tasklist
* @param preSevereWeatherTask the Task which would be added if there is not already
* the same Type of severe weather task
* @param severeWeatherTasks List of severe weather tasks from e specific severe weather
* @return true If there is not already a severe weather task of the same type of preSevereWeatherTask
* task at the date of the preSevereWeatherTask
*/
private boolean isNoSevereWeatherTaskAtDate(Task preSevereWeatherTask, List<Task> severeWeatherTasks) {
List<Task> severeWeatherTasksAtDate = new ArrayList<>();
for (Task task : severeWeatherTasks) {
if (task.getStartDate() == preSevereWeatherTask.getStartDate()) {
severeWeatherTasksAtDate.add(task);
}
}
return severeWeatherTasksAtDate.isEmpty();
}
/** /**
* Method to adjust the water plant tasks * Method to adjust the water plant tasks

View File

@ -1,7 +1,6 @@
package ch.zhaw.gartenverwaltung.backgroundtasks.weather; package ch.zhaw.gartenverwaltung.backgroundtasks.weather;
/** /**
* The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner * The WeatherService is a class to cause weather events for the WeatherGardenTaskPlanner
*
*/ */
public class WeatherService { public class WeatherService {
private static final int NO_RAIN = 0; private static final int NO_RAIN = 0;
@ -9,6 +8,11 @@ public class WeatherService {
private static final int RAIN = 25; private static final int RAIN = 25;
private static final int HEAVY_RAIN = 50; private static final int HEAVY_RAIN = 50;
/**
* Method to simmulate a Weather Service for testing
* @param randomWeather random int. Range: 1-3
* @return the selected SevereWeather
*/
public SevereWeather causeSevereWeather(int randomWeather) { public SevereWeather causeSevereWeather(int randomWeather) {
return switch (randomWeather) { return switch (randomWeather) {
case 1 -> SevereWeather.HAIL; case 1 -> SevereWeather.HAIL;
@ -19,6 +23,11 @@ public class WeatherService {
} }
/**
* Method to simulate a Weather Service for testing
* @param randomRainAmount random int. Range: 1-4
* @return the selected rain amount
*/
public int causeRainAmount(int randomRainAmount) { public int causeRainAmount(int randomRainAmount) {
return switch (randomRainAmount) { return switch (randomRainAmount) {
case 1 -> NO_RAIN; case 1 -> NO_RAIN;

View File

@ -1,5 +1,6 @@
package ch.zhaw.gartenverwaltung.bootstrap; package ch.zhaw.gartenverwaltung.bootstrap;
import ch.zhaw.gartenverwaltung.CropDetailController;
import ch.zhaw.gartenverwaltung.Main; import ch.zhaw.gartenverwaltung.Main;
import ch.zhaw.gartenverwaltung.io.*; import ch.zhaw.gartenverwaltung.io.*;
import ch.zhaw.gartenverwaltung.models.Garden; import ch.zhaw.gartenverwaltung.models.Garden;
@ -17,12 +18,15 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
/** /**
* Class responsible for bootstrapping the application wide dependencies * Class responsible for bootstrapping the application wide dependencies
* and injecting them into JavaFX Controllers. * and injecting them into JavaFX Controllers.
*/ */
public class AppLoader { public class AppLoader {
private static final Logger LOG = Logger.getLogger(CropDetailController.class.getName());
/** /**
* Caching the panes * Caching the panes
*/ */
@ -146,12 +150,17 @@ public class AppLoader {
try { try {
afterInjectMethod.invoke(controller); afterInjectMethod.invoke(controller);
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
// TODO: Log LOG.log(Level.SEVERE, "Could not invoke afterInjectMethod", e.getCause());
e.printStackTrace(); e.printStackTrace();
} }
}); });
} }
/**
* Method to get any AppDependency
* @param type Class of Dependency
* @return the App dependency
*/
public Object getAppDependency(Class<?> type) { public Object getAppDependency(Class<?> type) {
return dependencies.get(type.getSimpleName()); return dependencies.get(type.getSimpleName());
} }

View File

@ -1,5 +1,8 @@
package ch.zhaw.gartenverwaltung.io; package ch.zhaw.gartenverwaltung.io;
/**
* Exceptionm which is thrown if Hardiness zone is not set in plant list.
*/
public class HardinessZoneNotSetException extends Exception { public class HardinessZoneNotSetException extends Exception {
public HardinessZoneNotSetException() { public HardinessZoneNotSetException() {
super("HardinessZone must be set to retrieve plants!"); super("HardinessZone must be set to retrieve plants!");

View File

@ -2,6 +2,9 @@ package ch.zhaw.gartenverwaltung.io;
import java.io.IOException; import java.io.IOException;
/**
* Excption which is thrown if a JSON file has a invalid File format.
*/
class InvalidJsonException extends IOException { class InvalidJsonException extends IOException {
public InvalidJsonException(String reason) { public InvalidJsonException(String reason) {
super(reason); super(reason);

View File

@ -50,8 +50,6 @@ public class Garden {
*/ */
public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException { public void plantAsCrop(Plant plant, LocalDate plantingDate) throws IOException, HardinessZoneNotSetException, PlantNotFoundException {
Crop crop = new Crop(plant.id(), plantingDate); Crop crop = new Crop(plant.id(), plantingDate);
//TODO Add Area to Plant
//crop.withArea(0);
cropList.saveCrop(crop); cropList.saveCrop(crop);
gardenSchedule.planTasksForCrop(crop); gardenSchedule.planTasksForCrop(crop);
plantedCrops.clear(); plantedCrops.clear();

View File

@ -32,16 +32,6 @@ public class GardenSchedule {
public GardenSchedule(TaskList taskList, PlantList plantList) throws IOException { public GardenSchedule(TaskList taskList, PlantList plantList) throws IOException {
this.taskList = taskList; this.taskList = taskList;
this.plantList = plantList; this.plantList = plantList;
TaskList.TaskListObserver taskListObserver = newTaskList -> {
Platform.runLater(() -> {
try {
getTasksUpcomingWeek();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
};
setTaskListObserver(taskListObserver);
} }
public ListProperty<List<Task>> getWeeklyTaskListProperty() { public ListProperty<List<Task>> getWeeklyTaskListProperty() {
@ -176,14 +166,12 @@ public class GardenSchedule {
dayTaskList.add(new ArrayList<>()); dayTaskList.add(new ArrayList<>());
final int finalI = i; final int finalI = i;
weekTasks.forEach(task -> { weekTasks.forEach(task -> {
if (task.getNextExecution() == null) { if(task.getNextExecution() != null) {
task.isDone();
} else {
LocalDate checkDate = task.getNextExecution(); LocalDate checkDate = task.getNextExecution();
do { do {
if (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN))) { if (date.equals(task.getNextExecution()) || (date.equals(checkDate) && !date.isAfter(task.getEndDate().orElse(LocalDate.MIN)))) {
dayTaskList.get(finalI).add(task); dayTaskList.get(finalI).add(task);
break;
} }
checkDate = checkDate.plusDays(task.getInterval().orElse(0)); checkDate = checkDate.plusDays(task.getInterval().orElse(0));
} while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength))); } while (!(task.getInterval().orElse(0) == 0) && checkDate.isBefore(LocalDate.now().plusDays(listLength)));

View File

@ -1,5 +1,6 @@
package ch.zhaw.gartenverwaltung.models; package ch.zhaw.gartenverwaltung.models;
import ch.zhaw.gartenverwaltung.Settings;
import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException; import ch.zhaw.gartenverwaltung.io.HardinessZoneNotSetException;
import ch.zhaw.gartenverwaltung.io.PlantList; import ch.zhaw.gartenverwaltung.io.PlantList;
import ch.zhaw.gartenverwaltung.types.GrowthPhaseType; import ch.zhaw.gartenverwaltung.types.GrowthPhaseType;
@ -16,7 +17,6 @@ import java.util.stream.Collectors;
public class PlantListModel { public class PlantListModel {
private final PlantList plantList; private final PlantList plantList;
private HardinessZone currentZone;
/** /**
* Comparators to create sorted Plant List * Comparators to create sorted Plant List
@ -33,15 +33,15 @@ public class PlantListModel {
} }
private void setDefaultZone() { private void setDefaultZone() {
currentZone = HardinessZone.ZONE_8A; // TODO: get Default Zone from Settings Settings.getInstance().setCurrentHardinessZone(null);
} }
public void setCurrentZone(HardinessZone currentZone) { public void setCurrentZone(HardinessZone currentZone) {
this.currentZone = currentZone; Settings.getInstance().setCurrentHardinessZone(currentZone);
} }
public HardinessZone getCurrentZone() { public HardinessZone getCurrentZone() {
return currentZone; return Settings.getInstance().getCurrentHardinessZone();
} }
/** /**

View File

@ -1,5 +1,8 @@
package ch.zhaw.gartenverwaltung.models; package ch.zhaw.gartenverwaltung.models;
/**
* Exception which is thrown if there is no plant in plant Database with the given id.
*/
public class PlantNotFoundException extends Exception { public class PlantNotFoundException extends Exception {
public PlantNotFoundException() { public PlantNotFoundException() {
super("The selected Plant was not found in Database!"); super("The selected Plant was not found in Database!");

View File

@ -40,7 +40,6 @@ public class Crop {
public Optional<Long> getCropId() { public Optional<Long> getCropId() {
return Optional.ofNullable(cropId); return Optional.ofNullable(cropId);
} }
public long getPlantId() { return plantId; } public long getPlantId() { return plantId; }
public LocalDate getStartDate() { return startDate; } public LocalDate getStartDate() { return startDate; }
public double getArea() { return area; } public double getArea() { return area; }

View File

@ -68,7 +68,7 @@ public record Plant(
return growthPhase.group(); return growthPhase.group();
} }
} }
return 0; // TODO implement return 0;
} }
/** /**

View File

@ -63,6 +63,7 @@ public class Task {
this.startDate = startDate; this.startDate = startDate;
nextExecution = startDate; nextExecution = startDate;
this.endDate = endDate; this.endDate = endDate;
this.cropId = cropId;
} }
/** /**
@ -107,7 +108,7 @@ public class Task {
* @return Whether the Task is within the given range * @return Whether the Task is within the given range
*/ */
public boolean isInTimePeriod(LocalDate searchStartDate, LocalDate searchEndDate) { public boolean isInTimePeriod(LocalDate searchStartDate, LocalDate searchEndDate) {
return endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate) || (nextExecution != null && nextExecution.isBefore(searchEndDate) && nextExecution.isAfter(searchStartDate)); return (endDate.isAfter(searchStartDate) && startDate.isBefore(searchEndDate)) || ((nextExecution != null && nextExecution.isBefore(searchEndDate.plusDays(1)) && nextExecution.isAfter(searchStartDate.minusDays(1))));
} }
/** /**

View File

@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDate; import java.time.LocalDate;
/**
* Class which represents a Task if the start and enddate is not known yet.
*/
public class TaskTemplate { public class TaskTemplate {
@JsonProperty @JsonProperty
private final String name; private final String name;

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.ListView?> <?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.AnchorPane?>
@ -19,11 +20,12 @@
</Label> </Label>
<HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="541.0" prefWidth="867.0" spacing="10.0" VBox.vgrow="ALWAYS"> <HBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="541.0" prefWidth="867.0" spacing="10.0" VBox.vgrow="ALWAYS">
<children> <children>
<ListView fx:id="scheduledPlants_listview" maxWidth="1.7976931348623157E308" prefHeight="522.0" prefWidth="271.0" HBox.hgrow="NEVER"> <VBox prefHeight="497.0" prefWidth="237.0" spacing="10.0" HBox.hgrow="NEVER">
<HBox.margin> <children>
<Insets /> <ListView fx:id="scheduledPlants_listview" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="522.0" prefWidth="271.0" VBox.vgrow="ALWAYS" />
</HBox.margin> <Button maxWidth="1.7976931348623157E308" mnemonicParsing="false" onAction="#showAllTasks" styleClass="button-class" text="Show All Tasks" VBox.vgrow="NEVER" />
</ListView> </children>
</VBox>
<VBox maxWidth="1.7976931348623157E308" prefHeight="537.0" prefWidth="650.0" spacing="10.0" HBox.hgrow="ALWAYS"> <VBox maxWidth="1.7976931348623157E308" prefHeight="537.0" prefWidth="650.0" spacing="10.0" HBox.hgrow="ALWAYS">
<children> <children>
<ListView fx:id="week_listView" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS"> <ListView fx:id="week_listView" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0" VBox.vgrow="ALWAYS">

View File

@ -14,7 +14,7 @@
<?import javafx.scene.text.Text?> <?import javafx.scene.text.Text?>
<?import javafx.scene.text.TextFlow?> <?import javafx.scene.text.TextFlow?>
<BorderPane maxHeight="470.0" maxWidth="724.0" minHeight="470.0" minWidth="724.0" prefHeight="470.0" prefWidth="724.0" xmlns="http://javafx.com/javafx/19" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.TutorialController"> <BorderPane maxHeight="470.0" maxWidth="724.0" minHeight="470.0" minWidth="724.0" prefHeight="470.0" prefWidth="724.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ch.zhaw.gartenverwaltung.TutorialController">
<bottom> <bottom>
<HBox alignment="CENTER" prefHeight="0.0" prefWidth="724.0" BorderPane.alignment="CENTER"> <HBox alignment="CENTER" prefHeight="0.0" prefWidth="724.0" BorderPane.alignment="CENTER">
<children> <children>

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -52,7 +52,7 @@ public class WeatherGardenTaskPlannerTest {
exampleTask.setNextExecution(LocalDate.now().plusDays(1L)); exampleTask.setNextExecution(LocalDate.now().plusDays(1L));
exampleWeatherTask = new Task("Hail", exampleWeatherTask = new Task("Hail",
"During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin", "During a summer Thunderstorm it could hail heavily. THe Hail could damage the crops. To prevent damage cover the plants with a strong tarpaulin",
LocalDate.now().minusDays(1L),LocalDate.now().plusDays(1L),3L); LocalDate.now(),LocalDate.now().plusDays(1L),3L);
taskList = new JsonTaskList(testFile); taskList = new JsonTaskList(testFile);

View File

@ -1,7 +1,12 @@
package ch.zhaw.gartenverwaltung.io; package ch.zhaw.gartenverwaltung.io;
import ch.zhaw.gartenverwaltung.models.GardenSchedule;
import ch.zhaw.gartenverwaltung.models.PlantNotFoundException;
import ch.zhaw.gartenverwaltung.types.Crop;
import ch.zhaw.gartenverwaltung.types.Task; import ch.zhaw.gartenverwaltung.types.Task;
import javafx.application.Platform;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers; import org.mockito.ArgumentMatchers;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -13,6 +18,7 @@ import java.nio.file.Path;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List; import java.util.List;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -27,6 +33,22 @@ public class JsonTaskListTest {
private final URL dbDataSource = this.getClass().getResource("test-taskdb.json"); private final URL dbDataSource = this.getClass().getResource("test-taskdb.json");
private final URL testFile = this.getClass().getResource("template-taskdb.json"); private final URL testFile = this.getClass().getResource("template-taskdb.json");
@BeforeAll
static void setUpAll() {
try{
Platform.startup(()->{});
}catch (IllegalStateException ise){
//ignore double launches
}
}
@AfterAll
static void tearDownAll() {
//Dont do: Platform.exit();
}
@BeforeEach @BeforeEach
void connectToDb() throws URISyntaxException, IOException { void connectToDb() throws URISyntaxException, IOException {
assertNotNull(testFile); assertNotNull(testFile);
@ -35,6 +57,10 @@ public class JsonTaskListTest {
testDatabase = new JsonTaskList(dbDataSource); testDatabase = new JsonTaskList(dbDataSource);
} }
private void reloadDb() {
testDatabase = new JsonTaskList(dbDataSource);
}
@Test @Test
@DisplayName("Check if results are retrieved completely") @DisplayName("Check if results are retrieved completely")
void getTasks() { void getTasks() {
@ -47,7 +73,8 @@ public class JsonTaskListTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Assertions.assertEquals(3, taskList.size()); List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
Assertions.assertEquals(Arrays.asList(1L, 2L, 5L), ids);
} }
@ -65,7 +92,8 @@ public class JsonTaskListTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Assertions.assertEquals(4, taskList.size()); List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
Assertions.assertEquals(Arrays.asList(1L, 2L, 5L, 9L), ids);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -83,7 +111,8 @@ public class JsonTaskListTest {
taskList = testDatabase.getTaskList(LocalDate.parse("2022-04-30", formatter), taskList = testDatabase.getTaskList(LocalDate.parse("2022-04-30", formatter),
LocalDate.parse("2022-05-31", formatter)); LocalDate.parse("2022-05-31", formatter));
Assertions.assertEquals(2, taskList.size()); List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
Assertions.assertEquals(Arrays.asList(1L, 5L), ids);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -100,8 +129,8 @@ public class JsonTaskListTest {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Assertions.assertEquals(6, taskList.size()); List<Long> ids = taskList.stream().map(t -> t.getId().orElse(0L)).toList();
Assertions.assertEquals(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L), ids);
} }
@ -116,6 +145,16 @@ public class JsonTaskListTest {
} }
Assertions.assertEquals(0, taskList.size()); Assertions.assertEquals(0, taskList.size());
try {
taskList = testDatabase.getTaskForCrop(1);
} catch (IOException e) {
throw new RuntimeException(e);
}
List<Long> ids = (taskList.stream().map( task -> task.getId().orElse(0L)).toList());
Assertions.assertEquals(Arrays.asList(7L, 8L), ids);
} }
@Test @Test
@ -138,6 +177,43 @@ public class JsonTaskListTest {
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
verify(mockObs, times(1)).onChange(ArgumentMatchers.anyList());
ArgumentCaptor<List<Task>> captor = ArgumentCaptor.forClass(List.class);
verify(mockObs, times(1)).onChange(captor.capture());
List<Long> ids = captor.getValue().stream().map(t -> t.getId().orElse(0L)).toList();
Assertions.assertEquals(Arrays.asList(7L, 8L), ids);
}
@Test
@Tag("IntegrationTest")
void testComplete() {
JsonPlantList plantList = new JsonPlantList();
try {
testDatabase.removeTasksForCrop(0);
testDatabase.removeTasksForCrop(1);
} catch (IOException e) {
throw new RuntimeException(e);
}
GardenSchedule gardenSchedule = null;
try {
gardenSchedule = new GardenSchedule(testDatabase, plantList);
} catch (IOException e) {
throw new RuntimeException(e);
}
Crop crop = new Crop(3L, LocalDate.parse("2022-12-01", formatter));
try {
gardenSchedule.planTasksForCrop(crop);
reloadDb();
List<Task> tasks = gardenSchedule.getTaskList();
List<String> tasknames = (tasks.stream().map( task -> task.getName().substring(0,3).toLowerCase()).toList());
Assertions.assertEquals(Arrays.asList("ger","wat","hil","har"), tasknames);
} catch (IOException | PlantNotFoundException | HardinessZoneNotSetException e) {
throw new RuntimeException(e);
}
} }
} }

View File

@ -34,12 +34,17 @@ class GardenScheduleTest {
@BeforeAll @BeforeAll
static void setUpAll() { static void setUpAll() {
try{
Platform.startup(()->{}); Platform.startup(()->{});
}catch (IllegalStateException ise){
//ignore double launches
}
} }
@AfterAll @AfterAll
static void tearDownAll() { static void tearDownAll() {
Platform.exit(); //Dont do: Platform.exit();
} }
@BeforeEach @BeforeEach
@ -234,5 +239,8 @@ class GardenScheduleTest {
testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).get(0); testTaskList.getTaskList(LocalDate.MIN,LocalDate.MAX).get(0);
} }
@Test
void testPlantNotFoundException() throws HardinessZoneNotSetException, IOException {
assertThrowsExactly(PlantNotFoundException.class, () -> { model.planTasksForCrop(new Crop(0, exampleStartDate)); });
}
} }

View File

@ -101,7 +101,7 @@ class PlantListModelTest {
@Test @Test
void setCurrentZone() { void setCurrentZone() {
checkCurrentZone(HardinessZone.ZONE_8A); // TODO change to get default zone from config checkCurrentZone(HardinessZone.ZONE_8A);
model.setCurrentZone(HardinessZone.ZONE_1A); model.setCurrentZone(HardinessZone.ZONE_1A);
checkCurrentZone(HardinessZone.ZONE_1A); checkCurrentZone(HardinessZone.ZONE_1A);
model.setCurrentZone(HardinessZone.ZONE_8A); model.setCurrentZone(HardinessZone.ZONE_8A);

View File

@ -64,5 +64,27 @@
"endDate" : "2022-09-01", "endDate" : "2022-09-01",
"interval" : 0, "interval" : 0,
"cropId" : 0 "cropId" : 0
},
{
"id" : 7,
"name" : "sow plant",
"description": "Plant the seeds, crops in de bed.",
"startDate" : "2022-11-01",
"nextExecution": "2022-11-01",
"nextNotification": "2022-11-01",
"endDate" : "2022-11-01",
"interval" : 0,
"cropId" : 1
},
{
"id" : 8,
"name" : "harvest plant",
"description": "Pull the ripe vegetables out from the soil. Clean them with clear, fresh water. ",
"startDate" : "2022-12-01",
"nextExecution": "2022-12-01",
"nextNotification": "2022-12-01",
"endDate" : "2022-12-01",
"interval" : 0,
"cropId" : 1
} }
] ]